@operato/gantt 2.0.0-beta.14 → 2.0.0-beta.17

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 (42) hide show
  1. package/CHANGELOG.md +28 -0
  2. package/dist/src/gantt-chart-controller.d.ts +32 -0
  3. package/dist/src/gantt-chart-controller.js +393 -0
  4. package/dist/src/gantt-chart-controller.js.map +1 -0
  5. package/dist/src/locales.d.ts +52 -0
  6. package/dist/src/locales.js +79 -0
  7. package/dist/src/locales.js.map +1 -0
  8. package/dist/src/ox-gantt-chart.d.ts +10 -17
  9. package/dist/src/ox-gantt-chart.js +134 -440
  10. package/dist/src/ox-gantt-chart.js.map +1 -1
  11. package/dist/src/ox-gantt-resize-splitter.d.ts +2 -3
  12. package/dist/src/ox-gantt-resize-splitter.js +15 -22
  13. package/dist/src/ox-gantt-resize-splitter.js.map +1 -1
  14. package/dist/src/ox-gantt.d.ts +13 -1
  15. package/dist/src/ox-gantt.js +154 -27
  16. package/dist/src/ox-gantt.js.map +1 -1
  17. package/dist/src/ox-task-tooltip.d.ts +12 -0
  18. package/dist/src/ox-task-tooltip.js +132 -0
  19. package/dist/src/ox-task-tooltip.js.map +1 -0
  20. package/dist/src/types.d.ts +10 -3
  21. package/dist/src/types.js.map +1 -1
  22. package/dist/stories/ox-gantt.stories.js +91 -85
  23. package/dist/stories/ox-gantt.stories.js.map +1 -1
  24. package/dist/tsconfig.tsbuildinfo +1 -1
  25. package/package.json +3 -2
  26. package/src/gantt-chart-controller.ts +470 -0
  27. package/src/locales.ts +78 -0
  28. package/src/ox-gantt-chart.ts +141 -487
  29. package/src/ox-gantt-resize-splitter.ts +18 -25
  30. package/src/ox-gantt.ts +163 -29
  31. package/src/ox-task-tooltip.ts +120 -0
  32. package/src/types.ts +11 -3
  33. package/stories/ox-gantt.stories.ts +93 -85
  34. package/translations/en.json +11 -1
  35. package/translations/ja.json +11 -1
  36. package/translations/ko.json +11 -1
  37. package/translations/ms.json +11 -1
  38. package/translations/zh.json +11 -1
  39. package/dist/src/locale.d.ts +0 -1
  40. package/dist/src/locale.js +0 -49
  41. package/dist/src/locale.js.map +0 -1
  42. package/src/locale.ts +0 -51
@@ -1,6 +1,7 @@
1
1
  import { __decorate } from "tslib";
2
2
  import { LitElement, html, css } from 'lit';
3
- import { customElement, property, query } from 'lit/decorators.js';
3
+ import i18next from 'i18next';
4
+ import { customElement, property, query, state } from 'lit/decorators.js';
4
5
  import { styles as MDTypeScaleStyles } from '@material/web/typography/md-typescale-styles';
5
6
  import { ScrollbarStyles } from '@operato/styles';
6
7
  import './ox-gantt-chart.js';
@@ -12,7 +13,49 @@ let OxGantt = class OxGantt extends LitElement {
12
13
  this.fromDate = new Date(new Date().getFullYear(), 0, 1).toISOString().split('T')[0]; /* beginning of this year */
13
14
  this.toDate = new Date(new Date().getFullYear(), 11, 31).toISOString().split('T')[0]; /* end of this year */
14
15
  this.extendGridLines = false;
16
+ this.columnConfig = [
17
+ { name: 'id', label: i18next.t('label.gantt-task-id') || 'ID', visible: true, width: '50px', order: 1 },
18
+ {
19
+ name: 'section',
20
+ label: i18next.t('label.gantt-task-section') || 'section',
21
+ visible: true,
22
+ width: '100px',
23
+ order: 2
24
+ },
25
+ { name: 'title', label: i18next.t('label.gantt-task-title') || 'title', visible: true, width: '150px', order: 3 },
26
+ { name: 'type', label: i18next.t('label.gantt-task-type') || 'type', visible: true, width: '100px', order: 4 },
27
+ {
28
+ name: 'startDate',
29
+ label: i18next.t('label.gantt-task-start-date') || 'start date',
30
+ visible: true,
31
+ width: '100px',
32
+ order: 5
33
+ },
34
+ {
35
+ name: 'endDate',
36
+ label: i18next.t('label.gantt-task-end-date') || 'end date',
37
+ visible: true,
38
+ width: '100px',
39
+ order: 6
40
+ },
41
+ { name: 'tags', label: i18next.t('label.gantt-task-tags') || 'tags', visible: true, width: '100px', order: 7 },
42
+ {
43
+ name: 'progress',
44
+ label: i18next.t('label.gantt-task-progress') || 'progress',
45
+ visible: true,
46
+ width: '100px',
47
+ order: 8
48
+ },
49
+ {
50
+ name: 'dependsOn',
51
+ label: i18next.t('label.gantt-task-previous') || 'previous',
52
+ visible: true,
53
+ width: '100px',
54
+ order: 9
55
+ }
56
+ ];
15
57
  this._startWidth = 0;
58
+ this._isDragging = false;
16
59
  }
17
60
  static { this.styles = [
18
61
  MDTypeScaleStyles,
@@ -22,6 +65,7 @@ let OxGantt = class OxGantt extends LitElement {
22
65
  display: block;
23
66
  font-family: Arial, sans-serif;
24
67
  text-wrap: nowrap;
68
+ position: relative;
25
69
  }
26
70
 
27
71
  .container {
@@ -48,6 +92,7 @@ let OxGantt = class OxGantt extends LitElement {
48
92
 
49
93
  ox-gantt-resize-splitter {
50
94
  width: 4px;
95
+ cursor: ew-resize;
51
96
  }
52
97
 
53
98
  table {
@@ -63,6 +108,7 @@ let OxGantt = class OxGantt extends LitElement {
63
108
  top: -1px;
64
109
  z-index: 1;
65
110
  background-color: var(--ox-gantt-header-background-color, var(--md-sys-color-secondary-container));
111
+ text-transform: capitalize;
66
112
  }
67
113
 
68
114
  th,
@@ -81,6 +127,10 @@ let OxGantt = class OxGantt extends LitElement {
81
127
  height: 30px;
82
128
  box-sizing: border-box;
83
129
  }
130
+
131
+ tr.selected {
132
+ background-color: var(--ox-gantt-selected-background-color, var(--md-sys-color-surface-variant));
133
+ }
84
134
  `
85
135
  ]; }
86
136
  render() {
@@ -91,6 +141,7 @@ let OxGantt = class OxGantt extends LitElement {
91
141
  vertical
92
142
  @splitter-dragstart=${(e) => this.resizeStart(e)}
93
143
  @splitter-drag=${(e) => this.resizeDrag(e)}
144
+ @splitter-dragend=${(e) => this.resizeEnd(e)}
94
145
  ></ox-gantt-resize-splitter>
95
146
  <ox-gantt-chart
96
147
  class="chart-container"
@@ -98,63 +149,133 @@ let OxGantt = class OxGantt extends LitElement {
98
149
  .fromDate=${this.fromDate}
99
150
  .toDate=${this.toDate}
100
151
  .tasks=${this.tasks}
152
+ .selectedTaskId=${this.selectedTaskId}
101
153
  axis-scale="week-day"
102
154
  ?extend-grid-lines=${this.extendGridLines}
155
+ @task-clicked=${this.handleTaskClicked}
103
156
  ></ox-gantt-chart>
104
157
  </div>
105
158
  `;
106
159
  }
107
160
  renderTaskTable() {
161
+ const mergedTasks = this.mergeTasksBySection(this.tasks);
162
+ // Sort columns by the configured order
163
+ const sortedColumns = [...this.columnConfig].sort((a, b) => a.order - b.order);
108
164
  return html `
109
165
  <table>
110
166
  <thead>
111
167
  <tr>
112
- <th>ID</th>
113
- <th>Section</th>
114
- <th>Title</th>
115
- <th>Type</th>
116
- <th>Start Time</th>
117
- <th>End Time</th>
118
- <th>Tags</th>
119
- <th>Progress</th>
120
- <th>Prev. Task</th>
168
+ ${sortedColumns.map(col => (col.visible ? html `<th style="width: ${col.width}">${col.label}</th>` : null))}
121
169
  </tr>
122
170
  </thead>
123
171
  <tbody>
124
- ${this.tasks.map(task => html `
125
- <tr>
126
- <td>${task.id}</td>
127
- <td>${task.section?.name || ''}</td>
128
- <td>${task.title}</td>
129
- <td>${task.type}</td>
130
- <td>${task.startTime.toISOString().split('T')[0]}</td>
131
- <td>${task.endTime.toISOString().split('T')[0]}</td>
132
- <td>${task.tags?.join(', ') || ''}</td>
133
- <td>${task.progress || ''}</td>
134
- <td>${task.after || ''}</td>
172
+ ${mergedTasks.map(({ task, showSection, rowSpan }) => html `
173
+ <tr class="${this.selectedTaskId === task.id ? 'selected' : ''}" @click=${() => this.selectTask(task.id)}>
174
+ ${sortedColumns.map(col => {
175
+ if (col.name === 'section') {
176
+ return col.visible && showSection
177
+ ? html `<td rowspan="${rowSpan}" style="width: ${col.width}">${task.section?.name || ''}</td>`
178
+ : null;
179
+ }
180
+ return col.visible
181
+ ? html `<td style="width: ${col.width}">${this.getTaskFieldValue(task, col.name)}</td>`
182
+ : null;
183
+ })}
135
184
  </tr>
136
185
  `)}
137
186
  </tbody>
138
187
  </table>
139
188
  `;
140
189
  }
190
+ getTaskFieldValue(task, field) {
191
+ switch (field) {
192
+ case 'id':
193
+ return task.id;
194
+ case 'section':
195
+ return task.section?.name || '';
196
+ case 'title':
197
+ return task.title;
198
+ case 'type':
199
+ return task.type;
200
+ case 'startDate':
201
+ return task.startDate.toISOString().split('T')[0];
202
+ case 'endDate':
203
+ return task.endDate.toISOString().split('T')[0];
204
+ case 'tags':
205
+ return task.tags?.join(', ') || '';
206
+ case 'progress':
207
+ return task.progress || '';
208
+ case 'dependsOn':
209
+ return task.dependsOn || '';
210
+ default:
211
+ return '';
212
+ }
213
+ }
214
+ mergeTasksBySection(tasks) {
215
+ const mergedTasks = [];
216
+ let currentSection = '';
217
+ let rowSpan = 0;
218
+ tasks.forEach((task, index) => {
219
+ if (task.section?.name !== currentSection) {
220
+ currentSection = task.section?.name || '';
221
+ rowSpan = 1;
222
+ mergedTasks.push({ task, showSection: true, rowSpan: 1 });
223
+ }
224
+ else {
225
+ mergedTasks[mergedTasks.length - rowSpan].rowSpan = ++rowSpan;
226
+ mergedTasks.push({ task, showSection: false, rowSpan: 0 });
227
+ }
228
+ if (index === tasks.length - 1 && rowSpan > 0) {
229
+ mergedTasks[mergedTasks.length - rowSpan].rowSpan = rowSpan;
230
+ }
231
+ });
232
+ return mergedTasks;
233
+ }
234
+ selectTask(taskId) {
235
+ this.selectedTaskId = taskId;
236
+ }
237
+ handleTaskClicked(event) {
238
+ this.selectedTaskId = event.detail.taskId;
239
+ }
141
240
  firstUpdated(_changedProperties) {
142
241
  this.taskContainer.style.width = '254px';
143
242
  }
144
243
  updated(changes) { }
145
- syncScroll() {
146
- this.ganttChart.setVerticalOffset(this.taskContainer.scrollTop);
244
+ syncScroll(e) {
245
+ const target = e.target;
246
+ if (target === this.taskContainer) {
247
+ // Sync chart scroll with table scroll
248
+ const newScrollTop = this.taskContainer.scrollTop;
249
+ this.ganttChart.setVerticalOffset(newScrollTop);
250
+ // Ensure chart scroll matches table scroll
251
+ if (this.ganttChart.getVerticalOffset() !== newScrollTop) {
252
+ this.ganttChart.setVerticalOffset(newScrollTop);
253
+ }
254
+ }
255
+ else if (target === this.ganttChart) {
256
+ // Sync table scroll with chart scroll
257
+ const newScrollTop = this.ganttChart.getVerticalOffset();
258
+ this.taskContainer.scrollTop = newScrollTop;
259
+ // Ensure table scroll matches chart scroll
260
+ this.ganttChart.setVerticalOffset(this.taskContainer.scrollTop);
261
+ }
147
262
  }
148
263
  resizeStart(e) {
149
264
  this._startWidth = e.target?.previousElementSibling?.offsetWidth;
265
+ this._isDragging = true;
150
266
  }
151
267
  resizeDrag(e) {
152
- var delta = e.detail;
153
- var x = e.target?.previousElementSibling;
154
- if (x) {
155
- x.style.width = `${this._startWidth + delta.x}px`;
268
+ if (!this._isDragging)
269
+ return;
270
+ const delta = e.detail;
271
+ const taskContainer = this.taskContainer;
272
+ if (taskContainer) {
273
+ taskContainer.style.width = `${this._startWidth + delta.x}px`;
156
274
  }
157
275
  }
276
+ resizeEnd(e) {
277
+ this._isDragging = false;
278
+ }
158
279
  };
159
280
  __decorate([
160
281
  property({ type: Array })
@@ -168,6 +289,12 @@ __decorate([
168
289
  __decorate([
169
290
  property({ type: Boolean, attribute: 'extend-grid-lines' })
170
291
  ], OxGantt.prototype, "extendGridLines", void 0);
292
+ __decorate([
293
+ state()
294
+ ], OxGantt.prototype, "selectedTaskId", void 0);
295
+ __decorate([
296
+ state()
297
+ ], OxGantt.prototype, "columnConfig", void 0);
171
298
  __decorate([
172
299
  query('.container')
173
300
  ], OxGantt.prototype, "container", void 0);
@@ -1 +1 @@
1
- {"version":3,"file":"ox-gantt.js","sourceRoot":"","sources":["../../src/ox-gantt.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, html, css, PropertyValues, PropertyValueMap } from 'lit'\nimport { customElement, property, query } from 'lit/decorators.js'\nimport { styles as MDTypeScaleStyles } from '@material/web/typography/md-typescale-styles'\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport './ox-gantt-chart.js'\nimport './ox-gantt-resize-splitter.js'\nimport { OxGanttChart } from './ox-gantt-chart.js'\nimport { Task } from './types.js'\n\n@customElement('ox-gantt')\nexport class OxGantt extends LitElement {\n static styles = [\n MDTypeScaleStyles,\n ScrollbarStyles,\n css`\n :host {\n display: block;\n font-family: Arial, sans-serif;\n text-wrap: nowrap;\n }\n\n .container {\n display: flex;\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n }\n\n .task-container {\n padding: 0;\n overflow: auto;\n overflow-y: overlay;\n box-sizing: border-box;\n border: 1px solid var(--ox-gantt-border-color, var(--md-sys-color-on-surface));\n }\n\n .chart-container {\n flex: 1;\n padding: 0;\n box-sizing: border-box;\n border: 1px solid var(--ox-gantt-border-color, var(--md-sys-color-on-surface));\n }\n\n ox-gantt-resize-splitter {\n width: 4px;\n }\n\n table {\n width: 100%;\n border-collapse: collapse;\n border: 1px solid var(--ox-gantt-border-color, var(--md-sys-color-on-surface));\n margin: -1px;\n margin-right: 0;\n }\n\n thead th {\n position: sticky;\n top: -1px;\n z-index: 1;\n background-color: var(--ox-gantt-header-background-color, var(--md-sys-color-secondary-container));\n }\n\n th,\n td {\n border: 1px solid var(--ox-gantt-border-color, var(--md-sys-color-on-surface));\n padding: 4px;\n text-align: left;\n }\n\n th {\n height: 40px;\n box-sizing: border-box;\n }\n\n td {\n height: 30px;\n box-sizing: border-box;\n }\n `\n ]\n\n @property({ type: Array }) tasks: Task[] = []\n @property({ type: String, attribute: 'from-date' })\n fromDate: string = new Date(new Date().getFullYear(), 0, 1).toISOString().split('T')[0] /* beginning of this year */\n @property({ type: String, attribute: 'to-date' })\n toDate: string = new Date(new Date().getFullYear(), 11, 31).toISOString().split('T')[0] /* end of this year */\n @property({ type: Boolean, attribute: 'extend-grid-lines' }) extendGridLines: boolean = false\n\n @query('.container') container!: HTMLDivElement\n @query('.task-container') taskContainer!: HTMLDivElement\n @query('.chart-container') chartContainer!: HTMLDivElement\n @query('table') taskTable!: HTMLTableElement\n @query('ox-gantt-chart') ganttChart!: OxGanttChart\n\n private _startWidth: number = 0\n\n render() {\n return html`\n <div class=\"container md-typescale-body-medium\">\n <div class=\"task-container\" @scroll=${this.syncScroll}>${this.renderTaskTable()}</div>\n <ox-gantt-resize-splitter\n vertical\n @splitter-dragstart=${(e: CustomEvent) => this.resizeStart(e)}\n @splitter-drag=${(e: CustomEvent) => this.resizeDrag(e)}\n ></ox-gantt-resize-splitter>\n <ox-gantt-chart\n class=\"chart-container\"\n @scroll=${this.syncScroll}\n .fromDate=${this.fromDate}\n .toDate=${this.toDate}\n .tasks=${this.tasks}\n axis-scale=\"week-day\"\n ?extend-grid-lines=${this.extendGridLines}\n ></ox-gantt-chart>\n </div>\n `\n }\n\n renderTaskTable() {\n return html`\n <table>\n <thead>\n <tr>\n <th>ID</th>\n <th>Section</th>\n <th>Title</th>\n <th>Type</th>\n <th>Start Time</th>\n <th>End Time</th>\n <th>Tags</th>\n <th>Progress</th>\n <th>Prev. Task</th>\n </tr>\n </thead>\n <tbody>\n ${this.tasks.map(\n task => html`\n <tr>\n <td>${task.id}</td>\n <td>${task.section?.name || ''}</td>\n <td>${task.title}</td>\n <td>${task.type}</td>\n <td>${task.startTime.toISOString().split('T')[0]}</td>\n <td>${task.endTime.toISOString().split('T')[0]}</td>\n <td>${task.tags?.join(', ') || ''}</td>\n <td>${task.progress || ''}</td>\n <td>${task.after || ''}</td>\n </tr>\n `\n )}\n </tbody>\n </table>\n `\n }\n\n protected firstUpdated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void {\n this.taskContainer.style.width = '254px'\n }\n\n updated(changes: PropertyValues<this>) {}\n\n syncScroll() {\n this.ganttChart.setVerticalOffset(this.taskContainer.scrollTop)\n }\n\n resizeStart(e: CustomEvent) {\n this._startWidth = ((e.target as HTMLElement)?.previousElementSibling as HTMLElement)?.offsetWidth\n }\n\n resizeDrag(e: CustomEvent) {\n var delta = e.detail\n var x = (e.target as HTMLElement)?.previousElementSibling as HTMLElement\n if (x) {\n x.style.width = `${this._startWidth + delta.x}px`\n }\n }\n}\n"]}
1
+ {"version":3,"file":"ox-gantt.js","sourceRoot":"","sources":["../../src/ox-gantt.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, html, css, PropertyValues, PropertyValueMap } from 'lit'\nimport i18next from 'i18next'\nimport { customElement, property, query, state } from 'lit/decorators.js'\nimport { styles as MDTypeScaleStyles } from '@material/web/typography/md-typescale-styles'\nimport { ScrollbarStyles } from '@operato/styles'\n\nimport './ox-gantt-chart.js'\nimport './ox-gantt-resize-splitter.js'\nimport { OxGanttChart } from './ox-gantt-chart.js'\nimport { ColumnConfig, Task } from './types.js'\n\n@customElement('ox-gantt')\nexport class OxGantt extends LitElement {\n static styles = [\n MDTypeScaleStyles,\n ScrollbarStyles,\n css`\n :host {\n display: block;\n font-family: Arial, sans-serif;\n text-wrap: nowrap;\n position: relative;\n }\n\n .container {\n display: flex;\n width: 100%;\n height: 100%;\n box-sizing: border-box;\n }\n\n .task-container {\n padding: 0;\n overflow: auto;\n overflow-y: overlay;\n box-sizing: border-box;\n border: 1px solid var(--ox-gantt-border-color, var(--md-sys-color-on-surface));\n }\n\n .chart-container {\n flex: 1;\n padding: 0;\n box-sizing: border-box;\n border: 1px solid var(--ox-gantt-border-color, var(--md-sys-color-on-surface));\n }\n\n ox-gantt-resize-splitter {\n width: 4px;\n cursor: ew-resize;\n }\n\n table {\n width: 100%;\n border-collapse: collapse;\n border: 1px solid var(--ox-gantt-border-color, var(--md-sys-color-on-surface));\n margin: -1px;\n margin-right: 0;\n }\n\n thead th {\n position: sticky;\n top: -1px;\n z-index: 1;\n background-color: var(--ox-gantt-header-background-color, var(--md-sys-color-secondary-container));\n text-transform: capitalize;\n }\n\n th,\n td {\n border: 1px solid var(--ox-gantt-border-color, var(--md-sys-color-on-surface));\n padding: 4px;\n text-align: left;\n }\n\n th {\n height: 40px;\n box-sizing: border-box;\n }\n\n td {\n height: 30px;\n box-sizing: border-box;\n }\n\n tr.selected {\n background-color: var(--ox-gantt-selected-background-color, var(--md-sys-color-surface-variant));\n }\n `\n ]\n\n @property({ type: Array }) tasks: Task[] = []\n @property({ type: String, attribute: 'from-date' })\n fromDate: string = new Date(new Date().getFullYear(), 0, 1).toISOString().split('T')[0] /* beginning of this year */\n @property({ type: String, attribute: 'to-date' })\n toDate: string = new Date(new Date().getFullYear(), 11, 31).toISOString().split('T')[0] /* end of this year */\n @property({ type: Boolean, attribute: 'extend-grid-lines' }) extendGridLines: boolean = false\n\n @state() selectedTaskId?: string\n @state()\n private columnConfig: ColumnConfig[] = [\n { name: 'id', label: i18next.t('label.gantt-task-id') || 'ID', visible: true, width: '50px', order: 1 },\n {\n name: 'section',\n label: i18next.t('label.gantt-task-section') || 'section',\n visible: true,\n width: '100px',\n order: 2\n },\n { name: 'title', label: i18next.t('label.gantt-task-title') || 'title', visible: true, width: '150px', order: 3 },\n { name: 'type', label: i18next.t('label.gantt-task-type') || 'type', visible: true, width: '100px', order: 4 },\n {\n name: 'startDate',\n label: i18next.t('label.gantt-task-start-date') || 'start date',\n visible: true,\n width: '100px',\n order: 5\n },\n {\n name: 'endDate',\n label: i18next.t('label.gantt-task-end-date') || 'end date',\n visible: true,\n width: '100px',\n order: 6\n },\n { name: 'tags', label: i18next.t('label.gantt-task-tags') || 'tags', visible: true, width: '100px', order: 7 },\n {\n name: 'progress',\n label: i18next.t('label.gantt-task-progress') || 'progress',\n visible: true,\n width: '100px',\n order: 8\n },\n {\n name: 'dependsOn',\n label: i18next.t('label.gantt-task-previous') || 'previous',\n visible: true,\n width: '100px',\n order: 9\n }\n ]\n\n @query('.container') container!: HTMLDivElement\n @query('.task-container') taskContainer!: HTMLDivElement\n @query('.chart-container') chartContainer!: HTMLDivElement\n @query('table') taskTable!: HTMLTableElement\n @query('ox-gantt-chart') ganttChart!: OxGanttChart\n\n private _startWidth: number = 0\n private _isDragging: boolean = false\n\n render() {\n return html`\n <div class=\"container md-typescale-body-medium\">\n <div class=\"task-container\" @scroll=${this.syncScroll}>${this.renderTaskTable()}</div>\n <ox-gantt-resize-splitter\n vertical\n @splitter-dragstart=${(e: CustomEvent) => this.resizeStart(e)}\n @splitter-drag=${(e: CustomEvent) => this.resizeDrag(e)}\n @splitter-dragend=${(e: CustomEvent) => this.resizeEnd(e)}\n ></ox-gantt-resize-splitter>\n <ox-gantt-chart\n class=\"chart-container\"\n @scroll=${this.syncScroll}\n .fromDate=${this.fromDate}\n .toDate=${this.toDate}\n .tasks=${this.tasks}\n .selectedTaskId=${this.selectedTaskId}\n axis-scale=\"week-day\"\n ?extend-grid-lines=${this.extendGridLines}\n @task-clicked=${this.handleTaskClicked}\n ></ox-gantt-chart>\n </div>\n `\n }\n\n renderTaskTable() {\n const mergedTasks = this.mergeTasksBySection(this.tasks)\n\n // Sort columns by the configured order\n const sortedColumns = [...this.columnConfig].sort((a, b) => a.order - b.order)\n\n return html`\n <table>\n <thead>\n <tr>\n ${sortedColumns.map(col => (col.visible ? html`<th style=\"width: ${col.width}\">${col.label}</th>` : null))}\n </tr>\n </thead>\n <tbody>\n ${mergedTasks.map(\n ({ task, showSection, rowSpan }) => html`\n <tr class=\"${this.selectedTaskId === task.id ? 'selected' : ''}\" @click=${() => this.selectTask(task.id)}>\n ${sortedColumns.map(col => {\n if (col.name === 'section') {\n return col.visible && showSection\n ? html`<td rowspan=\"${rowSpan}\" style=\"width: ${col.width}\">${task.section?.name || ''}</td>`\n : null\n }\n return col.visible\n ? html`<td style=\"width: ${col.width}\">${this.getTaskFieldValue(task, col.name)}</td>`\n : null\n })}\n </tr>\n `\n )}\n </tbody>\n </table>\n `\n }\n\n getTaskFieldValue(task: Task, field: string) {\n switch (field) {\n case 'id':\n return task.id\n case 'section':\n return task.section?.name || ''\n case 'title':\n return task.title\n case 'type':\n return task.type\n case 'startDate':\n return task.startDate.toISOString().split('T')[0]\n case 'endDate':\n return task.endDate.toISOString().split('T')[0]\n case 'tags':\n return task.tags?.join(', ') || ''\n case 'progress':\n return task.progress || ''\n case 'dependsOn':\n return task.dependsOn || ''\n default:\n return ''\n }\n }\n\n mergeTasksBySection(tasks: Task[]): Array<{ task: Task; showSection: boolean; rowSpan: number }> {\n const mergedTasks = [] as Array<{ task: Task; showSection: boolean; rowSpan: number }>\n let currentSection = ''\n let rowSpan = 0\n\n tasks.forEach((task, index) => {\n if (task.section?.name !== currentSection) {\n currentSection = task.section?.name || ''\n rowSpan = 1\n mergedTasks.push({ task, showSection: true, rowSpan: 1 })\n } else {\n mergedTasks[mergedTasks.length - rowSpan].rowSpan = ++rowSpan\n mergedTasks.push({ task, showSection: false, rowSpan: 0 })\n }\n\n if (index === tasks.length - 1 && rowSpan > 0) {\n mergedTasks[mergedTasks.length - rowSpan].rowSpan = rowSpan\n }\n })\n\n return mergedTasks\n }\n\n selectTask(taskId: string) {\n this.selectedTaskId = taskId\n }\n\n handleTaskClicked(event: CustomEvent) {\n this.selectedTaskId = event.detail.taskId\n }\n\n protected firstUpdated(_changedProperties: PropertyValueMap<any> | Map<PropertyKey, unknown>): void {\n this.taskContainer.style.width = '254px'\n }\n\n updated(changes: PropertyValues<this>) {}\n\n syncScroll(e: Event) {\n const target = e.target as HTMLElement\n if (target === this.taskContainer) {\n // Sync chart scroll with table scroll\n const newScrollTop = this.taskContainer.scrollTop\n this.ganttChart.setVerticalOffset(newScrollTop)\n\n // Ensure chart scroll matches table scroll\n if (this.ganttChart.getVerticalOffset() !== newScrollTop) {\n this.ganttChart.setVerticalOffset(newScrollTop)\n }\n } else if (target === this.ganttChart) {\n // Sync table scroll with chart scroll\n const newScrollTop = this.ganttChart.getVerticalOffset()\n this.taskContainer.scrollTop = newScrollTop\n\n // Ensure table scroll matches chart scroll\n this.ganttChart.setVerticalOffset(this.taskContainer.scrollTop)\n }\n }\n\n resizeStart(e: CustomEvent) {\n this._startWidth = ((e.target as HTMLElement)?.previousElementSibling as HTMLElement)?.offsetWidth\n this._isDragging = true\n }\n\n resizeDrag(e: CustomEvent) {\n if (!this._isDragging) return\n const delta = e.detail\n const taskContainer = this.taskContainer\n\n if (taskContainer) {\n taskContainer.style.width = `${this._startWidth + delta.x}px`\n }\n }\n\n resizeEnd(e: CustomEvent) {\n this._isDragging = false\n }\n}\n"]}
@@ -0,0 +1,12 @@
1
+ import { LitElement } from 'lit';
2
+ export declare class OxTaskTooltip extends LitElement {
3
+ static styles: import("lit").CSSResult;
4
+ title: string;
5
+ startDate: string;
6
+ endDate: string;
7
+ progress: number;
8
+ type: string;
9
+ show(x: number, y: number): void;
10
+ hide(): void;
11
+ render(): import("lit-html").TemplateResult<1>;
12
+ }
@@ -0,0 +1,132 @@
1
+ import { __decorate } from "tslib";
2
+ import { LitElement, html, css } from 'lit';
3
+ import { customElement, property } from 'lit/decorators.js';
4
+ let OxTaskTooltip = class OxTaskTooltip extends LitElement {
5
+ constructor() {
6
+ super(...arguments);
7
+ this.title = '';
8
+ this.startDate = '';
9
+ this.endDate = '';
10
+ this.progress = 0;
11
+ this.type = '';
12
+ }
13
+ static { this.styles = css `
14
+ :host {
15
+ position: fixed; /* position: absolute로 변경 */
16
+ background-color: var(--ox-gantt-tooltip-background-color, var(--md-sys-color-surface, #f9f9f9));
17
+ border: 1px solid var(--ox-gantt-tooltip-border-color, var(--md-sys-color-outline, #ccc));
18
+ padding: var(--spacing-medium, 10px);
19
+ border-radius: var(--spacing-medium, 8px);
20
+ box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);
21
+ visibility: hidden;
22
+ z-index: 10;
23
+ max-width: 300px;
24
+ font-family: Roboto;
25
+ font-size: 14px;
26
+ line-height: 1.6;
27
+ color: var(--ox-gantt-tooltip-color, var(--md-sys-color-on-surface, #333));
28
+ transition:
29
+ visibility 0.1s,
30
+ opacity 0.1s;
31
+ opacity: 0; /* 초기에는 보이지 않음 */
32
+ }
33
+ :host([visible]) {
34
+ visibility: visible;
35
+ opacity: 1; /* 보일 때는 불투명 */
36
+ }
37
+ .title {
38
+ font-weight: bold;
39
+ font-size: 16px;
40
+ margin-bottom: 8px;
41
+ color: var(--ox-gantt-tooltip-title-color, var(--md-sys-color-primary, #0078d4)); /* 파란색 텍스트 */
42
+ }
43
+ .detail {
44
+ display: grid;
45
+ grid-template-columns: auto auto 1fr;
46
+ gap: 4px;
47
+ align-items: center;
48
+ }
49
+ .label {
50
+ font-weight: bold;
51
+ color: var(--ox-gantt-tooltip-color, var(--md-sys-color-on-surface-variant, #333));
52
+ text-align: right; /* 라벨을 우측 정렬 */
53
+ }
54
+ .colon {
55
+ text-align: center;
56
+ color: var(--ox-gantt-tooltip-color, var(--md-sys-color-on-surface, #333));
57
+ }
58
+ .value {
59
+ text-align: left; /* 값을 좌측 정렬 */
60
+ color: var(--ox-gantt-tooltip-color, var(--md-sys-color-on-surface, #333));
61
+ }
62
+ `; }
63
+ show(x, y) {
64
+ const tooltipWidth = this.offsetWidth;
65
+ const tooltipHeight = this.offsetHeight;
66
+ const offsetX = 10;
67
+ const offsetY = 10;
68
+ // 기본 위치 계산
69
+ let left = x + offsetX;
70
+ let top = y + offsetY;
71
+ // 화면 경계 확인 및 조정
72
+ const screenWidth = window.innerWidth;
73
+ const screenHeight = window.innerHeight;
74
+ if (left + tooltipWidth > screenWidth) {
75
+ left = x - tooltipWidth - offsetX;
76
+ }
77
+ if (top + tooltipHeight > screenHeight) {
78
+ top = y - tooltipHeight - offsetY;
79
+ }
80
+ // offsetParent 요소를 기준으로 위치 설정
81
+ if (this.offsetParent) {
82
+ const parentRect = this.offsetParent.getBoundingClientRect();
83
+ this.style.left = `${left - parentRect.left}px`;
84
+ this.style.top = `${top - parentRect.top}px`;
85
+ }
86
+ else {
87
+ this.style.left = `${left}px`;
88
+ this.style.top = `${top}px`;
89
+ const myRect = this.getBoundingClientRect();
90
+ /* 실제 바운드와 설정한 left/top 이 일치하지 않는다면, 부모 어딘가에서 transform 되었다고 판단하고, 보정해줌 */
91
+ if (myRect.left !== left || myRect.top !== top) {
92
+ this.style.left = `${left + (left - myRect.left)}px`;
93
+ this.style.top = `${top + (top - myRect.top)}px`;
94
+ }
95
+ }
96
+ this.setAttribute('visible', '');
97
+ }
98
+ hide() {
99
+ this.removeAttribute('visible');
100
+ }
101
+ render() {
102
+ return html `
103
+ <div class="title">${this.title}</div>
104
+ <div class="detail">
105
+ <span class="label">Type</span><span class="colon">:</span><span class="value">${this.type}</span>
106
+ <span class="label">Start Date</span><span class="colon">:</span><span class="value">${this.startDate}</span>
107
+ <span class="label">End Date</span><span class="colon">:</span><span class="value">${this.endDate}</span>
108
+ <span class="label">Progress</span><span class="colon">:</span><span class="value">${this.progress}%</span>
109
+ </div>
110
+ `;
111
+ }
112
+ };
113
+ __decorate([
114
+ property({ type: String })
115
+ ], OxTaskTooltip.prototype, "title", void 0);
116
+ __decorate([
117
+ property({ type: String })
118
+ ], OxTaskTooltip.prototype, "startDate", void 0);
119
+ __decorate([
120
+ property({ type: String })
121
+ ], OxTaskTooltip.prototype, "endDate", void 0);
122
+ __decorate([
123
+ property({ type: Number })
124
+ ], OxTaskTooltip.prototype, "progress", void 0);
125
+ __decorate([
126
+ property({ type: String })
127
+ ], OxTaskTooltip.prototype, "type", void 0);
128
+ OxTaskTooltip = __decorate([
129
+ customElement('ox-task-tooltip')
130
+ ], OxTaskTooltip);
131
+ export { OxTaskTooltip };
132
+ //# sourceMappingURL=ox-task-tooltip.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ox-task-tooltip.js","sourceRoot":"","sources":["../../src/ox-task-tooltip.ts"],"names":[],"mappings":"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","sourcesContent":["import { LitElement, html, css } from 'lit'\nimport { customElement, property } from 'lit/decorators.js'\n\n@customElement('ox-task-tooltip')\nexport class OxTaskTooltip extends LitElement {\n static styles = css`\n :host {\n position: fixed; /* position: absolute로 변경 */\n background-color: var(--ox-gantt-tooltip-background-color, var(--md-sys-color-surface, #f9f9f9));\n border: 1px solid var(--ox-gantt-tooltip-border-color, var(--md-sys-color-outline, #ccc));\n padding: var(--spacing-medium, 10px);\n border-radius: var(--spacing-medium, 8px);\n box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1);\n visibility: hidden;\n z-index: 10;\n max-width: 300px;\n font-family: Roboto;\n font-size: 14px;\n line-height: 1.6;\n color: var(--ox-gantt-tooltip-color, var(--md-sys-color-on-surface, #333));\n transition:\n visibility 0.1s,\n opacity 0.1s;\n opacity: 0; /* 초기에는 보이지 않음 */\n }\n :host([visible]) {\n visibility: visible;\n opacity: 1; /* 보일 때는 불투명 */\n }\n .title {\n font-weight: bold;\n font-size: 16px;\n margin-bottom: 8px;\n color: var(--ox-gantt-tooltip-title-color, var(--md-sys-color-primary, #0078d4)); /* 파란색 텍스트 */\n }\n .detail {\n display: grid;\n grid-template-columns: auto auto 1fr;\n gap: 4px;\n align-items: center;\n }\n .label {\n font-weight: bold;\n color: var(--ox-gantt-tooltip-color, var(--md-sys-color-on-surface-variant, #333));\n text-align: right; /* 라벨을 우측 정렬 */\n }\n .colon {\n text-align: center;\n color: var(--ox-gantt-tooltip-color, var(--md-sys-color-on-surface, #333));\n }\n .value {\n text-align: left; /* 값을 좌측 정렬 */\n color: var(--ox-gantt-tooltip-color, var(--md-sys-color-on-surface, #333));\n }\n `\n\n @property({ type: String }) title = ''\n @property({ type: String }) startDate = ''\n @property({ type: String }) endDate = ''\n @property({ type: Number }) progress = 0\n @property({ type: String }) type = ''\n\n show(x: number, y: number) {\n const tooltipWidth = this.offsetWidth\n const tooltipHeight = this.offsetHeight\n const offsetX = 10\n const offsetY = 10\n\n // 기본 위치 계산\n let left = x + offsetX\n let top = y + offsetY\n\n // 화면 경계 확인 및 조정\n const screenWidth = window.innerWidth\n const screenHeight = window.innerHeight\n\n if (left + tooltipWidth > screenWidth) {\n left = x - tooltipWidth - offsetX\n }\n if (top + tooltipHeight > screenHeight) {\n top = y - tooltipHeight - offsetY\n }\n\n // offsetParent 요소를 기준으로 위치 설정\n if (this.offsetParent) {\n const parentRect = this.offsetParent!.getBoundingClientRect()\n this.style.left = `${left - parentRect.left}px`\n this.style.top = `${top - parentRect.top}px`\n } else {\n this.style.left = `${left}px`\n this.style.top = `${top}px`\n\n const myRect = this.getBoundingClientRect()\n\n /* 실제 바운드와 설정한 left/top 이 일치하지 않는다면, 부모 어딘가에서 transform 되었다고 판단하고, 보정해줌 */\n if (myRect.left !== left || myRect.top !== top) {\n this.style.left = `${left + (left - myRect.left)}px`\n this.style.top = `${top + (top - myRect.top)}px`\n }\n }\n\n this.setAttribute('visible', '')\n }\n\n hide() {\n this.removeAttribute('visible')\n }\n\n render() {\n return html`\n <div class=\"title\">${this.title}</div>\n <div class=\"detail\">\n <span class=\"label\">Type</span><span class=\"colon\">:</span><span class=\"value\">${this.type}</span>\n <span class=\"label\">Start Date</span><span class=\"colon\">:</span><span class=\"value\">${this.startDate}</span>\n <span class=\"label\">End Date</span><span class=\"colon\">:</span><span class=\"value\">${this.endDate}</span>\n <span class=\"label\">Progress</span><span class=\"colon\">:</span><span class=\"value\">${this.progress}%</span>\n </div>\n `\n }\n}\n"]}
@@ -5,10 +5,10 @@ export interface Task {
5
5
  title: string;
6
6
  type: TaskType;
7
7
  section?: Section;
8
- startTime: Date;
9
- endTime: Date;
8
+ startDate: Date;
9
+ endDate: Date;
10
10
  progress?: number;
11
- after?: string;
11
+ dependsOn?: string;
12
12
  length: string;
13
13
  tags?: TaskTag[];
14
14
  children?: Task[];
@@ -16,4 +16,11 @@ export interface Task {
16
16
  export interface Section {
17
17
  name: string;
18
18
  }
19
+ export interface ColumnConfig {
20
+ name: string;
21
+ label: string;
22
+ visible: boolean;
23
+ width: string;
24
+ order: number;
25
+ }
19
26
  export type LEVEL = 'year-quarter' | 'year-month' | 'quarter-week' | 'week-day';
@@ -1 +1 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"","sourcesContent":["export type TaskTag = 'done' | 'active' | 'critical' | 'milestone'\nexport type TaskType = 'task' | 'milestone' | 'phase'\n\nexport interface Task {\n id: string\n title: string\n type: TaskType\n section?: Section\n startTime: Date\n endTime: Date\n progress?: number\n after?: string // 이전 태스크의 ID\n length: string // 예: '3d' (3 days)\n tags?: TaskTag[]\n children?: Task[]\n}\n\nexport interface Section {\n name: string\n}\n\nexport type LEVEL = 'year-quarter' | 'year-month' | 'quarter-week' | 'week-day'\n"]}
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/types.ts"],"names":[],"mappings":"","sourcesContent":["export type TaskTag = 'done' | 'active' | 'critical' | 'milestone'\nexport type TaskType = 'task' | 'milestone' | 'phase'\n\nexport interface Task {\n id: string\n title: string\n type: TaskType\n section?: Section\n startDate: Date\n endDate: Date\n progress?: number\n dependsOn?: string // 이전 태스크의 ID\n length: string // 예: '3d' (3 days)\n tags?: TaskTag[]\n children?: Task[]\n}\n\nexport interface Section {\n name: string\n}\n\nexport interface ColumnConfig {\n name: string\n label: string\n visible: boolean\n width: string\n order: number\n}\n\nexport type LEVEL = 'year-quarter' | 'year-month' | 'quarter-week' | 'week-day'\n"]}