@toclocoinc/lattice-grid 1.88.2 → 1.88.3

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 (309) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +1 -1
  3. package/angular/fesm2022/toclocoinc-lattice-grid-angular.mjs +6 -2
  4. package/angular/package.json +1 -1
  5. package/angular/types/toclocoinc-lattice-grid-angular.d.ts +3 -1
  6. package/docs/API.html +62 -6
  7. package/docs/api/adapters.html +1 -1
  8. package/docs/api/ai.html +1 -1
  9. package/docs/api/alarms.html +1 -1
  10. package/docs/api/calendar.html +1 -1
  11. package/docs/api/charts.html +1 -1
  12. package/docs/api/dashboard.html +1 -1
  13. package/docs/api/data-router.html +1 -1
  14. package/docs/api/deckgl.html +1 -1
  15. package/docs/api/gantt.html +58 -2
  16. package/docs/api/geometry.html +1 -1
  17. package/docs/api/grid.html +2 -2
  18. package/docs/api/index.html +2 -2
  19. package/docs/api/kanban.html +1 -1
  20. package/docs/api/kpi.html +1 -1
  21. package/docs/api/layout.html +1 -1
  22. package/docs/api/leaflet.html +1 -1
  23. package/docs/api/list.html +1 -1
  24. package/docs/api/mapview.html +1 -1
  25. package/docs/api/mock-socket.html +1 -1
  26. package/docs/api/presets.html +1 -1
  27. package/docs/api/tabs.html +1 -1
  28. package/docs/api/types.html +2 -2
  29. package/docs/api-detail.html +4 -4
  30. package/docs/warnings.json +1 -1
  31. package/lattice-grid.d.ts +1 -1
  32. package/lattice-grid.esm.min.js +3 -3
  33. package/lattice-grid.min.cjs +3 -3
  34. package/lattice-grid.min.js +3 -3
  35. package/modules/ai.d.ts +1 -1
  36. package/modules/ai.esm.min.js +2 -2
  37. package/modules/ai.min.cjs +2 -2
  38. package/modules/ai.min.js +2 -2
  39. package/modules/alarms.d.ts +1 -1
  40. package/modules/alarms.esm.min.js +2 -2
  41. package/modules/alarms.min.cjs +2 -2
  42. package/modules/alarms.min.js +2 -2
  43. package/modules/angular.d.ts +1 -1
  44. package/modules/angular.esm.min.js +2 -2
  45. package/modules/angular.min.cjs +2 -2
  46. package/modules/angular.min.js +2 -2
  47. package/modules/calendar.d.ts +1 -1
  48. package/modules/calendar.esm.min.js +2 -2
  49. package/modules/calendar.min.cjs +2 -2
  50. package/modules/calendar.min.js +2 -2
  51. package/modules/chart-alluvial.d.ts +1 -1
  52. package/modules/chart-alluvial.esm.min.js +1 -1
  53. package/modules/chart-alluvial.min.cjs +1 -1
  54. package/modules/chart-alluvial.min.js +1 -1
  55. package/modules/chart-arc.d.ts +1 -1
  56. package/modules/chart-arc.esm.min.js +1 -1
  57. package/modules/chart-arc.min.cjs +1 -1
  58. package/modules/chart-arc.min.js +1 -1
  59. package/modules/chart-barrace.d.ts +1 -1
  60. package/modules/chart-barrace.esm.min.js +1 -1
  61. package/modules/chart-barrace.min.cjs +1 -1
  62. package/modules/chart-barrace.min.js +1 -1
  63. package/modules/chart-bubblemap.d.ts +1 -1
  64. package/modules/chart-bubblemap.esm.min.js +1 -1
  65. package/modules/chart-bubblemap.min.cjs +1 -1
  66. package/modules/chart-bubblemap.min.js +1 -1
  67. package/modules/chart-bump.d.ts +1 -1
  68. package/modules/chart-bump.esm.min.js +1 -1
  69. package/modules/chart-bump.min.cjs +1 -1
  70. package/modules/chart-bump.min.js +1 -1
  71. package/modules/chart-calendar.d.ts +1 -1
  72. package/modules/chart-calendar.esm.min.js +1 -1
  73. package/modules/chart-calendar.min.cjs +1 -1
  74. package/modules/chart-calendar.min.js +1 -1
  75. package/modules/chart-choropleth.d.ts +1 -1
  76. package/modules/chart-choropleth.esm.min.js +1 -1
  77. package/modules/chart-choropleth.min.cjs +1 -1
  78. package/modules/chart-choropleth.min.js +1 -1
  79. package/modules/chart-decomposition.d.ts +1 -1
  80. package/modules/chart-decomposition.esm.min.js +1 -1
  81. package/modules/chart-decomposition.min.cjs +1 -1
  82. package/modules/chart-decomposition.min.js +1 -1
  83. package/modules/chart-diverging.d.ts +1 -1
  84. package/modules/chart-diverging.esm.min.js +1 -1
  85. package/modules/chart-diverging.min.cjs +1 -1
  86. package/modules/chart-diverging.min.js +1 -1
  87. package/modules/chart-dumbbell.d.ts +1 -1
  88. package/modules/chart-dumbbell.esm.min.js +1 -1
  89. package/modules/chart-dumbbell.min.cjs +1 -1
  90. package/modules/chart-dumbbell.min.js +1 -1
  91. package/modules/chart-fan.d.ts +1 -1
  92. package/modules/chart-fan.esm.min.js +1 -1
  93. package/modules/chart-fan.min.cjs +1 -1
  94. package/modules/chart-fan.min.js +1 -1
  95. package/modules/chart-forcetree.d.ts +1 -1
  96. package/modules/chart-forcetree.esm.min.js +1 -1
  97. package/modules/chart-forcetree.min.cjs +1 -1
  98. package/modules/chart-forcetree.min.js +1 -1
  99. package/modules/chart-hexbin.d.ts +1 -1
  100. package/modules/chart-hexbin.esm.min.js +1 -1
  101. package/modules/chart-hexbin.min.cjs +1 -1
  102. package/modules/chart-hexbin.min.js +1 -1
  103. package/modules/chart-hexmap.d.ts +1 -1
  104. package/modules/chart-hexmap.esm.min.js +1 -1
  105. package/modules/chart-hexmap.min.cjs +1 -1
  106. package/modules/chart-hexmap.min.js +1 -1
  107. package/modules/chart-icicle.d.ts +1 -1
  108. package/modules/chart-icicle.esm.min.js +1 -1
  109. package/modules/chart-icicle.min.cjs +1 -1
  110. package/modules/chart-icicle.min.js +1 -1
  111. package/modules/chart-markermap.d.ts +1 -1
  112. package/modules/chart-markermap.esm.min.js +1 -1
  113. package/modules/chart-markermap.min.cjs +1 -1
  114. package/modules/chart-markermap.min.js +1 -1
  115. package/modules/chart-motion.d.ts +1 -1
  116. package/modules/chart-motion.esm.min.js +1 -1
  117. package/modules/chart-motion.min.cjs +1 -1
  118. package/modules/chart-motion.min.js +1 -1
  119. package/modules/chart-pack.d.ts +1 -1
  120. package/modules/chart-pack.esm.min.js +1 -1
  121. package/modules/chart-pack.min.cjs +1 -1
  122. package/modules/chart-pack.min.js +1 -1
  123. package/modules/chart-parallel.d.ts +1 -1
  124. package/modules/chart-parallel.esm.min.js +1 -1
  125. package/modules/chart-parallel.min.cjs +1 -1
  126. package/modules/chart-parallel.min.js +1 -1
  127. package/modules/chart-pictorial.d.ts +1 -1
  128. package/modules/chart-pictorial.esm.min.js +1 -1
  129. package/modules/chart-pictorial.min.cjs +1 -1
  130. package/modules/chart-pictorial.min.js +1 -1
  131. package/modules/chart-polararea.d.ts +1 -1
  132. package/modules/chart-polararea.esm.min.js +1 -1
  133. package/modules/chart-polararea.min.cjs +1 -1
  134. package/modules/chart-polararea.min.js +1 -1
  135. package/modules/chart-polarscatter.d.ts +1 -1
  136. package/modules/chart-polarscatter.esm.min.js +1 -1
  137. package/modules/chart-polarscatter.min.cjs +1 -1
  138. package/modules/chart-polarscatter.min.js +1 -1
  139. package/modules/chart-pyramid.d.ts +1 -1
  140. package/modules/chart-pyramid.esm.min.js +1 -1
  141. package/modules/chart-pyramid.min.cjs +1 -1
  142. package/modules/chart-pyramid.min.js +1 -1
  143. package/modules/chart-radialbar.d.ts +1 -1
  144. package/modules/chart-radialbar.esm.min.js +1 -1
  145. package/modules/chart-radialbar.min.cjs +1 -1
  146. package/modules/chart-radialbar.min.js +1 -1
  147. package/modules/chart-ridgeline.d.ts +1 -1
  148. package/modules/chart-ridgeline.esm.min.js +1 -1
  149. package/modules/chart-ridgeline.min.cjs +1 -1
  150. package/modules/chart-ridgeline.min.js +1 -1
  151. package/modules/chart-roc.d.ts +1 -1
  152. package/modules/chart-roc.esm.min.js +1 -1
  153. package/modules/chart-roc.min.cjs +1 -1
  154. package/modules/chart-roc.min.js +1 -1
  155. package/modules/chart-serpentine.d.ts +1 -1
  156. package/modules/chart-serpentine.esm.min.js +1 -1
  157. package/modules/chart-serpentine.min.cjs +1 -1
  158. package/modules/chart-serpentine.min.js +1 -1
  159. package/modules/chart-slope.d.ts +1 -1
  160. package/modules/chart-slope.esm.min.js +1 -1
  161. package/modules/chart-slope.min.cjs +1 -1
  162. package/modules/chart-slope.min.js +1 -1
  163. package/modules/chart-spiral.d.ts +1 -1
  164. package/modules/chart-spiral.esm.min.js +1 -1
  165. package/modules/chart-spiral.min.cjs +1 -1
  166. package/modules/chart-spiral.min.js +1 -1
  167. package/modules/chart-splom.d.ts +1 -1
  168. package/modules/chart-splom.esm.min.js +1 -1
  169. package/modules/chart-splom.min.cjs +1 -1
  170. package/modules/chart-splom.min.js +1 -1
  171. package/modules/chart-tree.d.ts +1 -1
  172. package/modules/chart-tree.esm.min.js +1 -1
  173. package/modules/chart-tree.min.cjs +1 -1
  174. package/modules/chart-tree.min.js +1 -1
  175. package/modules/chart-venn.d.ts +1 -1
  176. package/modules/chart-venn.esm.min.js +1 -1
  177. package/modules/chart-venn.min.cjs +1 -1
  178. package/modules/chart-venn.min.js +1 -1
  179. package/modules/chart-voronoi.d.ts +1 -1
  180. package/modules/chart-voronoi.esm.min.js +1 -1
  181. package/modules/chart-voronoi.min.cjs +1 -1
  182. package/modules/chart-voronoi.min.js +1 -1
  183. package/modules/chart-waffle.d.ts +1 -1
  184. package/modules/chart-waffle.esm.min.js +1 -1
  185. package/modules/chart-waffle.min.cjs +1 -1
  186. package/modules/chart-waffle.min.js +1 -1
  187. package/modules/chart-wordcloud.d.ts +1 -1
  188. package/modules/chart-wordcloud.esm.min.js +1 -1
  189. package/modules/chart-wordcloud.min.cjs +1 -1
  190. package/modules/chart-wordcloud.min.js +1 -1
  191. package/modules/charts.d.ts +1 -1
  192. package/modules/charts.esm.min.js +2 -2
  193. package/modules/charts.min.cjs +2 -2
  194. package/modules/charts.min.js +2 -2
  195. package/modules/dashboard.d.ts +1 -1
  196. package/modules/dashboard.esm.min.js +2 -2
  197. package/modules/dashboard.min.cjs +2 -2
  198. package/modules/dashboard.min.js +2 -2
  199. package/modules/data-router.d.ts +1 -1
  200. package/modules/data-router.esm.min.js +2 -2
  201. package/modules/data-router.min.cjs +2 -2
  202. package/modules/data-router.min.js +2 -2
  203. package/modules/deckgl.d.ts +1 -1
  204. package/modules/deckgl.esm.min.js +2 -2
  205. package/modules/deckgl.min.cjs +2 -2
  206. package/modules/deckgl.min.js +2 -2
  207. package/modules/devtools.d.ts +1 -1
  208. package/modules/devtools.esm.min.js +1 -1
  209. package/modules/devtools.min.cjs +1 -1
  210. package/modules/devtools.min.js +1 -1
  211. package/modules/dhtmlx-compat.d.ts +1 -1
  212. package/modules/dhtmlx-compat.esm.min.js +2 -2
  213. package/modules/dhtmlx-compat.min.cjs +2 -2
  214. package/modules/dhtmlx-compat.min.js +2 -2
  215. package/modules/gantt.d.ts +58 -3
  216. package/modules/gantt.esm.min.js +223 -217
  217. package/modules/gantt.esm.min.js.map +2 -2
  218. package/modules/gantt.min.cjs +222 -216
  219. package/modules/gantt.min.js +222 -216
  220. package/modules/gantt.min.js.map +2 -2
  221. package/modules/geo-europe-nuts.d.ts +1 -1
  222. package/modules/geo-europe-nuts.esm.min.js +1 -1
  223. package/modules/geo-europe-nuts.min.cjs +1 -1
  224. package/modules/geo-europe-nuts.min.js +1 -1
  225. package/modules/geo-uk.d.ts +1 -1
  226. package/modules/geo-uk.esm.min.js +1 -1
  227. package/modules/geo-uk.min.cjs +1 -1
  228. package/modules/geo-uk.min.js +1 -1
  229. package/modules/geo-us-states.d.ts +1 -1
  230. package/modules/geo-us-states.esm.min.js +1 -1
  231. package/modules/geo-us-states.min.cjs +1 -1
  232. package/modules/geo-us-states.min.js +1 -1
  233. package/modules/geo-world-110m.d.ts +1 -1
  234. package/modules/geo-world-110m.esm.min.js +1 -1
  235. package/modules/geo-world-110m.min.cjs +1 -1
  236. package/modules/geo-world-110m.min.js +1 -1
  237. package/modules/geo-world-50m.d.ts +1 -1
  238. package/modules/geo-world-50m.esm.min.js +1 -1
  239. package/modules/geo-world-50m.min.cjs +1 -1
  240. package/modules/geo-world-50m.min.js +1 -1
  241. package/modules/geometry.d.ts +1 -1
  242. package/modules/geometry.esm.min.js +2 -2
  243. package/modules/geometry.min.cjs +2 -2
  244. package/modules/geometry.min.js +2 -2
  245. package/modules/htmx.d.ts +1 -1
  246. package/modules/htmx.esm.min.js +3 -3
  247. package/modules/htmx.min.cjs +3 -3
  248. package/modules/htmx.min.js +3 -3
  249. package/modules/kanban.d.ts +1 -1
  250. package/modules/kanban.esm.min.js +2 -2
  251. package/modules/kanban.min.cjs +2 -2
  252. package/modules/kanban.min.js +2 -2
  253. package/modules/kpi.d.ts +1 -1
  254. package/modules/kpi.esm.min.js +2 -2
  255. package/modules/kpi.min.cjs +2 -2
  256. package/modules/kpi.min.js +2 -2
  257. package/modules/layout.d.ts +1 -1
  258. package/modules/layout.esm.min.js +2 -2
  259. package/modules/layout.min.cjs +2 -2
  260. package/modules/layout.min.js +2 -2
  261. package/modules/leaflet.d.ts +1 -1
  262. package/modules/leaflet.esm.min.js +2 -2
  263. package/modules/leaflet.min.cjs +2 -2
  264. package/modules/leaflet.min.js +2 -2
  265. package/modules/list.d.ts +1 -1
  266. package/modules/list.esm.min.js +2 -2
  267. package/modules/list.min.cjs +2 -2
  268. package/modules/list.min.js +2 -2
  269. package/modules/mapview.d.ts +1 -1
  270. package/modules/mapview.esm.min.js +2 -2
  271. package/modules/mapview.min.cjs +2 -2
  272. package/modules/mapview.min.js +2 -2
  273. package/modules/mock-socket.d.ts +1 -1
  274. package/modules/mock-socket.esm.min.js +1 -1
  275. package/modules/mock-socket.min.cjs +1 -1
  276. package/modules/mock-socket.min.js +1 -1
  277. package/modules/presets.d.ts +1 -1
  278. package/modules/presets.esm.min.js +2 -2
  279. package/modules/presets.min.cjs +2 -2
  280. package/modules/presets.min.js +2 -2
  281. package/modules/react.d.ts +1 -1
  282. package/modules/react.esm.min.js +2 -2
  283. package/modules/react.esm.min.js.map +1 -1
  284. package/modules/react.min.cjs +2 -2
  285. package/modules/react.min.js +2 -2
  286. package/modules/react.min.js.map +1 -1
  287. package/modules/svelte.d.ts +1 -1
  288. package/modules/svelte.esm.min.js +3 -3
  289. package/modules/svelte.esm.min.js.map +1 -1
  290. package/modules/svelte.min.cjs +2 -2
  291. package/modules/svelte.min.js +2 -2
  292. package/modules/svelte.min.js.map +1 -1
  293. package/modules/tabs.d.ts +1 -1
  294. package/modules/tabs.esm.min.js +2 -2
  295. package/modules/tabs.min.cjs +2 -2
  296. package/modules/tabs.min.js +2 -2
  297. package/modules/vue.d.ts +1 -1
  298. package/modules/vue.esm.min.js +2 -2
  299. package/modules/vue.esm.min.js.map +1 -1
  300. package/modules/vue.min.cjs +2 -2
  301. package/modules/vue.min.js +2 -2
  302. package/modules/vue.min.js.map +1 -1
  303. package/modules/webcomponent.d.ts +1 -1
  304. package/modules/webcomponent.esm.min.js +4 -4
  305. package/modules/webcomponent.esm.min.js.map +1 -1
  306. package/modules/webcomponent.min.cjs +4 -4
  307. package/modules/webcomponent.min.js +4 -4
  308. package/modules/webcomponent.min.js.map +1 -1
  309. package/package.json +1 -1
@@ -13,7 +13,7 @@
13
13
  Self-contained: no stylesheet, script or font is fetched, so this opens from disk, from
14
14
  a file share or from behind a firewall with nothing else present.
15
15
  -->
16
- <title>Gantt API Reference — Lattice Grid 1.88.2</title>
16
+ <title>Gantt API Reference — Lattice Grid 1.88.3</title>
17
17
  <style>
18
18
  /* ---------------------------------------------------------------
19
19
  Palette lifted from the grid's own theme, so the reference reads as an
@@ -822,6 +822,46 @@ view.setWorkloadUnit('hours'); // the same toggle the band's own switch drives
822
822
  const after = cellText(); // the identical booking, read back as hours: 8
823
823
  view.destroy();
824
824
  return [before, after].join(' | ');</code></pre>
825
+ <p id="split-column-resize"><strong>Split view: resizable columns and divider (BACKLOG-0001924).</strong> Every left-table column header (<code>__colhead</code>) carries a draggable right border with a col-resize cursor; once it is focused (by pointer or Tab), the arrow keys step it 8px a press, 32px with Shift. A column's own <code>minWidth</code>/<code>maxWidth</code> clamp how far it goes, and <code>resizable: false</code> omits the border entirely. The table/timeline divider (<code>gridWidth</code>) is the same gesture — a thin strip between the two panels, focusable and keyed the same way. A settled drag or keystroke on either — never mid-drag — fires exactly one <code>columnResize</code> event: <code>{ key, width, widths }</code>, the divider reporting <code>key: 'grid'</code> and <code>widths</code> carrying every column's current width plus the divider's own. The same widths are reachable any time off the view as <code>view.getColumnWidths()</code>, and round-trip through <code>gantt.getState()</code>/<code>setState()</code> — restoring a saved state calls <code>view.setColumnWidths()</code> for you.</p>
826
+ <pre data-run="js" data-expect="2 | grid | 90px | none | 332 | 90" data-covers="method:gantt.mountSplit"><code>const { createTestDom } = await import('../packages/dom/src/renderer/testdom.js');
827
+ const { createGantt } = await import('../packages/modules/gantt/index.js');
828
+
829
+ const { root, document } = createTestDom();
830
+ const columns = [
831
+ { key: 'name', title: 'Task', width: 0, kind: 'name' },
832
+ { key: 'duration', title: 'Days', width: 60, kind: 'duration', minWidth: 50, maxWidth: 90 },
833
+ { key: 'locked', title: 'Locked', width: 40, resizable: false },
834
+ ];
835
+ const gantt = createGantt({ projectStart: '2027-01-04', tasks: [{ id: 'design', name: 'Design', duration: 5 }] });
836
+ const view = gantt.mountSplit(root, { gridWidth: 300, columns });
837
+ const NS = 'lat-gantt-split';
838
+
839
+ let events = 0;
840
+ let lastKey = null;
841
+ gantt.on('columnResize', (e) => { events += 1; lastKey = e.key; });
842
+
843
+ // Drag the "Days" column's border 50px right — past its own 90px maxWidth.
844
+ const handle = root.querySelector('.' + NS + '__colresize[data-resize-key="duration"]');
845
+ handle.dispatchEvent({ type: 'pointerdown', target: handle, clientX: 0, clientY: 0, button: 0, bubbles: true });
846
+ document.documentElement.dispatchEvent({ type: 'pointermove', target: document.documentElement, clientX: 50, clientY: 0 });
847
+ document.documentElement.dispatchEvent({ type: 'pointerup', target: document.documentElement, clientX: 50, clientY: 0 });
848
+ const daysWidth = root.querySelectorAll('.' + NS + '__colhead')[1].style.width;
849
+
850
+ // `resizable: false` grows no border to drag at all.
851
+ const lockedHandle = root.querySelector('.' + NS + '__colresize[data-resize-key="locked"]');
852
+
853
+ // Shift+ArrowRight on the focused divider steps it 32px.
854
+ const divider = root.querySelector('.' + NS + '__divider--resize');
855
+ divider.dispatchEvent({ type: 'keydown', target: divider, key: 'ArrowRight', shiftKey: true, bubbles: true });
856
+
857
+ // Persist the resize, remount fresh, and restore it.
858
+ const saved = gantt.getState();
859
+ gantt.mountSplit(root, { gridWidth: 300, columns });
860
+ gantt.setState(saved);
861
+ const restored = gantt.getState();
862
+
863
+ view.destroy();
864
+ return [events, lastKey, daysWidth, lockedHandle ? 'handle' : 'none', restored.gridWidth, restored.columnWidths.duration].join(' | ');</code></pre>
825
865
  <p><strong>Live data.</strong> The Gantt exposes the same consumer surface as the grid — <code>gantt.rows.apply({ add, update, remove })</code>, keyed by its <code>rowKey</code> (default <code>id</code>) — so a <a href="data-router.html#datarouter">Data Router</a> attaches to it exactly as it does a grid, a board or a chart. One arriving stream can hydrate and update a whole screen, the Gantt included; each change recomputes the schedule and redraws.</p>
826
866
  <pre><code>import { createDataRouter } from '@toclocoinc/lattice-grid/modules/data-router';
827
867
 
@@ -1298,6 +1338,19 @@ router.apply(deltas); // updates recompute the s
1298
1338
  <tr><td class="name">dependencyCreate:cancelled</td><td class="type"><a href="#type-GanttDependencyCreateCancelledEvent">GanttDependencyCreateCancelledEvent</a></td><td class="desc">The links that were not created, and why.</td></tr>
1299
1339
  <tr><td class="name">taskDelete:cancelled</td><td class="type"><a href="#type-GanttTaskDeleteCancelledEvent">GanttTaskDeleteCancelledEvent</a></td><td class="desc">The task that was not deleted, and why.</td></tr>
1300
1340
  <tr><td class="name">history</td><td class="type"><a href="#type-GanttHistoryEvent">GanttHistoryEvent</a></td><td class="desc">The undo/redo timeline's new state (BACKLOG-0001864).</td></tr>
1341
+ <tr><td class="name">columnResize</td><td class="type"><a href="#type-GanttColumnResizeEvent">GanttColumnResizeEvent</a></td><td class="desc">The settled column/divider width, and a snapshot of every width (BACKLOG-0001924).</td></tr>
1342
+ </tbody>
1343
+ </table>
1344
+ </div>
1345
+ <h4 id="type-GanttColumnResizeEvent">GanttColumnResizeEvent</h4>
1346
+ <p class="section-note">The payload of the `columnResize` event (BACKLOG-0001924), fired once a split-view column-border or table/timeline-divider drag or keyboard resize settles — never mid-drag, so one gesture is exactly one event.</p>
1347
+ <div class="table-wrap">
1348
+ <table>
1349
+ <thead><tr><th>Property</th><th>Type</th><th>Description</th></tr></thead>
1350
+ <tbody>
1351
+ <tr><td class="name">key</td><td class="type">string</td><td class="desc">The column `key` that was resized, or `'grid'` for the table/timeline divider.</td></tr>
1352
+ <tr><td class="name">width</td><td class="type">number</td><td class="desc">The settled width, in pixels, after the column's/divider's own `minWidth`/`maxWidth` clamp.</td></tr>
1353
+ <tr><td class="name">widths</td><td class="type">Record&lt;string, number&gt;</td><td class="desc">Every left-panel column's current rendered width, keyed by its own `key`, plus the divider's own width under `'grid'` — a full snapshot a host can persist directly, e.g. alongside `gantt.getState()`'s own `columnWidths` (which carries the same shape, minus `grid`).</td></tr>
1301
1354
  </tbody>
1302
1355
  </table>
1303
1356
  </div>
@@ -1336,6 +1389,8 @@ router.apply(deltas); // updates recompute the s
1336
1389
  <tr><td class="name">toggleResource</td><td class="type">(resource: string): void</td><td class="desc"><code>resource: string</code></td><td class="type"><code>void</code></td><td class="desc">Expand or collapse a resource's per-task sub-rows in the workload band, and redraw.</td></tr>
1337
1390
  <tr><td class="name">getWorkloadUnit</td><td class="type">(): 'hours' | 'percent' | 'cost'</td><td class="desc">&mdash;</td><td class="type"><code>'hours' | 'percent' | 'cost'</code></td><td class="desc">The unit the workload band (and, when mounted, the histogram band) is currently drawing in (BACKLOG-0001879, BACKLOG-0001866).</td></tr>
1338
1391
  <tr><td class="name">setWorkloadUnit</td><td class="type">(unit: 'hours' | 'percent' | 'cost'): void</td><td class="desc"><code>unit: 'hours' | 'percent' | 'cost'</code></td><td class="type"><code>void</code></td><td class="desc">Switch the workload and histogram bands to hours, percent-of-capacity or cost (BACKLOG-0001879, BACKLOG-0001866), redraw, and announce the change in the live region. Round-trips through the controller's `getState`/`setState`. A no-op when neither band is mounted.</td></tr>
1392
+ <tr><td class="name">getColumnWidths</td><td class="type">(): Record&lt;string, number&gt;</td><td class="desc">&mdash;</td><td class="type"><code>Record&lt;string, number&gt;</code></td><td class="desc">Every left-panel column's current rendered width, keyed by column `key` (BACKLOG-0001924) — every column, not merely a resized one, so restoring this exact snapshot reproduces the layout on screen. Round-trips through the controller's `getState`/`setState`.</td></tr>
1393
+ <tr><td class="name">setColumnWidths</td><td class="type">(widths: Record&lt;string, number&gt;): void</td><td class="desc"><code>widths: Record&lt;string, number&gt;</code></td><td class="type"><code>void</code></td><td class="desc">Restore column widths from {@link getColumnWidths} (BACKLOG-0001924). Each is clamped to that column's own `minWidth`/`maxWidth` and skipped for an unknown key or a `resizable: false` column, then the view redraws.</td></tr>
1339
1394
  <tr><td class="name">toSVG</td><td class="type">(svgOpts?: { range?: { from?: number | string | Date; to?: number | string | Date } }): string</td><td class="desc"><code>svgOpts?: { range?: { from?: number | string | Date; to?: number | string | Date } }</code></td><td class="type"><code>string</code></td><td class="desc">Serialise this split view — the left panel, the timeline and whichever bands are mounted — to a standalone SVG string (BACKLOG-0001863), drawn with a fixed palette independent of the mounted theme. `''` before anything has been drawn.</td></tr>
1340
1395
  <tr><td class="name">toPNG</td><td class="type">(pngOpts?: { range?: { from?: number | string | Date; to?: number | string | Date }; scale?: number; background?: string; }): Promise&lt;Blob | null&gt;</td><td class="desc"><code>pngOpts?: { range?: { from?: number | string | Date; to?: number | string | Date }; scale?: number; background?: string; }</code></td><td class="type"><code>Promise&lt;Blob | null&gt;</code></td><td class="desc">This split view as a PNG (BACKLOG-0001863): `toSVG` rasterised through a canvas. Makes no network request. `null` when nothing is drawn or there is no canvas to rasterise with.</td></tr>
1341
1396
  <tr><td class="name">print</td><td class="type">(printOpts?: { paper?: 'A4' | 'Letter' | 'A3'; orientation?: 'landscape' | 'portrait'; fitToWidth?: boolean; scale?: number; title?: string | false; header?: string | ((page: number, pages: number) =&gt; string) | false; footer?: string | ((page: number, pages: number) =&gt; string) | false; }): boolean</td><td class="desc"><code>printOpts?: { paper?: 'A4' | 'Letter' | 'A3'; orientation?: 'landscape' | 'portrait'; fitToWidth?: boolean; scale?: number; title?: string | false; header?: string | ((page: number, pages: number) =&gt; string) | false; footer?: string | ((page: number, pages: number) =&gt; string) | false; }</code></td><td class="type"><code>boolean</code></td><td class="desc">Print this split view — the table, the timeline, and the workload and histogram bands when mounted — paged and scaled (BACKLOG-0001863): the table header and timeline header repeat on every page and no row is split across a page boundary. Opens the browser's own print path over a standalone document; "PDF" is whatever the browser's print dialog offers ("Save as PDF") — no server, no dependency. Always prints in a fixed, print-safe light palette, independent of the mounted theme.</td></tr>
@@ -1392,7 +1447,7 @@ router.apply(deltas); // updates recompute the s
1392
1447
  <tr><td class="name">canRedo</td><td class="type">(): boolean</td><td class="desc">&mdash;</td><td class="type"><code>boolean</code></td><td class="desc">Whether there is an edit to redo (BACKLOG-0001864).</td></tr>
1393
1448
  <tr><td class="name">clearHistory</td><td class="type">(): void</td><td class="desc">&mdash;</td><td class="type"><code>void</code></td><td class="desc">Forget the whole undo/redo timeline (BACKLOG-0001864) and emit `history`. History is also cleared by `setTasks`/`setState` and lost on reload; this is the explicit reset after loading a fresh plan through `rows.apply`.</td></tr>
1394
1449
  <tr><td class="name">mount</td><td class="type">(container: unknown, options?: { /** * The plot width. `'container'` (the default) measures the element it was * mounted into and keeps following it, so a plan in a tab, drawer, * accordion or split pane fits without the host writing a * `ResizeObserver` (BACKLOG-0001079); a container with no box yet holds a * 720px fallback rather than drawing at zero. A number is honoured * exactly and installs no observer. Ignored under `zoom`, which warns. */ width?: number | 'container'; rowHeight?: number; labelWidth?: number; rowLabels?: boolean; showArrows?: boolean; showCritical?: boolean; showProgress?: boolean; dateAxis?: boolean; /** * The today line, as a plan day-number or a calendar date. A date is * converted into plan space through `projectEpoch` (BACKLOG-0001079), so * "put the line on the real today" is expressible for a relative plan. */ today?: number | string | Date; /** * The calendar date plan day 0 stands for (BACKLOG-0001079). * * Display-only: axis ticks, bar labels, tooltips, screen-reader text and * the built-in `'weekends'` shading move with it; the schedule, `getState` * and the CSV/MSPDI exports do not. Without it, the engine's contract makes * day 0 the Unix epoch, which is why a plan written as day offsets renders * as January 1970. A host-supplied `nonWorking` function still receives raw * plan days. */ projectEpoch?: number | string | Date | null; nonWorking?: 'weekends' | ((day: number) =&gt; boolean); label?: GanttBarLabel | ((task: GanttScheduledTask) =&gt; string); /** Whether bars can be dragged to move/resize (default true). */ editable?: boolean; /** Pixels from a bar's right edge that begin a resize rather than a move. */ resizeZone?: number; /** Time-scale zoom: a level, or raw pixels-per-day. Omit to fit the width. */ zoom?: <a href="types.html#type-GanttZoom">GanttZoom</a> | number; /** Scroll so the today line is in view after drawing. */ scrollToToday?: boolean; /** * The task tooltip (BACKLOG-0001921): a positioned card on hover and * keyboard focus, anchored to the bar. Default true. See {@link <a href="types.html#type-GanttTooltip">GanttTooltip</a>}. */ tooltip?: <a href="types.html#type-GanttTooltip">GanttTooltip</a>; /** Group tasks into swimlanes by a task property name or `fn(task)`. */ groupBy?: string | ((task: <a href="#type-GanttTask">GanttTask</a>) =&gt; unknown); /** Keyboard editing + focusable bars + ARIA announcements (default true). */ keyboard?: boolean; /** Days a keyboard arrow moves/resizes a task (default 1). */ moveStep?: number; }): unknown</td><td class="desc"><code>container: unknown</code><br><code>options?: { /** * The plot width. `'container'` (the default) measures the element it was * mounted into and keeps following it, so a plan in a tab, drawer, * accordion or split pane fits without the host writing a * `ResizeObserver` (BACKLOG-0001079); a container with no box yet holds a * 720px fallback rather than drawing at zero. A number is honoured * exactly and installs no observer. Ignored under `zoom`, which warns. */ width?: number | 'container'; rowHeight?: number; labelWidth?: number; rowLabels?: boolean; showArrows?: boolean; showCritical?: boolean; showProgress?: boolean; dateAxis?: boolean; /** * The today line, as a plan day-number or a calendar date. A date is * converted into plan space through `projectEpoch` (BACKLOG-0001079), so * "put the line on the real today" is expressible for a relative plan. */ today?: number | string | Date; /** * The calendar date plan day 0 stands for (BACKLOG-0001079). * * Display-only: axis ticks, bar labels, tooltips, screen-reader text and * the built-in `'weekends'` shading move with it; the schedule, `getState` * and the CSV/MSPDI exports do not. Without it, the engine's contract makes * day 0 the Unix epoch, which is why a plan written as day offsets renders * as January 1970. A host-supplied `nonWorking` function still receives raw * plan days. */ projectEpoch?: number | string | Date | null; nonWorking?: 'weekends' | ((day: number) =&gt; boolean); label?: GanttBarLabel | ((task: GanttScheduledTask) =&gt; string); /** Whether bars can be dragged to move/resize (default true). */ editable?: boolean; /** Pixels from a bar's right edge that begin a resize rather than a move. */ resizeZone?: number; /** Time-scale zoom: a level, or raw pixels-per-day. Omit to fit the width. */ zoom?: <a href="types.html#type-GanttZoom">GanttZoom</a> | number; /** Scroll so the today line is in view after drawing. */ scrollToToday?: boolean; /** * The task tooltip (BACKLOG-0001921): a positioned card on hover and * keyboard focus, anchored to the bar. Default true. See {@link <a href="types.html#type-GanttTooltip">GanttTooltip</a>}. */ tooltip?: <a href="types.html#type-GanttTooltip">GanttTooltip</a>; /** Group tasks into swimlanes by a task property name or `fn(task)`. */ groupBy?: string | ((task: <a href="#type-GanttTask">GanttTask</a>) =&gt; unknown); /** Keyboard editing + focusable bars + ARIA announcements (default true). */ keyboard?: boolean; /** Days a keyboard arrow moves/resizes a task (default 1). */ moveStep?: number; }</code></td><td class="type"><code>unknown</code></td><td class="desc">Render the plan into a container as an SVG timeline (bars, dependency arrows, critical-path highlight, today line, non-working shading, milestones, progress). The view redraws when the schedule recomputes.</td></tr>
1395
- <tr><td class="name">mountSplit</td><td class="type">(container: unknown, options?: { height?: number; rowHeight?: number; headerHeight?: number; gridWidth?: number; indent?: number; zoom?: <a href="types.html#type-GanttZoom">GanttZoom</a> | number; today?: number; nonWorking?: 'weekends' | ((day: number) =&gt; boolean); calendar?: <a href="types.html#type-GanttCalendar">GanttCalendar</a> | null; showArrows?: boolean; showProgress?: boolean; showBaseline?: boolean; barLabel?: <a href="types.html#type-GanttBarLabel">GanttBarLabel</a> | ((task: <a href="#type-GanttScheduledTask">GanttScheduledTask</a>) =&gt; string); /** * Surface earned-value metrics in `kind: 'evm'` columns (BACKLOG-0000958). * `true` computes EVM at the today line (or the project finish); an object * overrides the status date and the cost field names. */ evm?: boolean | { statusDate?: number | string | Date; costField?: string; actualCostField?: string }; /** * The S-curve status-date progress line (BACKLOG-0001867): a vertical line * at the status date that jogs, at each task row, to that task's actual * progress point (start + %complete × duration). `true` uses the today line * (or the project finish); an object sets the status date explicitly. The * same status date drives the `plannedPercentComplete` column. */ progressLine?: boolean | { statusDate?: number | string | Date }; /** * Whether the plan can be edited: pointer drags on the timeline and the * left panel's inline cell editors (default true). Same meaning and * default as `mount`'s. */ editable?: boolean; /** * Keyboard editing + focusable bars + ARIA announcements on the timeline * (default true). Same meaning and default as `mount`'s. */ keyboard?: boolean; /** * Pixels from a bar's right edge that begin a resize rather than a move * (default 6). Same meaning and default as `mount`'s. */ resizeZone?: number; /** * The task tooltip (BACKLOG-0001921): the SAME positioned card `mount` * draws, anchored to the hovered or keyboard-focused bar. Default true. * See {@link <a href="types.html#type-GanttTooltip">GanttTooltip</a>}. */ tooltip?: <a href="types.html#type-GanttTooltip">GanttTooltip</a>; /** * A `{ t(key, params) }` resolver for the view's own text — the live * region's edit announcements. Omit it and a gantt bound to a grid borrows * that grid's catalogue; a standalone plan falls back to English. */ messages?: { t: (key: string, params?: Record&lt;string, unknown&gt;) =&gt; string }; /** * The left panel's columns. `kind` decides what the cell shows and what a * double-click edits: `'name'` the WBS tree (edits the name), `'assignee'` * the avatars, `'progress'` the % ring (edits `percentComplete`), `'evm'` * an earned-value `metric`, and `'start'`/`'end'`/`'duration'` the * scheduled window — an ISO date, an ISO date, and a whole number of days, * each of which edits the plan through the same path a bar drag takes * (BACKLOG-0001280). `'effort'` (hours) and `'units'` (a percentage, 100 = * one full-time resource) are the optional effort-driven columns * (BACKLOG-0001868); each edits through `applyEdit`, so the task * reschedules per its `schedulingMode`. A bare string names a built-in * column, so `['name', 'duration', 'effort', 'units']` is enough. On an * editable plan the assignee cell opens the assignment picker. A column * with no `kind` shows the raw task's `key` and edits it only with * `editable: true`. */ columns?: Array&lt;'name' | 'start' | 'end' | 'duration' | 'assignee' | 'progress' | 'effort' | 'units' | { key: string; title?: string; width?: number; kind?: 'name' | 'assignee' | 'progress' | 'evm' | 'plannedPercentComplete' | 'start' | 'end' | 'duration' | 'effort' | 'units' | 'number'; metric?: 'bac' | 'pv' | 'ev' | 'ac' | 'sv' | 'cv' | 'spi' | 'cpi'; digits?: number; editable?: boolean; editField?: string; render?: (task: GanttScheduledTask, ctx: { rawTask: GanttTask; depth: number }) =&gt; unknown }&gt;; /** * A resource workload band beneath the split view (BACKLOG-0001281): * one row per resource on the left and, on the right, that resource's * hours per time bucket — aligned column-for-column with the timeline's * scale header, scroll-locked to it horizontally (vertically it scrolls * on its own), and redrawn in the same paint as the bars whenever the * plan changes. `true` takes the defaults below; an object overrides * them; omitted, no band is drawn. * * **Editing (BACKLOG-0001282).** A resource row expands (a disclosure * button, `aria-expanded`) into one sub-row per task it carries. The * resource's own cell is the read-only aggregate; a SUB-ROW cell accepts * a typed number of hours on a double-click whenever the view's * `editable` is on. What is typed is written to that task's `work` * contour through the same `applyEdit` choke point (and the same * `beforeTaskEdit` veto) a bar drag uses, so the bar, the table row and * the band all move in one paint — including the span, which follows the * contour: type into a column beyond the bar and the bar grows to reach * it. A bucket containing no working day declines the edit and says so. * * **Where the hours come from.** They are DERIVED from the tasks, never * supplied: a task's own `work` (or `hours`) field when it carries a * finite one, otherwise `working days × hoursPerDay × units`, divided * between the task's assignments in proportion to their units and spread * evenly over the working days the task spans. Working days are the days * this view already shades — pass the `calendar`/`nonWorking` option the * plan is scheduled with. Resources, units and capacities are the gantt's * existing vocabulary (`assignee`/`assignees`/`owner`/`assignments` on a * task; `resources`/`defaultCapacity` on `createGantt`); a task naming no * resource is carried on an "Unassigned" row rather than dropped. An * empty bucket is blank, not `0`, and a bucket over * `capacity × hoursPerDay × the bucket's working days` is marked with a * class and an accessible label. */ workload?: boolean | { /** Hours a full-time (`units: 1`) resource works in a working day; default 8. */ hoursPerDay?: number; /** The band's height in pixels, taken from the view's own `height`; default 160. */ height?: number; /** A band row's height in pixels; default 28. */ rowHeight?: number; /** Maximum decimal places in a cell, trailing zeros dropped; default 1. */ decimals?: number; /** Draw the totals row and totals column; default true. */ totals?: boolean; /** * `'hours'` (default; an existing page is unchanged) draws booked * hours; `'percent'` draws hours as a share of the resource's own * available hours that bucket — `booked ÷ available × 100`, the SAME * available-hours figure the over-capacity highlight already uses * (the per-resource calendar included), falling back to hours for a * resource with no known capacity; a bucket with a KNOWN zero (a * part-timer's non-working day, a week wholly on leave) reads "–", * never `Infinity`/`NaN` (BACKLOG-0001879). An `&lt;button * aria-pressed&gt;` switch in the band's header toggles it (and the * histogram band's, when one is mounted) live; the same switch is * reachable off the view as `setWorkloadUnit`/`getWorkloadUnit`. * Editing in percent mode writes HOURS: typing `50` books half the * resource's available hours in that bucket, through the identical * `applyEdit` path an hours edit uses. `'cost'` draws hours × the * resource's rate in force each day (BACKLOG-0001866), read off the * SAME `computeWorkload` pass, falling back to hours for a resource * with no rate data; cost has no capacity concept, so there is no * over-highlight or capacity line in this unit. */ unit?: 'hours' | 'percent' | 'cost'; }; /** * A resource histogram band beneath the split view, below the workload * band when both are mounted (BACKLOG-0001860): one row per resource, * drawn as bars per time bucket rather than a table of numbers, with a * capacity line and a hover/focus tooltip. `true` takes the defaults * below; an object overrides them; omitted, no band is drawn. * * The bars come from the SAME derivation the workload band uses * (`computeWorkload`, driven off `work`/`hours`/`assignments` exactly as * documented on `workload` above) — this is a second PICTURE of the same * numbers, not a second source of them. The non-stacked bar for a bucket * over capacity carries both the normal fill up to capacity and the * over-allocation fill above it; `stacked: 'task'` additionally splits * the within-capacity portion into one coloured segment per contributing * task, still capped by the one over-allocation segment on top. An * accessible table (resource, period, hours/percent, capacity, * over-allocated) is rebuilt alongside the bars on every redraw. * * Mounted alongside `workload` at a fixed `height`, the two bands share * it rather than squeezing the timeline: the timeline keeps at least * half the view, the bands shrink in proportion when both do not * otherwise fit, and — rather than ever reading as an unreadably thin * sliver of bars — the histogram collapses to its header strip (with a * console warning naming the height it needs) when even its * proportional share would leave too little room for the plot. */ histogram?: boolean | { /** Which resources to draw, and in what order; omitted draws every resource `computeWorkload` finds, Unassigned last. */ resources?: string[]; /** `'hours'` (default) draws raw hours; `'percent'` draws hours as a percentage of capacity, falling back to `'hours'` for a resource with no capacity; `'cost'` draws hours × rate (BACKLOG-0001866), falling back to `'hours'` for a resource with no rate data, with no capacity line in this unit. */ unit?: 'hours' | 'percent' | 'cost'; /** `'task'` stacks one segment per contributing task; `false` (default) draws one solid bar per bucket. */ stacked?: 'task' | false; /** The band's total height in pixels; default 160. */ height?: number; /** A band row's height in pixels; default 48. */ rowHeight?: number; }; }): <a href="#type-GanttSplitView">GanttSplitView</a></td><td class="desc"><code>container: unknown</code><br><code>options?: { height?: number; rowHeight?: number; headerHeight?: number; gridWidth?: number; indent?: number; zoom?: <a href="types.html#type-GanttZoom">GanttZoom</a> | number; today?: number; nonWorking?: 'weekends' | ((day: number) =&gt; boolean); calendar?: <a href="types.html#type-GanttCalendar">GanttCalendar</a> | null; showArrows?: boolean; showProgress?: boolean; showBaseline?: boolean; barLabel?: <a href="types.html#type-GanttBarLabel">GanttBarLabel</a> | ((task: <a href="#type-GanttScheduledTask">GanttScheduledTask</a>) =&gt; string); /** * Surface earned-value metrics in `kind: 'evm'` columns (BACKLOG-0000958). * `true` computes EVM at the today line (or the project finish); an object * overrides the status date and the cost field names. */ evm?: boolean | { statusDate?: number | string | Date; costField?: string; actualCostField?: string }; /** * The S-curve status-date progress line (BACKLOG-0001867): a vertical line * at the status date that jogs, at each task row, to that task's actual * progress point (start + %complete × duration). `true` uses the today line * (or the project finish); an object sets the status date explicitly. The * same status date drives the `plannedPercentComplete` column. */ progressLine?: boolean | { statusDate?: number | string | Date }; /** * Whether the plan can be edited: pointer drags on the timeline and the * left panel's inline cell editors (default true). Same meaning and * default as `mount`'s. */ editable?: boolean; /** * Keyboard editing + focusable bars + ARIA announcements on the timeline * (default true). Same meaning and default as `mount`'s. */ keyboard?: boolean; /** * Pixels from a bar's right edge that begin a resize rather than a move * (default 6). Same meaning and default as `mount`'s. */ resizeZone?: number; /** * The task tooltip (BACKLOG-0001921): the SAME positioned card `mount` * draws, anchored to the hovered or keyboard-focused bar. Default true. * See {@link <a href="types.html#type-GanttTooltip">GanttTooltip</a>}. */ tooltip?: <a href="types.html#type-GanttTooltip">GanttTooltip</a>; /** * A `{ t(key, params) }` resolver for the view's own text — the live * region's edit announcements. Omit it and a gantt bound to a grid borrows * that grid's catalogue; a standalone plan falls back to English. */ messages?: { t: (key: string, params?: Record&lt;string, unknown&gt;) =&gt; string }; /** * The left panel's columns. `kind` decides what the cell shows and what a * double-click edits: `'name'` the WBS tree (edits the name), `'assignee'` * the avatars, `'progress'` the % ring (edits `percentComplete`), `'evm'` * an earned-value `metric`, and `'start'`/`'end'`/`'duration'` the * scheduled window — an ISO date, an ISO date, and a whole number of days, * each of which edits the plan through the same path a bar drag takes * (BACKLOG-0001280). `'effort'` (hours) and `'units'` (a percentage, 100 = * one full-time resource) are the optional effort-driven columns * (BACKLOG-0001868); each edits through `applyEdit`, so the task * reschedules per its `schedulingMode`. A bare string names a built-in * column, so `['name', 'duration', 'effort', 'units']` is enough. On an * editable plan the assignee cell opens the assignment picker. A column * with no `kind` shows the raw task's `key` and edits it only with * `editable: true`. */ columns?: Array&lt;'name' | 'start' | 'end' | 'duration' | 'assignee' | 'progress' | 'effort' | 'units' | { key: string; title?: string; width?: number; kind?: 'name' | 'assignee' | 'progress' | 'evm' | 'plannedPercentComplete' | 'start' | 'end' | 'duration' | 'effort' | 'units' | 'number'; metric?: 'bac' | 'pv' | 'ev' | 'ac' | 'sv' | 'cv' | 'spi' | 'cpi'; digits?: number; editable?: boolean; editField?: string; render?: (task: GanttScheduledTask, ctx: { rawTask: GanttTask; depth: number }) =&gt; unknown }&gt;; /** * A resource workload band beneath the split view (BACKLOG-0001281): * one row per resource on the left and, on the right, that resource's * hours per time bucket — aligned column-for-column with the timeline's * scale header, scroll-locked to it horizontally (vertically it scrolls * on its own), and redrawn in the same paint as the bars whenever the * plan changes. `true` takes the defaults below; an object overrides * them; omitted, no band is drawn. * * **Editing (BACKLOG-0001282).** A resource row expands (a disclosure * button, `aria-expanded`) into one sub-row per task it carries. The * resource's own cell is the read-only aggregate; a SUB-ROW cell accepts * a typed number of hours on a double-click whenever the view's * `editable` is on. What is typed is written to that task's `work` * contour through the same `applyEdit` choke point (and the same * `beforeTaskEdit` veto) a bar drag uses, so the bar, the table row and * the band all move in one paint — including the span, which follows the * contour: type into a column beyond the bar and the bar grows to reach * it. A bucket containing no working day declines the edit and says so. * * **Where the hours come from.** They are DERIVED from the tasks, never * supplied: a task's own `work` (or `hours`) field when it carries a * finite one, otherwise `working days × hoursPerDay × units`, divided * between the task's assignments in proportion to their units and spread * evenly over the working days the task spans. Working days are the days * this view already shades — pass the `calendar`/`nonWorking` option the * plan is scheduled with. Resources, units and capacities are the gantt's * existing vocabulary (`assignee`/`assignees`/`owner`/`assignments` on a * task; `resources`/`defaultCapacity` on `createGantt`); a task naming no * resource is carried on an "Unassigned" row rather than dropped. An * empty bucket is blank, not `0`, and a bucket over * `capacity × hoursPerDay × the bucket's working days` is marked with a * class and an accessible label. */ workload?: boolean | { /** Hours a full-time (`units: 1`) resource works in a working day; default 8. */ hoursPerDay?: number; /** The band's height in pixels, taken from the view's own `height`; default 160. */ height?: number; /** A band row's height in pixels; default 28. */ rowHeight?: number; /** Maximum decimal places in a cell, trailing zeros dropped; default 1. */ decimals?: number; /** Draw the totals row and totals column; default true. */ totals?: boolean; /** * `'hours'` (default; an existing page is unchanged) draws booked * hours; `'percent'` draws hours as a share of the resource's own * available hours that bucket — `booked ÷ available × 100`, the SAME * available-hours figure the over-capacity highlight already uses * (the per-resource calendar included), falling back to hours for a * resource with no known capacity; a bucket with a KNOWN zero (a * part-timer's non-working day, a week wholly on leave) reads "–", * never `Infinity`/`NaN` (BACKLOG-0001879). An `&lt;button * aria-pressed&gt;` switch in the band's header toggles it (and the * histogram band's, when one is mounted) live; the same switch is * reachable off the view as `setWorkloadUnit`/`getWorkloadUnit`. * Editing in percent mode writes HOURS: typing `50` books half the * resource's available hours in that bucket, through the identical * `applyEdit` path an hours edit uses. `'cost'` draws hours × the * resource's rate in force each day (BACKLOG-0001866), read off the * SAME `computeWorkload` pass, falling back to hours for a resource * with no rate data; cost has no capacity concept, so there is no * over-highlight or capacity line in this unit. */ unit?: 'hours' | 'percent' | 'cost'; }; /** * A resource histogram band beneath the split view, below the workload * band when both are mounted (BACKLOG-0001860): one row per resource, * drawn as bars per time bucket rather than a table of numbers, with a * capacity line and a hover/focus tooltip. `true` takes the defaults * below; an object overrides them; omitted, no band is drawn. * * The bars come from the SAME derivation the workload band uses * (`computeWorkload`, driven off `work`/`hours`/`assignments` exactly as * documented on `workload` above) — this is a second PICTURE of the same * numbers, not a second source of them. The non-stacked bar for a bucket * over capacity carries both the normal fill up to capacity and the * over-allocation fill above it; `stacked: 'task'` additionally splits * the within-capacity portion into one coloured segment per contributing * task, still capped by the one over-allocation segment on top. An * accessible table (resource, period, hours/percent, capacity, * over-allocated) is rebuilt alongside the bars on every redraw. * * Mounted alongside `workload` at a fixed `height`, the two bands share * it rather than squeezing the timeline: the timeline keeps at least * half the view, the bands shrink in proportion when both do not * otherwise fit, and — rather than ever reading as an unreadably thin * sliver of bars — the histogram collapses to its header strip (with a * console warning naming the height it needs) when even its * proportional share would leave too little room for the plot. */ histogram?: boolean | { /** Which resources to draw, and in what order; omitted draws every resource `computeWorkload` finds, Unassigned last. */ resources?: string[]; /** `'hours'` (default) draws raw hours; `'percent'` draws hours as a percentage of capacity, falling back to `'hours'` for a resource with no capacity; `'cost'` draws hours × rate (BACKLOG-0001866), falling back to `'hours'` for a resource with no rate data, with no capacity line in this unit. */ unit?: 'hours' | 'percent' | 'cost'; /** `'task'` stacks one segment per contributing task; `false` (default) draws one solid bar per bucket. */ stacked?: 'task' | false; /** The band's total height in pixels; default 160. */ height?: number; /** A band row's height in pixels; default 48. */ rowHeight?: number; }; }</code></td><td class="type"><code><a href="#type-GanttSplitView">GanttSplitView</a></code></td><td class="desc">Mount the JOINED split view (BACKLOG-0000938): one continuous, row-aligned surface with a left task-grid panel — by default the Task Name tree with expand/collapse, start, finish, duration, assignee avatars and a circular % ring (BACKLOG-0001285), plus any host columns — and the right timeline, sharing a single vertical scroll so every grid row lines up exactly with its bar row. The timeline scrolls horizontally on its own. Composes the controller's schedule; makes no change to grid core. The plan is editable from BOTH panes (BACKLOG-0001280): every gesture `mount` has — pointer drag to move, drag on the right edge to resize, arrow-key move, Shift+arrow resize, `l` to link, Delete — works on the timeline here, and a `start`/`end`/`duration`/`progress`/`name` column in the left panel is inline-editable on a double-click. Both routes commit through the same `applyEdit` choke point, so `beforeTaskMove`, `beforeTaskResize`, `beforeProgressChange` and `beforeTaskEdit` stay the single veto whichever pane the edit came from. The three switches that govern it carry the same meaning and the same defaults as `mount`'s: `editable` (default true) turns every edit on or off, both panes at once; `keyboard` (default true) turns off the focusable bars, the arrow-key gestures and the ARIA announcements while leaving pointer editing alone; and `resizeZone` (default 6) is how many pixels in from a bar's right edge begin a resize rather than a move. `workload` adds the resource band beneath the plan (BACKLOG-0001281), which is display-only — it reports hours, it does not accept them.</td></tr>
1450
+ <tr><td class="name">mountSplit</td><td class="type">(container: unknown, options?: { height?: number; rowHeight?: number; headerHeight?: number; gridWidth?: number; indent?: number; zoom?: <a href="types.html#type-GanttZoom">GanttZoom</a> | number; today?: number; nonWorking?: 'weekends' | ((day: number) =&gt; boolean); calendar?: <a href="types.html#type-GanttCalendar">GanttCalendar</a> | null; showArrows?: boolean; showProgress?: boolean; showBaseline?: boolean; barLabel?: <a href="types.html#type-GanttBarLabel">GanttBarLabel</a> | ((task: <a href="#type-GanttScheduledTask">GanttScheduledTask</a>) =&gt; string); /** * Surface earned-value metrics in `kind: 'evm'` columns (BACKLOG-0000958). * `true` computes EVM at the today line (or the project finish); an object * overrides the status date and the cost field names. */ evm?: boolean | { statusDate?: number | string | Date; costField?: string; actualCostField?: string }; /** * The S-curve status-date progress line (BACKLOG-0001867): a vertical line * at the status date that jogs, at each task row, to that task's actual * progress point (start + %complete × duration). `true` uses the today line * (or the project finish); an object sets the status date explicitly. The * same status date drives the `plannedPercentComplete` column. */ progressLine?: boolean | { statusDate?: number | string | Date }; /** * Whether the plan can be edited: pointer drags on the timeline and the * left panel's inline cell editors (default true). Same meaning and * default as `mount`'s. */ editable?: boolean; /** * Keyboard editing + focusable bars + ARIA announcements on the timeline * (default true). Same meaning and default as `mount`'s. */ keyboard?: boolean; /** * Pixels from a bar's right edge that begin a resize rather than a move * (default 6). Same meaning and default as `mount`'s. */ resizeZone?: number; /** * The task tooltip (BACKLOG-0001921): the SAME positioned card `mount` * draws, anchored to the hovered or keyboard-focused bar. Default true. * See {@link <a href="types.html#type-GanttTooltip">GanttTooltip</a>}. */ tooltip?: <a href="types.html#type-GanttTooltip">GanttTooltip</a>; /** * A `{ t(key, params) }` resolver for the view's own text — the live * region's edit announcements. Omit it and a gantt bound to a grid borrows * that grid's catalogue; a standalone plan falls back to English. */ messages?: { t: (key: string, params?: Record&lt;string, unknown&gt;) =&gt; string }; /** * The left panel's columns. `kind` decides what the cell shows and what a * double-click edits: `'name'` the WBS tree (edits the name), `'assignee'` * the avatars, `'progress'` the % ring (edits `percentComplete`), `'evm'` * an earned-value `metric`, and `'start'`/`'end'`/`'duration'` the * scheduled window — an ISO date, an ISO date, and a whole number of days, * each of which edits the plan through the same path a bar drag takes * (BACKLOG-0001280). `'effort'` (hours) and `'units'` (a percentage, 100 = * one full-time resource) are the optional effort-driven columns * (BACKLOG-0001868); each edits through `applyEdit`, so the task * reschedules per its `schedulingMode`. A bare string names a built-in * column, so `['name', 'duration', 'effort', 'units']` is enough. On an * editable plan the assignee cell opens the assignment picker. A column * with no `kind` shows the raw task's `key` and edits it only with * `editable: true`. * * Every column header carries a draggable right border with a * col-resize cursor (BACKLOG-0001924): a pointer drag, or arrow keys * once the border itself is focused (8px a press, 32px with Shift). * `minWidth`/`maxWidth` clamp how far it goes; `resizable: false` omits * the border entirely. The table/timeline divider (`gridWidth`) is the * same gesture; a settled drag or keystroke on either fires exactly one * `columnResize`, and every width — the divider's included, under the * key `'grid'` — round-trips through `getState`/`setState`. */ columns?: Array&lt;'name' | 'start' | 'end' | 'duration' | 'assignee' | 'progress' | 'effort' | 'units' | { key: string; title?: string; width?: number; kind?: 'name' | 'assignee' | 'progress' | 'evm' | 'plannedPercentComplete' | 'start' | 'end' | 'duration' | 'effort' | 'units' | 'number'; metric?: 'bac' | 'pv' | 'ev' | 'ac' | 'sv' | 'cv' | 'spi' | 'cpi'; digits?: number; editable?: boolean; editField?: string; /** The narrowest this column can be dragged/keyed to (BACKLOG-0001924); default 80 for `kind: 'name'`, 40 otherwise. */ minWidth?: number; /** The widest this column can be dragged/keyed to (BACKLOG-0001924); default unbounded. */ maxWidth?: number; /** `false` omits the resize border on this column's header (BACKLOG-0001924); default true. */ resizable?: boolean; render?: (task: GanttScheduledTask, ctx: { rawTask: GanttTask; depth: number }) =&gt; unknown; }&gt;; /** * A resource workload band beneath the split view (BACKLOG-0001281): * one row per resource on the left and, on the right, that resource's * hours per time bucket — aligned column-for-column with the timeline's * scale header, scroll-locked to it horizontally (vertically it scrolls * on its own), and redrawn in the same paint as the bars whenever the * plan changes. `true` takes the defaults below; an object overrides * them; omitted, no band is drawn. * * **Editing (BACKLOG-0001282).** A resource row expands (a disclosure * button, `aria-expanded`) into one sub-row per task it carries. The * resource's own cell is the read-only aggregate; a SUB-ROW cell accepts * a typed number of hours on a double-click whenever the view's * `editable` is on. What is typed is written to that task's `work` * contour through the same `applyEdit` choke point (and the same * `beforeTaskEdit` veto) a bar drag uses, so the bar, the table row and * the band all move in one paint — including the span, which follows the * contour: type into a column beyond the bar and the bar grows to reach * it. A bucket containing no working day declines the edit and says so. * * **Where the hours come from.** They are DERIVED from the tasks, never * supplied: a task's own `work` (or `hours`) field when it carries a * finite one, otherwise `working days × hoursPerDay × units`, divided * between the task's assignments in proportion to their units and spread * evenly over the working days the task spans. Working days are the days * this view already shades — pass the `calendar`/`nonWorking` option the * plan is scheduled with. Resources, units and capacities are the gantt's * existing vocabulary (`assignee`/`assignees`/`owner`/`assignments` on a * task; `resources`/`defaultCapacity` on `createGantt`); a task naming no * resource is carried on an "Unassigned" row rather than dropped. An * empty bucket is blank, not `0`, and a bucket over * `capacity × hoursPerDay × the bucket's working days` is marked with a * class and an accessible label. */ workload?: boolean | { /** Hours a full-time (`units: 1`) resource works in a working day; default 8. */ hoursPerDay?: number; /** The band's height in pixels, taken from the view's own `height`; default 160. */ height?: number; /** A band row's height in pixels; default 28. */ rowHeight?: number; /** Maximum decimal places in a cell, trailing zeros dropped; default 1. */ decimals?: number; /** Draw the totals row and totals column; default true. */ totals?: boolean; /** * `'hours'` (default; an existing page is unchanged) draws booked * hours; `'percent'` draws hours as a share of the resource's own * available hours that bucket — `booked ÷ available × 100`, the SAME * available-hours figure the over-capacity highlight already uses * (the per-resource calendar included), falling back to hours for a * resource with no known capacity; a bucket with a KNOWN zero (a * part-timer's non-working day, a week wholly on leave) reads "–", * never `Infinity`/`NaN` (BACKLOG-0001879). An `&lt;button * aria-pressed&gt;` switch in the band's header toggles it (and the * histogram band's, when one is mounted) live; the same switch is * reachable off the view as `setWorkloadUnit`/`getWorkloadUnit`. * Editing in percent mode writes HOURS: typing `50` books half the * resource's available hours in that bucket, through the identical * `applyEdit` path an hours edit uses. `'cost'` draws hours × the * resource's rate in force each day (BACKLOG-0001866), read off the * SAME `computeWorkload` pass, falling back to hours for a resource * with no rate data; cost has no capacity concept, so there is no * over-highlight or capacity line in this unit. */ unit?: 'hours' | 'percent' | 'cost'; }; /** * A resource histogram band beneath the split view, below the workload * band when both are mounted (BACKLOG-0001860): one row per resource, * drawn as bars per time bucket rather than a table of numbers, with a * capacity line and a hover/focus tooltip. `true` takes the defaults * below; an object overrides them; omitted, no band is drawn. * * The bars come from the SAME derivation the workload band uses * (`computeWorkload`, driven off `work`/`hours`/`assignments` exactly as * documented on `workload` above) — this is a second PICTURE of the same * numbers, not a second source of them. The non-stacked bar for a bucket * over capacity carries both the normal fill up to capacity and the * over-allocation fill above it; `stacked: 'task'` additionally splits * the within-capacity portion into one coloured segment per contributing * task, still capped by the one over-allocation segment on top. An * accessible table (resource, period, hours/percent, capacity, * over-allocated) is rebuilt alongside the bars on every redraw. * * Mounted alongside `workload` at a fixed `height`, the two bands share * it rather than squeezing the timeline: the timeline keeps at least * half the view, the bands shrink in proportion when both do not * otherwise fit, and — rather than ever reading as an unreadably thin * sliver of bars — the histogram collapses to its header strip (with a * console warning naming the height it needs) when even its * proportional share would leave too little room for the plot. */ histogram?: boolean | { /** Which resources to draw, and in what order; omitted draws every resource `computeWorkload` finds, Unassigned last. */ resources?: string[]; /** `'hours'` (default) draws raw hours; `'percent'` draws hours as a percentage of capacity, falling back to `'hours'` for a resource with no capacity; `'cost'` draws hours × rate (BACKLOG-0001866), falling back to `'hours'` for a resource with no rate data, with no capacity line in this unit. */ unit?: 'hours' | 'percent' | 'cost'; /** `'task'` stacks one segment per contributing task; `false` (default) draws one solid bar per bucket. */ stacked?: 'task' | false; /** The band's total height in pixels; default 160. */ height?: number; /** A band row's height in pixels; default 48. */ rowHeight?: number; }; }): <a href="#type-GanttSplitView">GanttSplitView</a></td><td class="desc"><code>container: unknown</code><br><code>options?: { height?: number; rowHeight?: number; headerHeight?: number; gridWidth?: number; indent?: number; zoom?: <a href="types.html#type-GanttZoom">GanttZoom</a> | number; today?: number; nonWorking?: 'weekends' | ((day: number) =&gt; boolean); calendar?: <a href="types.html#type-GanttCalendar">GanttCalendar</a> | null; showArrows?: boolean; showProgress?: boolean; showBaseline?: boolean; barLabel?: <a href="types.html#type-GanttBarLabel">GanttBarLabel</a> | ((task: <a href="#type-GanttScheduledTask">GanttScheduledTask</a>) =&gt; string); /** * Surface earned-value metrics in `kind: 'evm'` columns (BACKLOG-0000958). * `true` computes EVM at the today line (or the project finish); an object * overrides the status date and the cost field names. */ evm?: boolean | { statusDate?: number | string | Date; costField?: string; actualCostField?: string }; /** * The S-curve status-date progress line (BACKLOG-0001867): a vertical line * at the status date that jogs, at each task row, to that task's actual * progress point (start + %complete × duration). `true` uses the today line * (or the project finish); an object sets the status date explicitly. The * same status date drives the `plannedPercentComplete` column. */ progressLine?: boolean | { statusDate?: number | string | Date }; /** * Whether the plan can be edited: pointer drags on the timeline and the * left panel's inline cell editors (default true). Same meaning and * default as `mount`'s. */ editable?: boolean; /** * Keyboard editing + focusable bars + ARIA announcements on the timeline * (default true). Same meaning and default as `mount`'s. */ keyboard?: boolean; /** * Pixels from a bar's right edge that begin a resize rather than a move * (default 6). Same meaning and default as `mount`'s. */ resizeZone?: number; /** * The task tooltip (BACKLOG-0001921): the SAME positioned card `mount` * draws, anchored to the hovered or keyboard-focused bar. Default true. * See {@link <a href="types.html#type-GanttTooltip">GanttTooltip</a>}. */ tooltip?: <a href="types.html#type-GanttTooltip">GanttTooltip</a>; /** * A `{ t(key, params) }` resolver for the view's own text — the live * region's edit announcements. Omit it and a gantt bound to a grid borrows * that grid's catalogue; a standalone plan falls back to English. */ messages?: { t: (key: string, params?: Record&lt;string, unknown&gt;) =&gt; string }; /** * The left panel's columns. `kind` decides what the cell shows and what a * double-click edits: `'name'` the WBS tree (edits the name), `'assignee'` * the avatars, `'progress'` the % ring (edits `percentComplete`), `'evm'` * an earned-value `metric`, and `'start'`/`'end'`/`'duration'` the * scheduled window — an ISO date, an ISO date, and a whole number of days, * each of which edits the plan through the same path a bar drag takes * (BACKLOG-0001280). `'effort'` (hours) and `'units'` (a percentage, 100 = * one full-time resource) are the optional effort-driven columns * (BACKLOG-0001868); each edits through `applyEdit`, so the task * reschedules per its `schedulingMode`. A bare string names a built-in * column, so `['name', 'duration', 'effort', 'units']` is enough. On an * editable plan the assignee cell opens the assignment picker. A column * with no `kind` shows the raw task's `key` and edits it only with * `editable: true`. * * Every column header carries a draggable right border with a * col-resize cursor (BACKLOG-0001924): a pointer drag, or arrow keys * once the border itself is focused (8px a press, 32px with Shift). * `minWidth`/`maxWidth` clamp how far it goes; `resizable: false` omits * the border entirely. The table/timeline divider (`gridWidth`) is the * same gesture; a settled drag or keystroke on either fires exactly one * `columnResize`, and every width — the divider's included, under the * key `'grid'` — round-trips through `getState`/`setState`. */ columns?: Array&lt;'name' | 'start' | 'end' | 'duration' | 'assignee' | 'progress' | 'effort' | 'units' | { key: string; title?: string; width?: number; kind?: 'name' | 'assignee' | 'progress' | 'evm' | 'plannedPercentComplete' | 'start' | 'end' | 'duration' | 'effort' | 'units' | 'number'; metric?: 'bac' | 'pv' | 'ev' | 'ac' | 'sv' | 'cv' | 'spi' | 'cpi'; digits?: number; editable?: boolean; editField?: string; /** The narrowest this column can be dragged/keyed to (BACKLOG-0001924); default 80 for `kind: 'name'`</code><br><code>40 otherwise. */ minWidth?: number; /** The widest this column can be dragged/keyed to (BACKLOG-0001924); default unbounded. */ maxWidth?: number; /** `false` omits the resize border on this column's header (BACKLOG-0001924); default true. */ resizable?: boolean; render?: (task: GanttScheduledTask, ctx: { rawTask: GanttTask; depth: number }) =&gt; unknown; }&gt;; /** * A resource workload band beneath the split view (BACKLOG-0001281): * one row per resource on the left and, on the right, that resource's * hours per time bucket — aligned column-for-column with the timeline's * scale header, scroll-locked to it horizontally (vertically it scrolls * on its own), and redrawn in the same paint as the bars whenever the * plan changes. `true` takes the defaults below; an object overrides * them; omitted, no band is drawn. * * **Editing (BACKLOG-0001282).** A resource row expands (a disclosure * button, `aria-expanded`) into one sub-row per task it carries. The * resource's own cell is the read-only aggregate; a SUB-ROW cell accepts * a typed number of hours on a double-click whenever the view's * `editable` is on. What is typed is written to that task's `work` * contour through the same `applyEdit` choke point (and the same * `beforeTaskEdit` veto) a bar drag uses, so the bar, the table row and * the band all move in one paint — including the span, which follows the * contour: type into a column beyond the bar and the bar grows to reach * it. A bucket containing no working day declines the edit and says so. * * **Where the hours come from.** They are DERIVED from the tasks, never * supplied: a task's own `work` (or `hours`) field when it carries a * finite one, otherwise `working days × hoursPerDay × units`, divided * between the task's assignments in proportion to their units and spread * evenly over the working days the task spans. Working days are the days * this view already shades — pass the `calendar`/`nonWorking` option the * plan is scheduled with. Resources, units and capacities are the gantt's * existing vocabulary (`assignee`/`assignees`/`owner`/`assignments` on a * task; `resources`/`defaultCapacity` on `createGantt`); a task naming no * resource is carried on an "Unassigned" row rather than dropped. An * empty bucket is blank, not `0`, and a bucket over * `capacity × hoursPerDay × the bucket's working days` is marked with a * class and an accessible label. */ workload?: boolean | { /** Hours a full-time (`units: 1`) resource works in a working day; default 8. */ hoursPerDay?: number; /** The band's height in pixels, taken from the view's own `height`; default 160. */ height?: number; /** A band row's height in pixels; default 28. */ rowHeight?: number; /** Maximum decimal places in a cell, trailing zeros dropped; default 1. */ decimals?: number; /** Draw the totals row and totals column; default true. */ totals?: boolean; /** * `'hours'` (default; an existing page is unchanged) draws booked * hours; `'percent'` draws hours as a share of the resource's own * available hours that bucket — `booked ÷ available × 100`, the SAME * available-hours figure the over-capacity highlight already uses * (the per-resource calendar included), falling back to hours for a * resource with no known capacity; a bucket with a KNOWN zero (a * part-timer's non-working day, a week wholly on leave) reads "–", * never `Infinity`/`NaN` (BACKLOG-0001879). An `&lt;button * aria-pressed&gt;` switch in the band's header toggles it (and the * histogram band's, when one is mounted) live; the same switch is * reachable off the view as `setWorkloadUnit`/`getWorkloadUnit`. * Editing in percent mode writes HOURS: typing `50` books half the * resource's available hours in that bucket, through the identical * `applyEdit` path an hours edit uses. `'cost'` draws hours × the * resource's rate in force each day (BACKLOG-0001866), read off the * SAME `computeWorkload` pass, falling back to hours for a resource * with no rate data; cost has no capacity concept, so there is no * over-highlight or capacity line in this unit. */ unit?: 'hours' | 'percent' | 'cost'; }; /** * A resource histogram band beneath the split view, below the workload * band when both are mounted (BACKLOG-0001860): one row per resource, * drawn as bars per time bucket rather than a table of numbers, with a * capacity line and a hover/focus tooltip. `true` takes the defaults * below; an object overrides them; omitted, no band is drawn. * * The bars come from the SAME derivation the workload band uses * (`computeWorkload`, driven off `work`/`hours`/`assignments` exactly as * documented on `workload` above) — this is a second PICTURE of the same * numbers, not a second source of them. The non-stacked bar for a bucket * over capacity carries both the normal fill up to capacity and the * over-allocation fill above it; `stacked: 'task'` additionally splits * the within-capacity portion into one coloured segment per contributing * task, still capped by the one over-allocation segment on top. An * accessible table (resource, period, hours/percent, capacity, * over-allocated) is rebuilt alongside the bars on every redraw. * * Mounted alongside `workload` at a fixed `height`, the two bands share * it rather than squeezing the timeline: the timeline keeps at least * half the view, the bands shrink in proportion when both do not * otherwise fit, and — rather than ever reading as an unreadably thin * sliver of bars — the histogram collapses to its header strip (with a * console warning naming the height it needs) when even its * proportional share would leave too little room for the plot. */ histogram?: boolean | { /** Which resources to draw, and in what order; omitted draws every resource `computeWorkload` finds, Unassigned last. */ resources?: string[]; /** `'hours'` (default) draws raw hours; `'percent'` draws hours as a percentage of capacity, falling back to `'hours'` for a resource with no capacity; `'cost'` draws hours × rate (BACKLOG-0001866), falling back to `'hours'` for a resource with no rate data, with no capacity line in this unit. */ unit?: 'hours' | 'percent' | 'cost'; /** `'task'` stacks one segment per contributing task; `false` (default) draws one solid bar per bucket. */ stacked?: 'task' | false; /** The band's total height in pixels; default 160. */ height?: number; /** A band row's height in pixels; default 48. */ rowHeight?: number; }; }</code></td><td class="type"><code><a href="#type-GanttSplitView">GanttSplitView</a></code></td><td class="desc">Mount the JOINED split view (BACKLOG-0000938): one continuous, row-aligned surface with a left task-grid panel — by default the Task Name tree with expand/collapse, start, finish, duration, assignee avatars and a circular % ring (BACKLOG-0001285), plus any host columns — and the right timeline, sharing a single vertical scroll so every grid row lines up exactly with its bar row. The timeline scrolls horizontally on its own. Composes the controller's schedule; makes no change to grid core. The plan is editable from BOTH panes (BACKLOG-0001280): every gesture `mount` has — pointer drag to move, drag on the right edge to resize, arrow-key move, Shift+arrow resize, `l` to link, Delete — works on the timeline here, and a `start`/`end`/`duration`/`progress`/`name` column in the left panel is inline-editable on a double-click. Both routes commit through the same `applyEdit` choke point, so `beforeTaskMove`, `beforeTaskResize`, `beforeProgressChange` and `beforeTaskEdit` stay the single veto whichever pane the edit came from. The three switches that govern it carry the same meaning and the same defaults as `mount`'s: `editable` (default true) turns every edit on or off, both panes at once; `keyboard` (default true) turns off the focusable bars, the arrow-key gestures and the ARIA announcements while leaving pointer editing alone; and `resizeZone` (default 6) is how many pixels in from a bar's right edge begin a resize rather than a move. `workload` adds the resource band beneath the plan (BACKLOG-0001281), which is display-only — it reports hours, it does not accept them.</td></tr>
1396
1451
  <tr><td class="name">captureBaseline</td><td class="type">(): Array&lt;{ id: string; baselineStart: number; baselineEnd: number; baselineDuration: number }&gt;</td><td class="desc">&mdash;</td><td class="type"><code>Array&lt;{ id: string; baselineStart: number; baselineEnd: number; baselineDuration: number }&gt;</code></td><td class="desc">Capture a baseline (planned) snapshot of the current schedule as HOST data (this does not mutate the tasks). Store it and feed it back as `baselineStart`/`baselineEnd` task fields to get variance and ghost bars.</td></tr>
1397
1452
  <tr><td class="name">earnedValue</td><td class="type">(evmOpts?: { statusDate?: number | string | Date; costField?: string; actualCostField?: string }): <a href="#type-GanttEarnedValue">GanttEarnedValue</a></td><td class="desc"><code>evmOpts?: { statusDate?: number | string | Date; costField?: string; actualCostField?: string }</code></td><td class="type"><code><a href="#type-GanttEarnedValue">GanttEarnedValue</a></code></td><td class="desc">Compute earned-value (EVM) metrics for the current plan at a status date (BACKLOG-0000958): PV/EV/AC and the derived SV/CV/SPI/CPI per task, rolled up to summaries and the project. Budget (BAC) is the task's `cost`, or its duration when no cost is given; AC comes from `actualCost`.</td></tr>
1398
1453
  <tr><td class="name">sCurve</td><td class="type">(scurveOpts?: { statusDate?: number | string | Date; bucket?: 'day' | 'week' | 'month'; costField?: string; actualCostField?: string }): <a href="#type-GanttSCurvePoint">GanttSCurvePoint</a>[]</td><td class="desc"><code>scurveOpts?: { statusDate?: number | string | Date; bucket?: 'day' | 'week' | 'month'; costField?: string; actualCostField?: string }</code></td><td class="type"><code><a href="#type-GanttSCurvePoint">GanttSCurvePoint</a>[]</code></td><td class="desc">Compute the cumulative S-curve for the current plan (BACKLOG-0001867) — one `{ date, pv, ev, ac }` point per time bucket from the project start to the project finish. The same arithmetic `earnedValue` performs, evaluated over time: PV climbs to the total budget at the finish, EV and AC stop at the status date.</td></tr>
@@ -1424,6 +1479,7 @@ router.apply(deltas); // updates recompute the s
1424
1479
  <tr><td class="name">dependencyCreate:cancelled</td><td class="desc">A `beforeDependencyCreate` handler refused the links.</td><td class="type"><a href="#type-GanttDependencyCreateCancelledEvent">GanttDependencyCreateCancelledEvent</a></td><td class="desc">no</td></tr>
1425
1480
  <tr><td class="name">taskDelete:cancelled</td><td class="desc">A `beforeTaskDelete` handler refused the delete.</td><td class="type"><a href="#type-GanttTaskDeleteCancelledEvent">GanttTaskDeleteCancelledEvent</a></td><td class="desc">no</td></tr>
1426
1481
  <tr><td class="name">history</td><td class="desc">The undo/redo timeline changed — an edit was recorded, undone, redone or cleared (BACKLOG-0001864).</td><td class="type"><a href="#type-GanttHistoryEvent">GanttHistoryEvent</a></td><td class="desc">no</td></tr>
1482
+ <tr><td class="name">columnResize</td><td class="desc">A split-view column border or the table/timeline divider finished a drag or keyboard resize (BACKLOG-0001924). Fired once per gesture, never mid-drag.</td><td class="type"><a href="#type-GanttColumnResizeEvent">GanttColumnResizeEvent</a></td><td class="desc">no</td></tr>
1427
1483
  </tbody>
1428
1484
  </table>
1429
1485
  </div>
@@ -13,7 +13,7 @@
13
13
  Self-contained: no stylesheet, script or font is fetched, so this opens from disk, from
14
14
  a file share or from behind a firewall with nothing else present.
15
15
  -->
16
- <title>Geometry API Reference — Lattice Grid 1.88.2</title>
16
+ <title>Geometry API Reference — Lattice Grid 1.88.3</title>
17
17
  <style>
18
18
  /* ---------------------------------------------------------------
19
19
  Palette lifted from the grid's own theme, so the reference reads as an
@@ -13,7 +13,7 @@
13
13
  Self-contained: no stylesheet, script or font is fetched, so this opens from disk, from
14
14
  a file share or from behind a firewall with nothing else present.
15
15
  -->
16
- <title>Grid API Reference — Lattice Grid 1.88.2</title>
16
+ <title>Grid API Reference — Lattice Grid 1.88.3</title>
17
17
  <style>
18
18
  /* ---------------------------------------------------------------
19
19
  Palette lifted from the grid's own theme, so the reference reads as an
@@ -1856,7 +1856,7 @@ grid.destroy();
1856
1856
  <table>
1857
1857
  <thead><tr><th>Member</th><th>Returns</th><th>Description</th></tr></thead>
1858
1858
  <tbody>
1859
- <tr><td class="sig">getVersion()</td><td class="type">string</td><td class="desc">The version this grid came from, e.g. <code>'1.88.2'</code>. Also on the module as <code>getVersion()</code>, for when you have no grid to hand.</td></tr>
1859
+ <tr><td class="sig">getVersion()</td><td class="type">string</td><td class="desc">The version this grid came from, e.g. <code>'1.88.3'</code>. Also on the module as <code>getVersion()</code>, for when you have no grid to hand.</td></tr>
1860
1860
  <tr><td class="sig">get(key)</td><td class="type">unknown</td><td class="desc">Read any configuration key.</td></tr>
1861
1861
  <tr><td class="sig">set(key, value)</td><td class="type">void</td><td class="desc">Write one key. Every key is live; nothing needs a rebuild.</td></tr>
1862
1862
  <tr><td class="sig">setAll(values)</td><td class="type">void</td><td class="desc">Write several in one pass. Emits one <code>config:changed</code> for the batch, not one per key.</td></tr>
@@ -13,7 +13,7 @@
13
13
  Self-contained: no stylesheet, script or font is fetched, so this opens from disk, from
14
14
  a file share or from behind a firewall with nothing else present.
15
15
  -->
16
- <title>API Reference — Lattice Grid 1.88.2</title>
16
+ <title>API Reference — Lattice Grid 1.88.3</title>
17
17
  <style>
18
18
  /* ---------------------------------------------------------------
19
19
  Palette lifted from the grid's own theme, so the reference reads as an
@@ -445,7 +445,7 @@
445
445
  <tr><td class="name"><a href="mapview.html">The map view</a></td><td class="desc"><code>createMapView</code>: a 3D map of the grid's rows beside the grid, linked both ways &mdash; filters, search and grouping redraw it, a selection flies it, a click selects the row. deck.gl and MapLibre stay the page's.</td><td class="type">1</td><td class="type">5</td><td class="type">48</td></tr>
446
446
  <tr><td class="name"><a href="list.html">The list module</a></td><td class="desc"><code>type: 'list'</code>: many values in one cell, each usable on its own &mdash; chips, a token editor, "any item matches" filters and four list operators.</td><td class="type">1</td><td class="type">0</td><td class="type">0</td></tr>
447
447
  <tr><td class="name"><a href="kanban.html">The board (kanban) view</a></td><td class="desc"><code>createKanban</code>: columns from any status property, drag or keyboard moves that write back, swimlanes, sprints, epics and the child grid.</td><td class="type">1</td><td class="type">46</td><td class="type">329</td></tr>
448
- <tr><td class="name"><a href="gantt.html">The Gantt module</a></td><td class="desc"><code>createGantt</code>: the scheduling engine and the critical path, the four dependency links, milestones and summaries, and editable bars.</td><td class="type">1</td><td class="type">32</td><td class="type">267</td></tr>
448
+ <tr><td class="name"><a href="gantt.html">The Gantt module</a></td><td class="desc"><code>createGantt</code>: the scheduling engine and the critical path, the four dependency links, milestones and summaries, and editable bars.</td><td class="type">1</td><td class="type">33</td><td class="type">273</td></tr>
449
449
  <tr><td class="name"><a href="calendar.html">The calendar viewer</a></td><td class="desc"><code>createCalendar</code>: a month grid and a week day-grid of rows as cards, keyed by a date field, with navigation, overflow and the viewer contract.</td><td class="type">1</td><td class="type">11</td><td class="type">89</td></tr>
450
450
  <tr><td class="name"><a href="tabs.html">The tabbed grid</a></td><td class="desc"><code>createTabs</code>: a tab strip where each tab holds a grid, a board, a KPI strip or a Gantt, and the tablist keyboard model.</td><td class="type">1</td><td class="type">7</td><td class="type">57</td></tr>
451
451
  <tr><td class="name"><a href="layout.html">The dashboard layout</a></td><td class="desc"><code>createLayout</code>: windows a reader moves, resizes and closes, the arrangement saved as plain JSON, locking, and the cancellable gestures.</td><td class="type">1</td><td class="type">15</td><td class="type">131</td></tr>
@@ -13,7 +13,7 @@
13
13
  Self-contained: no stylesheet, script or font is fetched, so this opens from disk, from
14
14
  a file share or from behind a firewall with nothing else present.
15
15
  -->
16
- <title>Kanban API Reference — Lattice Grid 1.88.2</title>
16
+ <title>Kanban API Reference — Lattice Grid 1.88.3</title>
17
17
  <style>
18
18
  /* ---------------------------------------------------------------
19
19
  Palette lifted from the grid's own theme, so the reference reads as an
package/docs/api/kpi.html CHANGED
@@ -13,7 +13,7 @@
13
13
  Self-contained: no stylesheet, script or font is fetched, so this opens from disk, from
14
14
  a file share or from behind a firewall with nothing else present.
15
15
  -->
16
- <title>KPI API Reference — Lattice Grid 1.88.2</title>
16
+ <title>KPI API Reference — Lattice Grid 1.88.3</title>
17
17
  <style>
18
18
  /* ---------------------------------------------------------------
19
19
  Palette lifted from the grid's own theme, so the reference reads as an
@@ -13,7 +13,7 @@
13
13
  Self-contained: no stylesheet, script or font is fetched, so this opens from disk, from
14
14
  a file share or from behind a firewall with nothing else present.
15
15
  -->
16
- <title>Layout API Reference — Lattice Grid 1.88.2</title>
16
+ <title>Layout API Reference — Lattice Grid 1.88.3</title>
17
17
  <style>
18
18
  /* ---------------------------------------------------------------
19
19
  Palette lifted from the grid's own theme, so the reference reads as an
@@ -13,7 +13,7 @@
13
13
  Self-contained: no stylesheet, script or font is fetched, so this opens from disk, from
14
14
  a file share or from behind a firewall with nothing else present.
15
15
  -->
16
- <title>Leaflet API Reference — Lattice Grid 1.88.2</title>
16
+ <title>Leaflet API Reference — Lattice Grid 1.88.3</title>
17
17
  <style>
18
18
  /* ---------------------------------------------------------------
19
19
  Palette lifted from the grid's own theme, so the reference reads as an
@@ -13,7 +13,7 @@
13
13
  Self-contained: no stylesheet, script or font is fetched, so this opens from disk, from
14
14
  a file share or from behind a firewall with nothing else present.
15
15
  -->
16
- <title>List API Reference — Lattice Grid 1.88.2</title>
16
+ <title>List API Reference — Lattice Grid 1.88.3</title>
17
17
  <style>
18
18
  /* ---------------------------------------------------------------
19
19
  Palette lifted from the grid's own theme, so the reference reads as an
@@ -13,7 +13,7 @@
13
13
  Self-contained: no stylesheet, script or font is fetched, so this opens from disk, from
14
14
  a file share or from behind a firewall with nothing else present.
15
15
  -->
16
- <title>Map view API Reference — Lattice Grid 1.88.2</title>
16
+ <title>Map view API Reference — Lattice Grid 1.88.3</title>
17
17
  <style>
18
18
  /* ---------------------------------------------------------------
19
19
  Palette lifted from the grid's own theme, so the reference reads as an
@@ -13,7 +13,7 @@
13
13
  Self-contained: no stylesheet, script or font is fetched, so this opens from disk, from
14
14
  a file share or from behind a firewall with nothing else present.
15
15
  -->
16
- <title>Mock socket API Reference — Lattice Grid 1.88.2</title>
16
+ <title>Mock socket API Reference — Lattice Grid 1.88.3</title>
17
17
  <style>
18
18
  /* ---------------------------------------------------------------
19
19
  Palette lifted from the grid's own theme, so the reference reads as an
@@ -13,7 +13,7 @@
13
13
  Self-contained: no stylesheet, script or font is fetched, so this opens from disk, from
14
14
  a file share or from behind a firewall with nothing else present.
15
15
  -->
16
- <title>Presets API Reference — Lattice Grid 1.88.2</title>
16
+ <title>Presets API Reference — Lattice Grid 1.88.3</title>
17
17
  <style>
18
18
  /* ---------------------------------------------------------------
19
19
  Palette lifted from the grid's own theme, so the reference reads as an
@@ -13,7 +13,7 @@
13
13
  Self-contained: no stylesheet, script or font is fetched, so this opens from disk, from
14
14
  a file share or from behind a firewall with nothing else present.
15
15
  -->
16
- <title>Tabs API Reference — Lattice Grid 1.88.2</title>
16
+ <title>Tabs API Reference — Lattice Grid 1.88.3</title>
17
17
  <style>
18
18
  /* ---------------------------------------------------------------
19
19
  Palette lifted from the grid's own theme, so the reference reads as an
@@ -13,7 +13,7 @@
13
13
  Self-contained: no stylesheet, script or font is fetched, so this opens from disk, from
14
14
  a file share or from behind a firewall with nothing else present.
15
15
  -->
16
- <title>Types API Reference — Lattice Grid 1.88.2</title>
16
+ <title>Types API Reference — Lattice Grid 1.88.3</title>
17
17
  <style>
18
18
  /* ---------------------------------------------------------------
19
19
  Palette lifted from the grid's own theme, so the reference reads as an
@@ -2978,7 +2978,7 @@
2978
2978
  <p class="section-note"><small>Declared in <code>lattice-grid/modules/gantt</code>.</small></p>
2979
2979
  <h4 id="type-GanttEventName">GanttEventName</h4>
2980
2980
  <p class="section-note">The events a Gantt controller raises. The controller's own, not a grid's: `grid.on` takes {@link EventName} and knows nothing about these, and a grid-bound Gantt follows the grid's events itself rather than re-publishing them. `on()` takes a name and a listener and warns about nothing, so a misspelt name is a subscription that never fires. The seven `before…` events are cancellable ({@link GanttBeforeEvent}); each has a matching `&lt;action&gt;:cancelled` that fires when a handler refuses, carrying the same context plus the reason. `schedule` and `error` are the recompute's own pair and are raised on every recompute, whatever caused it.</p>
2981
- <p class="type-def"><code>type GanttEventName = 'schedule' | 'error' | 'beforeTaskEdit' | 'beforeTaskMove' | 'beforeTaskResize' | 'beforeProgressChange' | 'beforeMilestoneMove' | 'beforeDependencyCreate' | 'beforeTaskDelete' | 'taskEdit:cancelled' | 'taskMove:cancelled' | 'taskResize:cancelled' | 'progressChange:cancelled' | 'milestoneMove:cancelled' | 'dependencyCreate:cancelled' | 'taskDelete:cancelled' | 'history'</code></p>
2981
+ <p class="type-def"><code>type GanttEventName = 'schedule' | 'error' | 'beforeTaskEdit' | 'beforeTaskMove' | 'beforeTaskResize' | 'beforeProgressChange' | 'beforeMilestoneMove' | 'beforeDependencyCreate' | 'beforeTaskDelete' | 'taskEdit:cancelled' | 'taskMove:cancelled' | 'taskResize:cancelled' | 'progressChange:cancelled' | 'milestoneMove:cancelled' | 'dependencyCreate:cancelled' | 'taskDelete:cancelled' | 'history' | 'columnResize'</code></p>
2982
2982
  <p class="section-note"><small>Declared in <code>lattice-grid/modules/gantt</code>.</small></p>
2983
2983
  <h4 id="type-GanttLinkType">GanttLinkType</h4>
2984
2984
  <p class="section-note">One of the four dependency link types (finish-to-start, start-to-start, finish-to-finish, start-to-finish).</p>
@@ -437,7 +437,7 @@
437
437
  <div class="shell">
438
438
  <aside class="rail">
439
439
  <p class="rail__brand">Lattice Grid</p>
440
- <p class="rail__sub">Developer guide · v1.88.2</p>
440
+ <p class="rail__sub">Developer guide · v1.88.3</p>
441
441
  <nav>
442
442
  <div class="rail__group">
443
443
  <span class="rail__label">Start here</span>
@@ -554,7 +554,7 @@
554
554
  <a href="API.html">reference tables</a> are the shorter version for when you already know.
555
555
  </p>
556
556
  <p class="chips">
557
- <span class="chip">Version 1.88.2</span>
557
+ <span class="chip">Version 1.88.3</span>
558
558
  <span class="chip">Zero dependencies</span>
559
559
  <span class="chip">No build step</span>
560
560
  </p>
@@ -1676,7 +1676,7 @@ off(); <span class="cmt">// every subscrip
1676
1676
  </p>
1677
1677
  <div class="example">
1678
1678
  <p class="example__label">Which version am I running?</p>
1679
- <pre><code>grid.getVersion(); <span class="cmt">// '1.88.2'</span>
1679
+ <pre><code>grid.getVersion(); <span class="cmt">// '1.88.3'</span>
1680
1680
  LatticeGrid.getVersion(); <span class="cmt">// the same, when you have no grid to hand</span></code></pre>
1681
1681
  </div>
1682
1682
  <p class="lead-in">
@@ -12332,7 +12332,7 @@ grid.licence.state(); <span class="cmt">// 'licensed' | 'localhost' | 'trial'<
12332
12332
 
12333
12333
  <footer>
12334
12334
  <p>
12335
- Lattice Grid 1.88.2 · Copyright © 2026 TOCLOCO Inc. All rights reserved.
12335
+ Lattice Grid 1.88.3 · Copyright © 2026 TOCLOCO Inc. All rights reserved.
12336
12336
  Written against the shipped source. Where this guide and the code disagree, the code wins,
12337
12337
  please <a href="https://www.latticegrid.dev">tell us</a>.
12338
12338
  </p>
@@ -1,5 +1,5 @@
1
1
  {
2
- "version": "1.88.2",
2
+ "version": "1.88.3",
3
3
  "generated": "tools/build.js from docs/warnings/catalogue.json",
4
4
  "about": "Every developer-facing diagnostic Lattice Grid prints to the console, by the key it de-duplicates on. The key is the stable identifier: it is the `id` of every reported entry `grid.diagnostics.warnings()` hands back, what the devtools panel lists, and what to quote in a support conversation. A `*` in an id stands for a value filled in at runtime (a column id, a chart id, an event name), so `icon:*` is one entry covering every column the icon renderer refuses.",
5
5
  "fields": {
package/lattice-grid.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Lattice Grid 1.88.2, type declarations
2
+ * Lattice Grid 1.88.3, type declarations
3
3
  * Copyright (c) 2026 TOCLOCO Inc. All rights reserved.
4
4
  * https://latticegrid.dev
5
5
  */