@dou-ui/gantt 0.0.0-stage → 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (119) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +10 -2
  3. package/dist/collaboration/index.js +323 -0
  4. package/dist/collaboration/index.js.map +1 -0
  5. package/dist/collaboration/peers.js +78 -0
  6. package/dist/collaboration/peers.js.map +1 -0
  7. package/dist/components/cell-editor.js +6 -0
  8. package/dist/components/cell-editor.js.map +1 -0
  9. package/dist/components/cell-editor.vue_vue_type_script_setup_true_lang.js +114 -0
  10. package/dist/components/cell-editor.vue_vue_type_script_setup_true_lang.js.map +1 -0
  11. package/dist/components/gantt-menu.js +6 -0
  12. package/dist/components/gantt-menu.js.map +1 -0
  13. package/dist/components/gantt-menu.vue_vue_type_script_setup_true_lang.js +40 -0
  14. package/dist/components/gantt-menu.vue_vue_type_script_setup_true_lang.js.map +1 -0
  15. package/dist/components/time-grid.js +6 -0
  16. package/dist/components/time-grid.js.map +1 -0
  17. package/dist/components/time-grid.vue_vue_type_script_setup_true_lang.js +32 -0
  18. package/dist/components/time-grid.vue_vue_type_script_setup_true_lang.js.map +1 -0
  19. package/dist/components/time-header.js +6 -0
  20. package/dist/components/time-header.js.map +1 -0
  21. package/dist/components/time-header.vue_vue_type_script_setup_true_lang.js +60 -0
  22. package/dist/components/time-header.vue_vue_type_script_setup_true_lang.js.map +1 -0
  23. package/dist/context.js +12 -0
  24. package/dist/context.js.map +1 -0
  25. package/dist/core/baseline.js +48 -0
  26. package/dist/core/baseline.js.map +1 -0
  27. package/dist/core/calendar.js +191 -0
  28. package/dist/core/calendar.js.map +1 -0
  29. package/dist/core/csv.js +424 -0
  30. package/dist/core/csv.js.map +1 -0
  31. package/dist/core/document.js +231 -0
  32. package/dist/core/document.js.map +1 -0
  33. package/dist/core/extension.js +42 -0
  34. package/dist/core/extension.js.map +1 -0
  35. package/dist/core/geometry.js +112 -0
  36. package/dist/core/geometry.js.map +1 -0
  37. package/dist/core/history.js +70 -0
  38. package/dist/core/history.js.map +1 -0
  39. package/dist/core/links.js +72 -0
  40. package/dist/core/links.js.map +1 -0
  41. package/dist/core/model.js +52 -0
  42. package/dist/core/model.js.map +1 -0
  43. package/dist/core/order.js +34 -0
  44. package/dist/core/order.js.map +1 -0
  45. package/dist/core/scale.js +118 -0
  46. package/dist/core/scale.js.map +1 -0
  47. package/dist/core/schedule.js +235 -0
  48. package/dist/core/schedule.js.map +1 -0
  49. package/dist/core/time.js +81 -0
  50. package/dist/core/time.js.map +1 -0
  51. package/dist/core/transaction.js +371 -0
  52. package/dist/core/transaction.js.map +1 -0
  53. package/dist/core/tree.js +114 -0
  54. package/dist/core/tree.js.map +1 -0
  55. package/dist/export/draw.js +214 -0
  56. package/dist/export/draw.js.map +1 -0
  57. package/dist/export/theme.js +131 -0
  58. package/dist/export/theme.js.map +1 -0
  59. package/dist/gantt.js +6 -0
  60. package/dist/gantt.js.map +1 -0
  61. package/dist/gantt.vue_vue_type_script_setup_true_lang.js +2774 -0
  62. package/dist/gantt.vue_vue_type_script_setup_true_lang.js.map +1 -0
  63. package/dist/index.js +20 -0
  64. package/dist/index.js.map +1 -0
  65. package/dist/labels.js +87 -0
  66. package/dist/labels.js.map +1 -0
  67. package/dist/locale.js +355 -0
  68. package/dist/locale.js.map +1 -0
  69. package/dist/scheduler/index.js +8 -0
  70. package/dist/scheduler/index.js.map +1 -0
  71. package/dist/scheduler/layout.js +97 -0
  72. package/dist/scheduler/layout.js.map +1 -0
  73. package/dist/scheduler/scheduler.js +6 -0
  74. package/dist/scheduler/scheduler.js.map +1 -0
  75. package/dist/scheduler/scheduler.vue_vue_type_script_setup_true_lang.js +1359 -0
  76. package/dist/scheduler/scheduler.vue_vue_type_script_setup_true_lang.js.map +1 -0
  77. package/dist/scheduler/style.d.ts +1 -0
  78. package/dist/scheduler/style.js +2 -0
  79. package/dist/style.css +1 -0
  80. package/dist/style.d.ts +1 -0
  81. package/dist/style.js +4 -0
  82. package/dist/time-axis.js +337 -0
  83. package/dist/time-axis.js.map +1 -0
  84. package/dist/types/collaboration/index.d.ts +39 -0
  85. package/dist/types/collaboration/peers.d.ts +22 -0
  86. package/dist/types/components/cell-editor.vue.d.ts +21 -0
  87. package/dist/types/components/gantt-menu.vue.d.ts +18 -0
  88. package/dist/types/components/time-grid.vue.d.ts +12 -0
  89. package/dist/types/components/time-header.vue.d.ts +23 -0
  90. package/dist/types/context.d.ts +64 -0
  91. package/dist/types/core/baseline.d.ts +14 -0
  92. package/dist/types/core/calendar.d.ts +75 -0
  93. package/dist/types/core/csv.d.ts +77 -0
  94. package/dist/types/core/document.d.ts +51 -0
  95. package/dist/types/core/extension.d.ts +88 -0
  96. package/dist/types/core/geometry.d.ts +33 -0
  97. package/dist/types/core/history.d.ts +19 -0
  98. package/dist/types/core/links.d.ts +20 -0
  99. package/dist/types/core/menu.d.ts +27 -0
  100. package/dist/types/core/model.d.ts +72 -0
  101. package/dist/types/core/order.d.ts +9 -0
  102. package/dist/types/core/scale.d.ts +33 -0
  103. package/dist/types/core/schedule.d.ts +44 -0
  104. package/dist/types/core/time.d.ts +39 -0
  105. package/dist/types/core/transaction.d.ts +134 -0
  106. package/dist/types/core/tree.d.ts +30 -0
  107. package/dist/types/export/draw.d.ts +76 -0
  108. package/dist/types/export/theme.d.ts +49 -0
  109. package/dist/types/gantt.vue.d.ts +54 -0
  110. package/dist/types/index.d.ts +148 -0
  111. package/dist/types/labels.d.ts +24 -0
  112. package/dist/types/locale.d.ts +161 -0
  113. package/dist/types/scheduler/index.d.ts +102 -0
  114. package/dist/types/scheduler/layout.d.ts +58 -0
  115. package/dist/types/scheduler/scheduler.vue.d.ts +46 -0
  116. package/dist/types/scheduler/types.d.ts +109 -0
  117. package/dist/types/time-axis.d.ts +80 -0
  118. package/dist/types/types.d.ts +305 -0
  119. package/package.json +79 -4
@@ -0,0 +1,214 @@
1
+ import { dayIndex } from "../core/time.js";
2
+ import { offTime } from "../core/calendar.js";
3
+ import { arrowPath, roundedPath, routeLink } from "../core/geometry.js";
4
+ import { hourStep, levelOf, nextUnit, unitStart, unitsBetween } from "../core/scale.js";
5
+ import { markerRoom, unitLabel } from "../labels.js";
6
+ var TIER = 28;
7
+ var BAR = 20;
8
+ var MILESTONE = 7;
9
+ /** How far bars move up when a baseline is drawn under them, in px. */
10
+ var BASELINE_SHIFT = 4;
11
+ var escape = (text) => text.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;");
12
+ var round = (value) => Math.round(value * 100) / 100;
13
+ /** Cuts a text to fit `max` px, with an ellipsis. */
14
+ function fit(text, max, measure) {
15
+ if (max <= 0) return "";
16
+ if (measure(text) <= max) return text;
17
+ let lo = 0;
18
+ let hi = text.length;
19
+ while (lo < hi) {
20
+ const mid = lo + hi + 1 >> 1;
21
+ if (measure(`${text.slice(0, mid)}…`) <= max) lo = mid;
22
+ else hi = mid - 1;
23
+ }
24
+ return lo ? `${text.slice(0, lo)}…` : "";
25
+ }
26
+ /** The time the content covers, widened to whole header cells with one more on either side. */
27
+ function paddedRange(start, end, dayWidth, weekStart) {
28
+ const level = levelOf(dayWidth);
29
+ const step = level.bottom === "hour" ? hourStep(dayWidth) : 1;
30
+ const first = unitStart(level.bottom, start, weekStart, step);
31
+ const before = unitStart(level.bottom, first - 1, weekStart, step);
32
+ let after = unitStart(level.bottom, end, weekStart, step);
33
+ if (after < end) after = nextUnit(level.bottom, after, step);
34
+ return {
35
+ start: before,
36
+ end: nextUnit(level.bottom, after, step)
37
+ };
38
+ }
39
+ function drawGantt(input, theme) {
40
+ const { rowHeight: rh, start, end, messages: m } = input;
41
+ const ppm = input.dayWidth / 1440;
42
+ const tableWidth = input.columns.reduce((sum, column) => sum + column.width, 0);
43
+ const chartWidth = Math.ceil((end - start) * ppm);
44
+ const width = tableWidth + chartWidth;
45
+ const bodyHeight = input.rows.length * rh;
46
+ const xOf = (at) => round(tableWidth + (at - start) * ppm);
47
+ const shift = input.baseline ? BASELINE_SHIFT : 0;
48
+ const level = levelOf(input.dayWidth);
49
+ const step = level.bottom === "hour" ? hourStep(input.dayWidth) : 1;
50
+ const font = (size = theme.fontSize, bold = false) => `font-size="${size}"${bold ? ` font-weight="${theme.fontWeight}"` : ""}`;
51
+ const measure = (bold) => (text) => input.textWidth(text, bold);
52
+ const text = (x, y, value, attrs) => value ? `<text x="${round(x)}" y="${round(y)}" dominant-baseline="central" ${attrs}>${escape(value)}</text>` : "";
53
+ const header = input.background ? [`<rect width="${width}" height="56" fill="${theme.headerBg}"/>`] : [];
54
+ input.columns.reduce((left, column) => {
55
+ const label = fit(column.title, column.width - 24, measure(false));
56
+ const x = column.align === "center" ? left + column.width / 2 : column.align === "end" ? left + column.width - 12 : left + 12;
57
+ const anchor = column.align === "center" ? "middle" : column.align === "end" ? "end" : "start";
58
+ header.push(text(x, 28, label, `${font()} fill="${theme.textSecondary}" text-anchor="${anchor}"`));
59
+ return left + column.width;
60
+ }, 0);
61
+ const top = unitsBetween(level.top, start, end, input.weekStart);
62
+ for (const cell of top) {
63
+ const left = Math.max(xOf(cell.start), tableWidth);
64
+ const right = Math.min(xOf(cell.end), width);
65
+ if (cell.start > start) header.push(`<rect x="${xOf(cell.start)}" y="0" width="1" height="${TIER}" fill="${theme.line}"/>`);
66
+ const label = fit(unitLabel(level.top, cell.start, m, input.dayWidth), right - left - 16, measure(true));
67
+ header.push(text(left + 8, TIER / 2, label, `${font(theme.fontSize, true)} fill="${theme.text}"`));
68
+ }
69
+ header.push(`<rect x="${tableWidth}" y="27" width="${chartWidth}" height="1" fill="${theme.line}"/>`);
70
+ const bottom = unitsBetween(level.bottom, start, end, input.weekStart, step);
71
+ for (const cell of bottom) {
72
+ const left = xOf(cell.start);
73
+ const cellWidth = (cell.end - cell.start) * ppm;
74
+ if (cell.start > start) header.push(`<rect x="${left}" y="${TIER}" width="1" height="28" fill="${theme.line}"/>`);
75
+ const isNow = input.now != null && input.now >= cell.start && input.now < cell.end;
76
+ const off = level.bottom === "day" && !input.calendar.isWorkday(dayIndex(cell.start));
77
+ const color = isNow ? theme.today : off ? theme.textTertiary : theme.textSecondary;
78
+ const label = fit(unitLabel(level.bottom, cell.start, m, input.dayWidth), cellWidth - 8, measure(isNow));
79
+ header.push(text(left + cellWidth / 2, 42, label, `${font(theme.fontSize, isNow)} fill="${color}" text-anchor="middle"`));
80
+ }
81
+ const shownMarkers = input.markers.filter((marker) => marker.label && marker.at >= start && marker.at <= end);
82
+ const markerRooms = markerRoom(shownMarkers.map((marker) => xOf(marker.at)));
83
+ for (const [i, marker] of shownMarkers.entries()) {
84
+ const room = markerRooms[i];
85
+ if (!room) continue;
86
+ const tone = theme.marker[marker.tone ?? "neutral"];
87
+ const label = fit(marker.label, room - 14, measure(false));
88
+ if (!label) continue;
89
+ const w = Math.ceil(input.textWidth(label)) + 12;
90
+ const x = xOf(marker.at);
91
+ header.push(`<rect x="${x + .5}" y="5.5" width="${w}" height="17" rx="4" fill="${theme.headerBg}" stroke="${tone.line}" stroke-opacity="0.4"/>`, text(x + 6.5, 14, label, `font-size="12" fill="${tone.text}"`));
92
+ }
93
+ if (tableWidth) header.push(`<rect x="${tableWidth - 1}" y="0" width="1" height="56" fill="${theme.lineStrong}"/>`);
94
+ header.push(`<rect x="0" y="55" width="${width}" height="1" fill="${theme.lineStrong}"/>`);
95
+ const body = input.background ? [`<rect width="${width}" height="${bodyHeight}" fill="${theme.surface}"/>`] : [];
96
+ if (input.dayWidth >= 8) for (const range of offTime(input.calendar, start, end, level.name === "hour")) body.push(`<rect x="${xOf(range.start)}" y="0" width="${round((range.end - range.start) * ppm)}" height="${bodyHeight}" fill="${theme.off}"/>`);
97
+ for (const cell of bottom) if (cell.start > start) body.push(`<rect x="${xOf(cell.start)}" y="0" width="1" height="${bodyHeight}" fill="${theme.line}"/>`);
98
+ input.rows.forEach((_, i) => body.push(`<rect x="0" y="${(i + 1) * rh - 1}" width="${width}" height="1" fill="${theme.line}"/>`));
99
+ if (tableWidth) body.push(`<rect x="${tableWidth - 1}" y="0" width="1" height="${bodyHeight}" fill="${theme.lineStrong}"/>`);
100
+ input.rows.forEach((row, i) => {
101
+ let left = 0;
102
+ for (const column of input.columns) {
103
+ const indent = column.isTitle ? row.depth * 16 : 0;
104
+ const bold = column.isTitle && row.summary;
105
+ const room = column.width - 24 - indent;
106
+ const value = fit(column.text(row), room, measure(bold));
107
+ const x = column.align === "center" ? left + column.width / 2 : column.align === "end" ? left + column.width - 12 : left + 12 + indent;
108
+ const anchor = column.align === "center" ? "middle" : column.align === "end" ? "end" : "start";
109
+ const color = column.isTitle ? theme.text : theme.textSecondary;
110
+ body.push(text(x, i * rh + rh / 2, value, `${font(theme.fontSize, bold)} fill="${color}" text-anchor="${anchor}"`));
111
+ left += column.width;
112
+ }
113
+ });
114
+ const now = input.now;
115
+ if (now != null && now >= start && now <= end) body.push(`<rect x="${xOf(now)}" y="0" width="1" height="${bodyHeight}" fill="${theme.today}"/>`);
116
+ for (const marker of input.markers) if (marker.at >= start && marker.at <= end) body.push(`<line x1="${xOf(marker.at) + .5}" y1="0" x2="${xOf(marker.at) + .5}" y2="${bodyHeight}" stroke="${theme.marker[marker.tone ?? "neutral"].line}" stroke-dasharray="4 4"/>`);
117
+ if (input.baseline) input.rows.forEach((row, i) => {
118
+ const plan = input.baseline.get(row.task.id);
119
+ if (!plan) return;
120
+ const y = i * rh + (rh + BAR) / 2 - 2;
121
+ if (row.milestone) {
122
+ const cx = xOf(plan.start);
123
+ body.push(`<rect x="${cx - 4}" y="${y - 2}" width="8" height="8" rx="1" fill="${theme.baseline}" transform="rotate(45 ${cx} ${y + 2})"/>`);
124
+ } else body.push(`<rect x="${xOf(plan.start)}" y="${y}" width="${round(Math.max(2, (plan.end - plan.start) * ppm))}" height="4" rx="2" fill="${theme.baseline}"/>`);
125
+ });
126
+ const index = new Map(input.rows.map((row, i) => [row.task.id, i]));
127
+ const boxOf = (row, i) => {
128
+ if (!row.span) return null;
129
+ const y = i * rh + rh / 2 - shift;
130
+ const left = xOf(row.span.start);
131
+ if (row.milestone) return {
132
+ left: left - MILESTONE,
133
+ right: left + MILESTONE,
134
+ y
135
+ };
136
+ return {
137
+ left,
138
+ right: left + Math.max(2, (row.span.end - row.span.start) * ppm),
139
+ y
140
+ };
141
+ };
142
+ for (const link of input.links) {
143
+ const a = index.get(link.from);
144
+ const b = index.get(link.to);
145
+ if (a == null || b == null || a === b) continue;
146
+ const boxA = boxOf(input.rows[a], a);
147
+ const boxB = boxOf(input.rows[b], b);
148
+ if (!boxA || !boxB) continue;
149
+ const route = routeLink(boxA, boxB, link.type, rh);
150
+ const broken = input.broken.has(link.id);
151
+ const color = broken ? theme.linkBroken : input.critical?.links.has(link.id) ? theme.linkCritical : theme.link;
152
+ body.push(`<path d="${roundedPath(route.points)}" fill="none" stroke="${color}"${broken ? " stroke-dasharray=\"4 3\"" : ""}/>`, `<path d="${arrowPath(route.tip, route.direction)}" fill="${color}"/>`);
153
+ }
154
+ let clips = 0;
155
+ input.rows.forEach((row, i) => {
156
+ const span = row.span;
157
+ if (!span || span.end < start || span.start > end) return;
158
+ const tone = input.critical?.tasks.has(row.task.id) ? "critical" : row.task.tone ?? "default";
159
+ const left = xOf(span.start);
160
+ const w = Math.max(row.milestone ? 0 : 2, (span.end - span.start) * ppm);
161
+ const mid = i * rh + rh / 2 - shift;
162
+ const side = (x) => {
163
+ if (input.barLabel === "none") return;
164
+ const room = input.linkedEnds.has(row.task.id) ? 14 : 0;
165
+ body.push(text(x + room, mid, row.task.title, `${font()} fill="${theme.textSecondary}"`));
166
+ };
167
+ if (row.milestone) {
168
+ const colors = theme.milestone[tone];
169
+ body.push(`<rect x="${left - 5 + .5}" y="${mid - 5 + .5}" width="9" height="9" rx="2" fill="${colors.fill}" stroke="${colors.stroke}" transform="rotate(45 ${left} ${mid})"/>`);
170
+ side(left + 12);
171
+ return;
172
+ }
173
+ if (row.summary) {
174
+ const color = theme.summary[tone];
175
+ const y = mid - 6;
176
+ body.push(`<path d="M${left} ${y + 2} Q${left} ${y} ${left + 2} ${y} L${left + w - 2} ${y} Q${left + w} ${y} ${left + w} ${y + 2} L${left + w} ${y + 11} L${left + w - 6} ${y + 6} L${left + 6} ${y + 6} L${left} ${y + 11} Z" fill="${color}"/>`);
177
+ side(left + w + 8);
178
+ return;
179
+ }
180
+ const colors = theme.bar[tone];
181
+ const y = mid - BAR / 2;
182
+ const id = `dou-gantt-bar-${clips++}`;
183
+ body.push(`<clipPath id="${id}"><rect x="${left}" y="${y}" width="${round(w)}" height="${BAR}" rx="6"/></clipPath>`);
184
+ body.push(`<rect x="${left + .5}" y="${y + .5}" width="${round(Math.max(1, w - 1))}" height="19" rx="5.5" fill="${colors.fill}" stroke="${colors.stroke}"/>`);
185
+ if (row.progress > 0) body.push(`<rect x="${left}" y="${y}" width="${round(w * row.progress)}" height="${BAR}" fill="${colors.progress}" clip-path="url(#${id})"/>`);
186
+ const label = row.task.title;
187
+ if (input.barLabel === "inside" || input.barLabel === "auto" && input.textWidth(label) + 20 <= w) {
188
+ const x = Math.max(left, tableWidth) + 8;
189
+ const shown = fit(label, left + w - x - 8, measure(false));
190
+ body.push(text(x, mid, shown, `${font()} fill="${theme.text}"`));
191
+ } else if (input.barLabel !== "none") side(left + w + 8);
192
+ });
193
+ const fontAttrs = `font-family="${escape(theme.fontFamily)}"`;
194
+ return {
195
+ width,
196
+ bodyHeight,
197
+ header: `<g ${fontAttrs}>${header.join("")}</g>`,
198
+ body: `<g ${fontAttrs}>${body.join("")}</g>`
199
+ };
200
+ }
201
+ /**
202
+ * A whole SVG document: the header, then the rows; `window` keeps only
203
+ * some of the rows, for a printed page.
204
+ */
205
+ function svgDocument(drawing, window) {
206
+ const top = window?.top ?? 0;
207
+ const height = window?.height ?? drawing.bodyHeight;
208
+ const total = 56 + height;
209
+ const clip = window ? `<clipPath id="dou-gantt-page-${top}"><rect x="0" y="56" width="${drawing.width}" height="${height}"/></clipPath>` : "";
210
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="${drawing.width}" height="${total}" viewBox="0 0 ${drawing.width} ${total}">` + clip + `<g${window ? ` clip-path="url(#dou-gantt-page-${top})"` : ""}><g transform="translate(0 ${56 - top})">${drawing.body}</g></g>` + drawing.header + `</svg>`;
211
+ }
212
+ export { drawGantt, paddedRange, svgDocument };
213
+
214
+ //# sourceMappingURL=draw.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"draw.js","names":[],"sources":["../../src/export/draw.ts"],"sourcesContent":["import type { Tone } from 'dou-ui'\nimport { offTime, type WorkCalendar } from '../core/calendar'\nimport { arrowPath, roundedPath, routeLink, type BarBox } from '../core/geometry'\nimport type { GanttLink, TaskSpan } from '../core/model'\nimport { hourStep, levelOf, nextUnit, unitStart, unitsBetween } from '../core/scale'\nimport { dayIndex } from '../core/time'\nimport type { GanttRow } from '../core/tree'\nimport { markerRoom, unitLabel } from '../labels'\nimport type { GanttMessages } from '../locale'\nimport type { GanttBarLabel } from '../types'\nimport type { BarTone, ExportTheme } from './theme'\n\n/** Height of the time header, in px, as on screen. */\nexport const HEADER = 56\nconst TIER = 28\nconst BAR = 20\nconst MILESTONE = 7\n/** How far bars move up when a baseline is drawn under them, in px. */\nconst BASELINE_SHIFT = 4\n/** More room before a side title where a link leaves the bar's end, in px. */\nexport const LINKED_END_ROOM = 14\n\nexport interface ExportColumn {\n title: string\n width: number\n align: 'start' | 'center' | 'end'\n /** The title column: indented by depth, summaries in medium weight. */\n isTitle: boolean\n text: (row: GanttRow) => string\n}\n\nexport interface DrawInput {\n /** The rows to draw, top to bottom. */\n rows: readonly GanttRow[]\n links: readonly GanttLink[]\n /** Columns of the table; none to leave the table out. */\n columns: readonly ExportColumn[]\n rowHeight: number\n dayWidth: number\n /** The time drawn, in minutes. */\n start: number\n end: number\n calendar: WorkCalendar\n messages: GanttMessages\n weekStart: 0 | 1\n /** The current time, or `null` to leave the today line out. */\n now: number | null\n markers: readonly { at: number; label?: string; tone?: Tone }[]\n critical: { tasks: ReadonlySet<string>; links: ReadonlySet<string> } | null\n broken: ReadonlySet<string>\n baseline: ReadonlyMap<string, TaskSpan> | null\n barLabel: GanttBarLabel\n /** Fill the header and the rows with the page colors; `false` leaves them transparent. */\n background: boolean\n /** Tasks with a link at their end, whose side titles start further out. */\n linkedEnds: ReadonlySet<string>\n /** Width of a text in px, at the given weight. */\n textWidth: (text: string, bold?: boolean) => number\n}\n\n/** The chart drawn as SVG markup, in two parts so the header can repeat on every printed page. */\nexport interface GanttDrawing {\n width: number\n /** Height of the rows, below the header. */\n bodyHeight: number\n header: string\n body: string\n}\n\nconst escape = (text: string) =>\n text.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;').replace(/\"/g, '&quot;')\n\nconst round = (value: number) => Math.round(value * 100) / 100\n\n/** Cuts a text to fit `max` px, with an ellipsis. */\nfunction fit(text: string, max: number, measure: (text: string) => number) {\n if (max <= 0) return ''\n if (measure(text) <= max) return text\n let lo = 0\n let hi = text.length\n while (lo < hi) {\n const mid = (lo + hi + 1) >> 1\n if (measure(`${text.slice(0, mid)}…`) <= max) lo = mid\n else hi = mid - 1\n }\n return lo ? `${text.slice(0, lo)}…` : ''\n}\n\n/** The time the content covers, widened to whole header cells with one more on either side. */\nexport function paddedRange(start: number, end: number, dayWidth: number, weekStart: 0 | 1) {\n const level = levelOf(dayWidth)\n const step = level.bottom === 'hour' ? hourStep(dayWidth) : 1\n const first = unitStart(level.bottom, start, weekStart, step)\n const before = unitStart(level.bottom, first - 1, weekStart, step)\n let after = unitStart(level.bottom, end, weekStart, step)\n if (after < end) after = nextUnit(level.bottom, after, step)\n return { start: before, end: nextUnit(level.bottom, after, step) }\n}\n\nexport function drawGantt(input: DrawInput, theme: ExportTheme): GanttDrawing {\n const { rowHeight: rh, start, end, messages: m } = input\n const ppm = input.dayWidth / (24 * 60)\n const tableWidth = input.columns.reduce((sum, column) => sum + column.width, 0)\n const chartWidth = Math.ceil((end - start) * ppm)\n const width = tableWidth + chartWidth\n const bodyHeight = input.rows.length * rh\n const xOf = (at: number) => round(tableWidth + (at - start) * ppm)\n const shift = input.baseline ? BASELINE_SHIFT : 0\n const level = levelOf(input.dayWidth)\n const step = level.bottom === 'hour' ? hourStep(input.dayWidth) : 1\n const font = (size = theme.fontSize, bold = false) =>\n `font-size=\"${size}\"${bold ? ` font-weight=\"${theme.fontWeight}\"` : ''}`\n const measure = (bold: boolean) => (text: string) => input.textWidth(text, bold)\n const text = (x: number, y: number, value: string, attrs: string) =>\n value\n ? `<text x=\"${round(x)}\" y=\"${round(y)}\" dominant-baseline=\"central\" ${attrs}>${escape(value)}</text>`\n : ''\n\n // Header -----------------------------------------------------------------------------\n const header: string[] = input.background\n ? [`<rect width=\"${width}\" height=\"${HEADER}\" fill=\"${theme.headerBg}\"/>`]\n : []\n input.columns.reduce((left, column) => {\n const label = fit(column.title, column.width - 24, measure(false))\n const x =\n column.align === 'center'\n ? left + column.width / 2\n : column.align === 'end'\n ? left + column.width - 12\n : left + 12\n const anchor = column.align === 'center' ? 'middle' : column.align === 'end' ? 'end' : 'start'\n header.push(\n text(x, HEADER / 2, label, `${font()} fill=\"${theme.textSecondary}\" text-anchor=\"${anchor}\"`),\n )\n return left + column.width\n }, 0)\n const top = unitsBetween(level.top, start, end, input.weekStart)\n for (const cell of top) {\n const left = Math.max(xOf(cell.start), tableWidth)\n const right = Math.min(xOf(cell.end), width)\n if (cell.start > start)\n header.push(\n `<rect x=\"${xOf(cell.start)}\" y=\"0\" width=\"1\" height=\"${TIER}\" fill=\"${theme.line}\"/>`,\n )\n // labels stay in view, as they stick on screen\n const label = fit(\n unitLabel(level.top, cell.start, m, input.dayWidth),\n right - left - 16,\n measure(true),\n )\n header.push(\n text(left + 8, TIER / 2, label, `${font(theme.fontSize, true)} fill=\"${theme.text}\"`),\n )\n }\n header.push(\n `<rect x=\"${tableWidth}\" y=\"${TIER - 1}\" width=\"${chartWidth}\" height=\"1\" fill=\"${theme.line}\"/>`,\n )\n const bottom = unitsBetween(level.bottom, start, end, input.weekStart, step)\n for (const cell of bottom) {\n const left = xOf(cell.start)\n const cellWidth = (cell.end - cell.start) * ppm\n if (cell.start > start)\n header.push(\n `<rect x=\"${left}\" y=\"${TIER}\" width=\"1\" height=\"${HEADER - TIER}\" fill=\"${theme.line}\"/>`,\n )\n const isNow = input.now != null && input.now >= cell.start && input.now < cell.end\n const off = level.bottom === 'day' && !input.calendar.isWorkday(dayIndex(cell.start))\n const color = isNow ? theme.today : off ? theme.textTertiary : theme.textSecondary\n const label = fit(\n unitLabel(level.bottom, cell.start, m, input.dayWidth),\n cellWidth - 8,\n measure(isNow),\n )\n header.push(\n text(\n left + cellWidth / 2,\n TIER + (HEADER - TIER) / 2,\n label,\n `${font(theme.fontSize, isNow)} fill=\"${color}\" text-anchor=\"middle\"`,\n ),\n )\n }\n const shownMarkers = input.markers.filter(\n (marker) => marker.label && marker.at >= start && marker.at <= end,\n )\n const markerRooms = markerRoom(shownMarkers.map((marker) => xOf(marker.at)))\n for (const [i, marker] of shownMarkers.entries()) {\n const room = markerRooms[i]!\n if (!room) continue\n const tone = theme.marker[marker.tone ?? 'neutral']\n // cut short before the next label, as on screen\n const label = fit(marker.label!, room - 14, measure(false))\n if (!label) continue\n const w = Math.ceil(input.textWidth(label)) + 12\n const x = xOf(marker.at)\n header.push(\n `<rect x=\"${x + 0.5}\" y=\"5.5\" width=\"${w}\" height=\"17\" rx=\"4\" fill=\"${theme.headerBg}\" stroke=\"${tone.line}\" stroke-opacity=\"0.4\"/>`,\n text(x + 6.5, 14, label, `font-size=\"12\" fill=\"${tone.text}\"`),\n )\n }\n if (tableWidth)\n header.push(\n `<rect x=\"${tableWidth - 1}\" y=\"0\" width=\"1\" height=\"${HEADER}\" fill=\"${theme.lineStrong}\"/>`,\n )\n header.push(\n `<rect x=\"0\" y=\"${HEADER - 1}\" width=\"${width}\" height=\"1\" fill=\"${theme.lineStrong}\"/>`,\n )\n\n // Body -------------------------------------------------------------------------------\n const body: string[] = input.background\n ? [`<rect width=\"${width}\" height=\"${bodyHeight}\" fill=\"${theme.surface}\"/>`]\n : []\n if (input.dayWidth >= 8)\n for (const range of offTime(input.calendar, start, end, level.name === 'hour'))\n body.push(\n `<rect x=\"${xOf(range.start)}\" y=\"0\" width=\"${round((range.end - range.start) * ppm)}\" height=\"${bodyHeight}\" fill=\"${theme.off}\"/>`,\n )\n for (const cell of bottom)\n if (cell.start > start)\n body.push(\n `<rect x=\"${xOf(cell.start)}\" y=\"0\" width=\"1\" height=\"${bodyHeight}\" fill=\"${theme.line}\"/>`,\n )\n input.rows.forEach((_, i) =>\n body.push(\n `<rect x=\"0\" y=\"${(i + 1) * rh - 1}\" width=\"${width}\" height=\"1\" fill=\"${theme.line}\"/>`,\n ),\n )\n if (tableWidth)\n body.push(\n `<rect x=\"${tableWidth - 1}\" y=\"0\" width=\"1\" height=\"${bodyHeight}\" fill=\"${theme.lineStrong}\"/>`,\n )\n\n // the table's cells\n input.rows.forEach((row, i) => {\n let left = 0\n for (const column of input.columns) {\n const indent = column.isTitle ? row.depth * 16 : 0\n const bold = column.isTitle && row.summary\n const room = column.width - 24 - indent\n const value = fit(column.text(row), room, measure(bold))\n const x =\n column.align === 'center'\n ? left + column.width / 2\n : column.align === 'end'\n ? left + column.width - 12\n : left + 12 + indent\n const anchor = column.align === 'center' ? 'middle' : column.align === 'end' ? 'end' : 'start'\n const color = column.isTitle ? theme.text : theme.textSecondary\n body.push(\n text(\n x,\n i * rh + rh / 2,\n value,\n `${font(theme.fontSize, bold)} fill=\"${color}\" text-anchor=\"${anchor}\"`,\n ),\n )\n left += column.width\n }\n })\n\n const now = input.now\n if (now != null && now >= start && now <= end)\n body.push(\n `<rect x=\"${xOf(now)}\" y=\"0\" width=\"1\" height=\"${bodyHeight}\" fill=\"${theme.today}\"/>`,\n )\n for (const marker of input.markers)\n if (marker.at >= start && marker.at <= end)\n body.push(\n `<line x1=\"${xOf(marker.at) + 0.5}\" y1=\"0\" x2=\"${xOf(marker.at) + 0.5}\" y2=\"${bodyHeight}\" stroke=\"${theme.marker[marker.tone ?? 'neutral'].line}\" stroke-dasharray=\"4 4\"/>`,\n )\n\n // baselines\n if (input.baseline)\n input.rows.forEach((row, i) => {\n const plan = input.baseline!.get(row.task.id)\n if (!plan) return\n const y = i * rh + (rh + BAR) / 2 - 2\n if (row.milestone) {\n const cx = xOf(plan.start)\n body.push(\n `<rect x=\"${cx - 4}\" y=\"${y - 2}\" width=\"8\" height=\"8\" rx=\"1\" fill=\"${theme.baseline}\" transform=\"rotate(45 ${cx} ${y + 2})\"/>`,\n )\n } else\n body.push(\n `<rect x=\"${xOf(plan.start)}\" y=\"${y}\" width=\"${round(Math.max(2, (plan.end - plan.start) * ppm))}\" height=\"4\" rx=\"2\" fill=\"${theme.baseline}\"/>`,\n )\n })\n\n // links, under the bars\n const index = new Map(input.rows.map((row, i) => [row.task.id, i]))\n const boxOf = (row: GanttRow, i: number): BarBox | null => {\n if (!row.span) return null\n const y = i * rh + rh / 2 - shift\n const left = xOf(row.span.start)\n if (row.milestone) return { left: left - MILESTONE, right: left + MILESTONE, y }\n return { left, right: left + Math.max(2, (row.span.end - row.span.start) * ppm), y }\n }\n for (const link of input.links) {\n const a = index.get(link.from)\n const b = index.get(link.to)\n if (a == null || b == null || a === b) continue\n const boxA = boxOf(input.rows[a]!, a)\n const boxB = boxOf(input.rows[b]!, b)\n if (!boxA || !boxB) continue\n const route = routeLink(boxA, boxB, link.type, rh)\n const broken = input.broken.has(link.id)\n const color = broken\n ? theme.linkBroken\n : input.critical?.links.has(link.id)\n ? theme.linkCritical\n : theme.link\n body.push(\n `<path d=\"${roundedPath(route.points)}\" fill=\"none\" stroke=\"${color}\"${broken ? ' stroke-dasharray=\"4 3\"' : ''}/>`,\n `<path d=\"${arrowPath(route.tip, route.direction)}\" fill=\"${color}\"/>`,\n )\n }\n\n // bars\n let clips = 0\n input.rows.forEach((row, i) => {\n const span = row.span\n if (!span || span.end < start || span.start > end) return\n const critical = input.critical?.tasks.has(row.task.id)\n const tone: BarTone = critical ? 'critical' : (row.task.tone ?? 'default')\n const left = xOf(span.start)\n const w = Math.max(row.milestone ? 0 : 2, (span.end - span.start) * ppm)\n const mid = i * rh + rh / 2 - shift\n const side = (x: number) => {\n if (input.barLabel === 'none') return\n const room = input.linkedEnds.has(row.task.id) ? LINKED_END_ROOM : 0\n body.push(text(x + room, mid, row.task.title, `${font()} fill=\"${theme.textSecondary}\"`))\n }\n if (row.milestone) {\n const colors = theme.milestone[tone]\n body.push(\n `<rect x=\"${left - 5 + 0.5}\" y=\"${mid - 5 + 0.5}\" width=\"9\" height=\"9\" rx=\"2\" fill=\"${colors.fill}\" stroke=\"${colors.stroke}\" transform=\"rotate(45 ${left} ${mid})\"/>`,\n )\n side(left + 12)\n return\n }\n if (row.summary) {\n const color = theme.summary[tone]\n const y = mid - 6\n body.push(\n `<path d=\"M${left} ${y + 2} Q${left} ${y} ${left + 2} ${y} L${left + w - 2} ${y} Q${left + w} ${y} ${left + w} ${y + 2} L${left + w} ${y + 11} L${left + w - 6} ${y + 6} L${left + 6} ${y + 6} L${left} ${y + 11} Z\" fill=\"${color}\"/>`,\n )\n side(left + w + 8)\n return\n }\n const colors = theme.bar[tone]\n const y = mid - BAR / 2\n const id = `dou-gantt-bar-${clips++}`\n body.push(\n `<clipPath id=\"${id}\"><rect x=\"${left}\" y=\"${y}\" width=\"${round(w)}\" height=\"${BAR}\" rx=\"6\"/></clipPath>`,\n )\n body.push(\n `<rect x=\"${left + 0.5}\" y=\"${y + 0.5}\" width=\"${round(Math.max(1, w - 1))}\" height=\"${BAR - 1}\" rx=\"5.5\" fill=\"${colors.fill}\" stroke=\"${colors.stroke}\"/>`,\n )\n if (row.progress > 0)\n body.push(\n `<rect x=\"${left}\" y=\"${y}\" width=\"${round(w * row.progress)}\" height=\"${BAR}\" fill=\"${colors.progress}\" clip-path=\"url(#${id})\"/>`,\n )\n const label = row.task.title\n const inside =\n input.barLabel === 'inside' || (input.barLabel === 'auto' && input.textWidth(label) + 20 <= w)\n if (inside) {\n // a long bar's title starts where the drawing does, as it sticks on screen\n const x = Math.max(left, tableWidth) + 8\n const shown = fit(label, left + w - x - 8, measure(false))\n body.push(text(x, mid, shown, `${font()} fill=\"${theme.text}\"`))\n } else if (input.barLabel !== 'none') side(left + w + 8)\n })\n\n const fontAttrs = `font-family=\"${escape(theme.fontFamily)}\"`\n return {\n width,\n bodyHeight,\n header: `<g ${fontAttrs}>${header.join('')}</g>`,\n body: `<g ${fontAttrs}>${body.join('')}</g>`,\n }\n}\n\n/**\n * A whole SVG document: the header, then the rows; `window` keeps only\n * some of the rows, for a printed page.\n */\nexport function svgDocument(drawing: GanttDrawing, window?: { top: number; height: number }) {\n const top = window?.top ?? 0\n const height = window?.height ?? drawing.bodyHeight\n const total = HEADER + height\n const clip = window\n ? `<clipPath id=\"dou-gantt-page-${top}\"><rect x=\"0\" y=\"${HEADER}\" width=\"${drawing.width}\" height=\"${height}\"/></clipPath>`\n : ''\n return (\n `<svg xmlns=\"http://www.w3.org/2000/svg\" width=\"${drawing.width}\" height=\"${total}\" viewBox=\"0 0 ${drawing.width} ${total}\">` +\n clip +\n `<g${window ? ` clip-path=\"url(#dou-gantt-page-${top})\"` : ''}><g transform=\"translate(0 ${HEADER - top})\">${drawing.body}</g></g>` +\n drawing.header +\n `</svg>`\n )\n}\n"],"mappings":"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"}
@@ -0,0 +1,131 @@
1
+ // src/export/theme.ts
2
+ var TONES = [
3
+ "default",
4
+ "neutral",
5
+ "primary",
6
+ "success",
7
+ "warning",
8
+ "danger",
9
+ "critical"
10
+ ];
11
+ var MARKER_TONES = [
12
+ "neutral",
13
+ "primary",
14
+ "success",
15
+ "warning",
16
+ "danger"
17
+ ];
18
+ var style = (el) => getComputedStyle(el);
19
+ var normalizer;
20
+ var SRGB = /^(#|rgba?\()/;
21
+ /**
22
+ * A computed color as `#rrggbb` or `rgba(…)`, which every SVG reader
23
+ * understands. A canvas converts most colors as it parses them; colors
24
+ * it keeps in another space (`oklab(…)`, `color(…)`) are painted on a
25
+ * pixel and read back.
26
+ */
27
+ function plain(color) {
28
+ if (SRGB.test(color)) return color;
29
+ if (normalizer === void 0) try {
30
+ const sheet = document.createElement("canvas");
31
+ sheet.width = sheet.height = 1;
32
+ normalizer = sheet.getContext("2d", { willReadFrequently: true });
33
+ } catch {
34
+ normalizer = null;
35
+ }
36
+ if (!normalizer) return color;
37
+ normalizer.fillStyle = "#000";
38
+ normalizer.fillStyle = color;
39
+ const parsed = String(normalizer.fillStyle);
40
+ if (SRGB.test(parsed)) return parsed;
41
+ normalizer.clearRect(0, 0, 1, 1);
42
+ normalizer.fillRect(0, 0, 1, 1);
43
+ const [r, g, b, a] = normalizer.getImageData(0, 0, 1, 1).data;
44
+ if (a === 255) return `#${[
45
+ r,
46
+ g,
47
+ b
48
+ ].map((n) => n.toString(16).padStart(2, "0")).join("")}`;
49
+ return `rgba(${r}, ${g}, ${b}, ${Math.round(a / 255 * 1e3) / 1e3})`;
50
+ }
51
+ /**
52
+ * Reads the colors from elements made like the chart's own, inside `root`
53
+ * so its theme and tokens apply, and removes them after.
54
+ */
55
+ function readTheme(root) {
56
+ const box = document.createElement("div");
57
+ box.setAttribute("aria-hidden", "true");
58
+ box.style.cssText = "position:absolute;visibility:hidden;pointer-events:none;top:0;left:0";
59
+ root.append(box);
60
+ const make = (className, parent = box) => {
61
+ const el = document.createElement("div");
62
+ el.className = className;
63
+ parent.append(el);
64
+ return el;
65
+ };
66
+ /** A color written with the chart's variables, as computed. */
67
+ const resolve = (value) => {
68
+ const el = make("");
69
+ el.style.color = value;
70
+ return plain(style(el).color);
71
+ };
72
+ try {
73
+ const rootStyle = style(root);
74
+ const bar = {};
75
+ const summary = {};
76
+ const milestone = {};
77
+ for (const tone of TONES) {
78
+ const toneClass = tone === "default" ? "" : ` is-${tone}`;
79
+ const el = make(`dou-gantt__bar${toneClass}`);
80
+ const progress = make("dou-gantt__progress", el);
81
+ bar[tone] = {
82
+ fill: plain(style(el).backgroundColor),
83
+ stroke: plain(style(el).borderTopColor),
84
+ progress: plain(style(progress).backgroundColor)
85
+ };
86
+ summary[tone] = plain(style(make(`dou-gantt__bar is-summary${toneClass}`)).backgroundColor);
87
+ const diamond = style(make(`dou-gantt__bar is-milestone${toneClass}`));
88
+ milestone[tone] = {
89
+ fill: plain(diamond.backgroundColor),
90
+ stroke: plain(diamond.borderTopColor)
91
+ };
92
+ }
93
+ const marker = {};
94
+ for (const tone of MARKER_TONES) {
95
+ const el = style(make(`dou-gantt__marker-label is-${tone}`));
96
+ marker[tone] = {
97
+ line: resolve(el.getPropertyValue("--dou-gantt-marker")),
98
+ text: resolve(el.getPropertyValue("--dou-gantt-marker-text"))
99
+ };
100
+ }
101
+ const header = style(make("dou-gantt__header"));
102
+ const baseline = style(make("dou-gantt__baseline"));
103
+ return {
104
+ fontFamily: rootStyle.fontFamily,
105
+ fontSize: Number.parseFloat(header.fontSize) || 13,
106
+ fontWeight: rootStyle.getPropertyValue("--dou-font-weight-medium").trim() || "500",
107
+ surface: plain(rootStyle.backgroundColor),
108
+ headerBg: plain(header.backgroundColor),
109
+ line: resolve("var(--dou-gantt-line)"),
110
+ lineStrong: resolve("var(--dou-gantt-line-strong)"),
111
+ off: resolve("var(--dou-gantt-off)"),
112
+ text: resolve("var(--dou-color-text)"),
113
+ textSecondary: resolve("var(--dou-color-text-secondary)"),
114
+ textTertiary: resolve("var(--dou-color-text-tertiary)"),
115
+ today: resolve("var(--dou-gantt-today)"),
116
+ link: resolve("var(--dou-gantt-link)"),
117
+ linkCritical: plain(style(make("dou-gantt__link is-critical")).color),
118
+ linkBroken: plain(style(make("dou-gantt__link is-broken")).color),
119
+ baseline: plain(baseline.backgroundColor),
120
+ bar,
121
+ summary,
122
+ milestone,
123
+ marker
124
+ };
125
+ } finally {
126
+ box.remove();
127
+ }
128
+ }
129
+ export { plain, readTheme };
130
+
131
+ //# sourceMappingURL=theme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.js","names":[],"sources":["../../src/export/theme.ts"],"sourcesContent":["import type { Tone } from 'dou-ui'\n\nexport type BarTone = Tone | 'default' | 'critical'\n\nexport interface BarColors {\n fill: string\n stroke: string\n progress: string\n}\n\n/** The chart's colors and font, read from the page, for drawing it elsewhere. */\nexport interface ExportTheme {\n fontFamily: string\n /** Size of the header, bar and cell text, in px. */\n fontSize: number\n fontWeight: string\n surface: string\n headerBg: string\n line: string\n lineStrong: string\n off: string\n text: string\n textSecondary: string\n textTertiary: string\n today: string\n link: string\n linkCritical: string\n linkBroken: string\n baseline: string\n bar: Record<BarTone, BarColors>\n summary: Record<BarTone, string>\n milestone: Record<BarTone, { fill: string; stroke: string }>\n marker: Record<Tone, { line: string; text: string }>\n}\n\nconst TONES: BarTone[] = [\n 'default',\n 'neutral',\n 'primary',\n 'success',\n 'warning',\n 'danger',\n 'critical',\n]\nconst MARKER_TONES: Tone[] = ['neutral', 'primary', 'success', 'warning', 'danger']\n\nconst style = (el: Element) => getComputedStyle(el)\n\nlet normalizer: CanvasRenderingContext2D | null | undefined\n\nconst SRGB = /^(#|rgba?\\()/\n\n/**\n * A computed color as `#rrggbb` or `rgba(…)`, which every SVG reader\n * understands. A canvas converts most colors as it parses them; colors\n * it keeps in another space (`oklab(…)`, `color(…)`) are painted on a\n * pixel and read back.\n */\nexport function plain(color: string) {\n if (SRGB.test(color)) return color\n if (normalizer === undefined)\n try {\n const sheet = document.createElement('canvas')\n sheet.width = sheet.height = 1\n normalizer = sheet.getContext('2d', { willReadFrequently: true })\n } catch {\n normalizer = null\n }\n if (!normalizer) return color\n normalizer.fillStyle = '#000'\n normalizer.fillStyle = color\n const parsed = String(normalizer.fillStyle)\n if (SRGB.test(parsed)) return parsed\n normalizer.clearRect(0, 0, 1, 1)\n normalizer.fillRect(0, 0, 1, 1)\n const [r, g, b, a] = normalizer.getImageData(0, 0, 1, 1).data\n if (a === 255) return `#${[r, g, b].map((n) => n!.toString(16).padStart(2, '0')).join('')}`\n return `rgba(${r}, ${g}, ${b}, ${Math.round((a! / 255) * 1000) / 1000})`\n}\n\n/**\n * Reads the colors from elements made like the chart's own, inside `root`\n * so its theme and tokens apply, and removes them after.\n */\nexport function readTheme(root: HTMLElement): ExportTheme {\n const box = document.createElement('div')\n box.setAttribute('aria-hidden', 'true')\n box.style.cssText = 'position:absolute;visibility:hidden;pointer-events:none;top:0;left:0'\n root.append(box)\n const make = (className: string, parent: HTMLElement = box) => {\n const el = document.createElement('div')\n el.className = className\n parent.append(el)\n return el\n }\n /** A color written with the chart's variables, as computed. */\n const resolve = (value: string) => {\n const el = make('')\n el.style.color = value\n return plain(style(el).color)\n }\n try {\n const rootStyle = style(root)\n const bar = {} as Record<BarTone, BarColors>\n const summary = {} as Record<BarTone, string>\n const milestone = {} as Record<BarTone, { fill: string; stroke: string }>\n for (const tone of TONES) {\n const toneClass = tone === 'default' ? '' : ` is-${tone}`\n const el = make(`dou-gantt__bar${toneClass}`)\n const progress = make('dou-gantt__progress', el)\n bar[tone] = {\n fill: plain(style(el).backgroundColor),\n stroke: plain(style(el).borderTopColor),\n progress: plain(style(progress).backgroundColor),\n }\n summary[tone] = plain(style(make(`dou-gantt__bar is-summary${toneClass}`)).backgroundColor)\n const diamond = style(make(`dou-gantt__bar is-milestone${toneClass}`))\n milestone[tone] = {\n fill: plain(diamond.backgroundColor),\n stroke: plain(diamond.borderTopColor),\n }\n }\n const marker = {} as Record<Tone, { line: string; text: string }>\n for (const tone of MARKER_TONES) {\n const el = style(make(`dou-gantt__marker-label is-${tone}`))\n marker[tone] = {\n line: resolve(el.getPropertyValue('--dou-gantt-marker')),\n text: resolve(el.getPropertyValue('--dou-gantt-marker-text')),\n }\n }\n const header = style(make('dou-gantt__header'))\n const baseline = style(make('dou-gantt__baseline'))\n return {\n fontFamily: rootStyle.fontFamily,\n fontSize: Number.parseFloat(header.fontSize) || 13,\n fontWeight: rootStyle.getPropertyValue('--dou-font-weight-medium').trim() || '500',\n surface: plain(rootStyle.backgroundColor),\n headerBg: plain(header.backgroundColor),\n line: resolve('var(--dou-gantt-line)'),\n lineStrong: resolve('var(--dou-gantt-line-strong)'),\n off: resolve('var(--dou-gantt-off)'),\n text: resolve('var(--dou-color-text)'),\n textSecondary: resolve('var(--dou-color-text-secondary)'),\n textTertiary: resolve('var(--dou-color-text-tertiary)'),\n today: resolve('var(--dou-gantt-today)'),\n link: resolve('var(--dou-gantt-link)'),\n linkCritical: plain(style(make('dou-gantt__link is-critical')).color),\n linkBroken: plain(style(make('dou-gantt__link is-broken')).color),\n baseline: plain(baseline.backgroundColor),\n bar,\n summary,\n milestone,\n marker,\n }\n } finally {\n box.remove()\n }\n}\n"],"mappings":"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"}
package/dist/gantt.js ADDED
@@ -0,0 +1,6 @@
1
+ import gantt_vue_vue_type_script_setup_true_lang_default from "./gantt.vue_vue_type_script_setup_true_lang.js";
2
+ // src/gantt.vue
3
+ var gantt_default = gantt_vue_vue_type_script_setup_true_lang_default;
4
+ export { gantt_default as default };
5
+
6
+ //# sourceMappingURL=gantt.js.map