@ganttloom/gantt-core 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,11 +1,17 @@
1
1
  # @ganttloom/gantt-core
2
2
 
3
+ [![npm](https://img.shields.io/npm/v/%40ganttloom%2Fgantt-core)](https://www.npmjs.com/package/@ganttloom/gantt-core)
4
+ [![license](https://img.shields.io/npm/l/%40ganttloom%2Fgantt-core)](../../LICENSE)
5
+
3
6
  Framework-agnostic Gantt chart engine: layout, SVG rendering, drag/resize/link
4
7
  interactions, grouping, critical path, undo/redo, and more — zero runtime
5
- dependencies. If you're using React, prefer
6
- [`@ganttloom/gantt-react`](../gantt-react); use this package directly if
7
- you're integrating with something else (Vue, Svelte, vanilla JS) or want full
8
- control over the DOM lifecycle.
8
+ dependencies. If you're using React or Vue, prefer
9
+ [`@ganttloom/gantt-react`](../gantt-react) or
10
+ [`@ganttloom/gantt-vue`](../gantt-vue); use this package directly if you're
11
+ integrating with something else (Svelte, vanilla JS) or want full control
12
+ over the DOM lifecycle.
13
+
14
+ ![ganttloom overview — day-view Gantt chart with dependencies, critical path, and baselines](https://raw.githubusercontent.com/santhoshkumarhari/ganttLoom/master/docs/screenshots/overview.png)
9
15
 
10
16
  ## Install
11
17
 
@@ -186,6 +192,30 @@ reorder columns. The chart applies the change to its own internal copy of
186
192
  `columns` immediately (so the drag feels live) and calls back so you can
187
193
  persist it — same pattern as a task drag and `onDateChange`.
188
194
 
195
+ ## Grid column sorting
196
+
197
+ Mark a column `sortable: true` and clicking its header cycles ascending →
198
+ descending → none, with a `▲`/`▼` indicator:
199
+
200
+ ```ts
201
+ new GanttChart(container, tasks, deps, {
202
+ columns: [
203
+ { id: "name", title: "Task", sortable: true },
204
+ { id: "assignee", title: "Assignee", accessor: (t) => t.assignees?.[0]?.name, sortable: true },
205
+ ],
206
+ onSortChange: (sort) => console.log(sort), // { columnId, direction } | null
207
+ });
208
+
209
+ chart.setSort("assignee", "desc"); // or null to clear
210
+ chart.getSort(); // { columnId: "assignee", direction: "desc" } | null
211
+ ```
212
+
213
+ Sorting reorders **siblings at every tree level** by the column's value (via
214
+ `accessor`, or `task.name` for the conventional unaccessored "name" column)
215
+ — the group/parent hierarchy itself is never reshuffled, only the order
216
+ within it. A column with neither `accessor` nor the id `"name"` has nothing
217
+ sortable to read and is a no-op if marked sortable.
218
+
189
219
  ## Task search/filter
190
220
 
191
221
  ```ts
@@ -246,6 +276,39 @@ link fires `onDependencyDblClick` — the engine has no built-in "edit link"
246
276
  popover (keeping with zero-dependency, minimal-UI scope), so build your own
247
277
  and call `chart.updateDependency(...)` (undoable) to apply the result.
248
278
 
279
+ Double-clicking a task bar itself (not a link) fires the separate
280
+ `onTaskDblClick(task)` — also off by default until you supply a handler.
281
+
282
+ ## Filling the viewport at any zoom level
283
+
284
+ A short project at month/year zoom, or a chart with just a handful of
285
+ tasks, naturally renders narrow — the timeline's pixel width is purely a
286
+ function of the task date range and the current zoom, with no awareness of
287
+ how much horizontal space is actually available. Set
288
+ `autoFitToViewport: true` to stretch (never shrink) the timeline so it
289
+ fills the container instead of leaving empty space to the right:
290
+
291
+ ```ts
292
+ new GanttChart(container, tasks, deps, { autoFitToViewport: true });
293
+ ```
294
+
295
+ Re-evaluated on view-mode/task changes and on container resize (via
296
+ `ResizeObserver`). It never applies if the content is already wider than
297
+ the container — that's what normal horizontal scrolling is for. Off by
298
+ default, so upgrading doesn't silently change an existing chart's pixel
299
+ layout for anyone who hasn't opted in.
300
+
301
+ Separately, and always on: a short project at a coarse zoom no longer
302
+ renders as one or two lonely ticks. The visible date range is padded out to
303
+ a sensible minimum column count per zoom level (year: 5, quarter: 4,
304
+ month/week: 6, day: 7, hour: 8), so a 3-month project at year zoom still
305
+ shows a real multi-year timeline instead of a cramped sliver. Wider ranges
306
+ are unaffected — this only ever pads, never trims.
307
+
308
+ The timeline's date header also stays pinned to the top of the chart while
309
+ you scroll a tall task list vertically (it still scrolls horizontally in
310
+ sync with the bars), instead of scrolling out of view along with the rows.
311
+
249
312
  ## Multi-select and bulk actions
250
313
 
251
314
  ```ts
@@ -277,10 +340,39 @@ Dragging the whole task shifts every segment together; resizing an edge
277
340
  only adjusts the first (left) or last (right) segment's outer edge, leaving
278
341
  any gap untouched.
279
342
 
343
+ ## Hover tooltips
344
+
345
+ Every bar shows a floating, CSS-customizable tooltip on hover (name, dates,
346
+ progress, assignees, and `task.notes` if set) — not the browser's native
347
+ `title` tooltip, so it's fully styleable:
348
+
349
+ ```css
350
+ .gantt-tooltip { background: #111827; border-radius: 8px; }
351
+ .gantt-tooltip-title { font-weight: 700; }
352
+ ```
353
+
354
+ For full control over markup, `renderTooltip` works exactly like
355
+ `GanttColumn.render` — return an `HTMLElement` to mount directly, a string
356
+ (rendered as text, never parsed as HTML), or `null`/`undefined` to suppress
357
+ the tooltip for that specific task:
358
+
359
+ ```ts
360
+ new GanttChart(el, tasks, deps, {
361
+ renderTooltip: (task) => {
362
+ if (task.isMilestone) return null; // no tooltip on milestones
363
+ const div = document.createElement("div");
364
+ div.textContent = `${task.name} — ${task.progress ?? 0}%`;
365
+ return div;
366
+ },
367
+ });
368
+ ```
369
+
370
+ Set `showTooltip: false` to disable it entirely.
371
+
280
372
  ## Task notes, auto-color, baseline history, and density presets
281
373
 
282
374
  ```ts
283
- { id: "t1", name: "Ship v2", start, end, notes: "Blocked on legal review" } // hover the bar for a native tooltip
375
+ { id: "t1", name: "Ship v2", start, end, notes: "Blocked on legal review" } // shown as an extra line in the default tooltip
284
376
  ```
285
377
 
286
378
  ```ts
@@ -381,6 +473,56 @@ in addition to the JS `theme` option (`Partial<GanttTheme>`) — style via
381
473
  either, or both. `colorScheme: "auto"` (the default) follows
382
474
  `prefers-color-scheme` live.
383
475
 
476
+ To override a token via CSS, target `.gantt-root` itself (the element the
477
+ chart renders into) rather than an ancestor — the defaults are declared on
478
+ `.gantt-root`, and a same-element declaration always wins over one inherited
479
+ from a parent, regardless of specificity:
480
+
481
+ ```css
482
+ .gantt-root {
483
+ --gantt-bar-color: #16a34a;
484
+ --gantt-critical-color: #ea580c;
485
+ }
486
+ ```
487
+
488
+ ### Styling structural elements (buttons, cells, rows)
489
+
490
+ Beyond color tokens, every structural/interactive element the chart renders
491
+ has a stable, undocumented-nowhere-else class name and **no inline styles
492
+ and no `!important`** — so plain CSS targeting these classes has full
493
+ control, same as any element you'd render yourself:
494
+
495
+ | Class | What it is |
496
+ |---|---|
497
+ | `.gantt-toggle` | The expand/collapse button on a group row |
498
+ | `.gantt-grid-header-cell` | A column header cell |
499
+ | `.gantt-grid-cell` | A grid body cell |
500
+ | `.gantt-grid-row` | A grid body row (has a default `:hover` background) |
501
+ | `.gantt-rename-input` | The inline text input shown while renaming a task |
502
+ | `.gantt-tooltip` | The floating hover tooltip's container (see "Hover tooltips" above) |
503
+ | `.gantt-tooltip-title` / `.gantt-tooltip-row` / `.gantt-tooltip-notes` | Elements inside the *default* tooltip content — irrelevant if you use `renderTooltip` |
504
+
505
+ For example, to make the expand/collapse toggle look like a small round
506
+ button instead of bare text:
507
+
508
+ ```css
509
+ .gantt-toggle {
510
+ border-radius: 999px;
511
+ padding: 2px 6px;
512
+ background: var(--gantt-grid-color, #e5e7eb);
513
+ }
514
+ .gantt-toggle:hover {
515
+ background: var(--gantt-bar-color, #3b82f6);
516
+ color: #fff;
517
+ }
518
+ ```
519
+
520
+ None of this is specific to the library's own chrome, either — anything
521
+ *you* render, like the playground demo's toolbar (`apps/playground`,
522
+ `apps/vue-playground`), is plain HTML/CSS in your own app code with no
523
+ library involvement at all, so it's exactly as customizable as any other
524
+ element on your page.
525
+
384
526
  ## API surface
385
527
 
386
528
  The full, current type/function list is re-exported from