@mogura/moguchart-core 0.7.0 → 0.8.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.
@@ -41,6 +41,10 @@ export declare class GanttRowElement extends LitElement {
41
41
  * マーカーのSVGパスを生成する
42
42
  */
43
43
  private getMarkerPath;
44
+ /**
45
+ * マーカーのフォントサイズ名をpx値に変換する
46
+ */
47
+ private resolveMarkerFontSize;
44
48
  /**
45
49
  * マーカーの表示幅を推定する(アイコン+ラベル)
46
50
  */
@@ -58,6 +62,10 @@ export declare class GanttRowElement extends LitElement {
58
62
  private handleHeaderClick;
59
63
  private handleHeaderContextMenu;
60
64
  private handleHeaderDblClick;
65
+ private _rowHeaderTooltipEl;
66
+ private _rowHeaderTooltipTimer;
67
+ private handleHeaderMouseEnter;
68
+ private handleHeaderMouseLeave;
61
69
  protected updated(changedProperties: PropertyValues): void;
62
70
  render(): import("lit").TemplateResult<1>;
63
71
  }
@@ -20,6 +20,10 @@ export type MarkerType = 'triangle-up' | 'triangle-down' | 'triangle-left' | 'tr
20
20
  * マーカーのアンカー位置
21
21
  */
22
22
  export type AnchorType = 'start' | 'end' | 'center';
23
+ /**
24
+ * マーカーのフォントサイズ
25
+ */
26
+ export type MarkerFontSize = 'xs' | 'sm' | 'md' | 'lg' | 'xl';
23
27
  /**
24
28
  * マーカーの設定
25
29
  */
@@ -36,6 +40,8 @@ export interface GanttMarker {
36
40
  type: MarkerType;
37
41
  /** マーカーの色 (CSS color string) */
38
42
  color?: string;
43
+ /** マーカーのラベルのフォントサイズ ('xs'=極小, 'sm'=小, 'md'=中, 'lg'=大, 'xl'=特大) */
44
+ fontSize?: MarkerFontSize;
39
45
  /** マーカーのカスタムスタイル (CSS文字列) */
40
46
  style?: string;
41
47
  }
@@ -82,6 +88,8 @@ export interface GanttRow {
82
88
  tasks: GanttTask[];
83
89
  /** マーカーの配列 */
84
90
  markers?: GanttMarker[];
91
+ /** 現在選択中(編集中)のマーカーID */
92
+ selectedMarkerId?: string;
85
93
  /** 行を表示するかどうか (デフォルト: true) */
86
94
  visible?: boolean;
87
95
  }
@@ -285,6 +293,8 @@ export interface GanttChartOptionCustomRendering {
285
293
  calendarHourContent?: (context: CalendarHourCellContext) => string | unknown;
286
294
  /** ガントチャート部の背景セルをレンダリングする関数。各日のセルごとに呼ばれ、HTML文字列またはTemplateResultを返す */
287
295
  chartBackground?: (context: ChartBackgroundCellContext) => string | unknown;
296
+ /** 行ヘッダーのツールチップコンテンツをレンダリングする関数。マウスホバー時に呼ばれる */
297
+ rowHeaderTooltip?: (row: GanttRow) => string | HTMLElement | unknown;
288
298
  }
289
299
  /**
290
300
  * チャート背景右クリックイベントの詳細データ
@@ -618,6 +628,28 @@ export interface DependencyClickEventDetail {
618
628
  /** 元のマウスイベント */
619
629
  event: MouseEvent;
620
630
  }
631
+ /**
632
+ * マーカーダブルクリックイベントの詳細データ
633
+ */
634
+ export interface MarkerDblClickEventDetail {
635
+ /** 対象のマーカー */
636
+ marker: GanttMarker;
637
+ /** マーカーが属する行ID */
638
+ rowId: string;
639
+ /** 元のマウスイベント */
640
+ event: MouseEvent;
641
+ }
642
+ /**
643
+ * マーカー右クリック(コンテキストメニュー)イベントの詳細データ
644
+ */
645
+ export interface MarkerContextMenuEventDetail {
646
+ /** 対象のマーカー */
647
+ marker: GanttMarker;
648
+ /** マーカーが属する行ID */
649
+ rowId: string;
650
+ /** 元のマウスイベント */
651
+ event: MouseEvent;
652
+ }
621
653
  /**
622
654
  * タスク削除イベントの詳細データ
623
655
  */
@@ -1019,6 +1019,9 @@ var H = class extends e {
1019
1019
  transition: opacity 0.2s ease;
1020
1020
  cursor: default;
1021
1021
  }
1022
+ .milestone-badge.milestone-hovered {
1023
+ z-index: 200;
1024
+ }
1022
1025
  .milestone-connector {
1023
1026
  position: absolute;
1024
1027
  top: 19px;
@@ -1029,6 +1032,9 @@ var H = class extends e {
1029
1032
  transition: opacity 0.2s ease;
1030
1033
  cursor: default;
1031
1034
  }
1035
+ .milestone-connector.milestone-hovered {
1036
+ z-index: 199;
1037
+ }
1032
1038
  `;
1033
1039
  }
1034
1040
  getDateX(e) {
@@ -1297,7 +1303,7 @@ var H = class extends e {
1297
1303
  ` : ""}
1298
1304
  ${(this.option.calendar.milestones ?? []).map((e) => n`
1299
1305
  <div
1300
- class="milestone-connector"
1306
+ class="milestone-connector ${this.hoveredMilestoneId === e.id ? "milestone-hovered" : ""}"
1301
1307
  style="
1302
1308
  left: ${this.getDateX(e.start) + 1}px;
1303
1309
  width: ${e.width ?? 2}px;
@@ -1320,7 +1326,7 @@ var H = class extends e {
1320
1326
  }}"
1321
1327
  ></div>
1322
1328
  <div
1323
- class="milestone-badge"
1329
+ class="milestone-badge ${this.hoveredMilestoneId === e.id ? "milestone-hovered" : ""}"
1324
1330
  style="
1325
1331
  left: ${this.getDateX(e.start)}px;
1326
1332
  background-color: ${e.color};
@@ -1427,7 +1433,7 @@ B([s({ type: Object })], U.prototype, "option", void 0), B([s({ type: String })]
1427
1433
  //#region src/components/gantt-row.ts
1428
1434
  var W = class extends e {
1429
1435
  constructor(...e) {
1430
- super(...e), this.isDragTarget = !1, this.draggingTask = null, this.draggingTaskIds = [], this.multiDragDx = 0, this.multiDragDy = 0, this.multiDragSameRow = !1, this.externalDragTask = null, this.theme = "light", this.isSelected = !1, this.dropPosition = null, this.selectedTaskIds = [], this.focusedTaskId = null, this.isExporting = !1, this.criticalPathTaskIds = [], this._cachedMonthGridLines = null, this._cachedMonthGridStartTime = 0, this._cachedMonthGridEndTime = 0, this._cachedMonthGridPxPerDay = 0, this._cachedMonthGridPxPerMonth = 0;
1436
+ super(...e), this.isDragTarget = !1, this.draggingTask = null, this.draggingTaskIds = [], this.multiDragDx = 0, this.multiDragDy = 0, this.multiDragSameRow = !1, this.externalDragTask = null, this.theme = "light", this.isSelected = !1, this.dropPosition = null, this.selectedTaskIds = [], this.focusedTaskId = null, this.isExporting = !1, this.criticalPathTaskIds = [], this._cachedMonthGridLines = null, this._cachedMonthGridStartTime = 0, this._cachedMonthGridEndTime = 0, this._cachedMonthGridPxPerDay = 0, this._cachedMonthGridPxPerMonth = 0, this._rowHeaderTooltipEl = null;
1431
1437
  }
1432
1438
  getDateX(e) {
1433
1439
  return M(e, this.option.calendar.start, this.option.calendar.pxPerDay, this.option.calendar.pxPerMonth);
@@ -1444,26 +1450,28 @@ var W = class extends e {
1444
1450
  default: return `M 0 ${t} L ${n} 0 L ${t} ${t} Z`;
1445
1451
  }
1446
1452
  }
1453
+ resolveMarkerFontSize(e) {
1454
+ switch (e) {
1455
+ case "xs": return 8;
1456
+ case "sm": return 10;
1457
+ case "md": return 12;
1458
+ case "lg": return 14;
1459
+ case "xl": return 18;
1460
+ default: return 10;
1461
+ }
1462
+ }
1447
1463
  estimateMarkerWidth(e, t) {
1448
- let n = e.name ? e.name.length * 7 + 4 : 0;
1449
- return e.anchor === "center" ? t : t + n;
1464
+ let n = this.resolveMarkerFontSize(e.fontSize) * .7, r = e.name ? e.name.length * n + 4 : 0;
1465
+ return e.anchor === "center" ? t : t + r;
1450
1466
  }
1451
1467
  getMarkerXRange(e, t) {
1452
- let n = this.getDateX(e.date), r = this.estimateMarkerWidth(e, t), i = e.anchor === "center", a = e.anchor === "end", o;
1453
- if (o = e.anchor === "start" ? n : e.anchor === "end" ? n - t : n - t / 2, i) return {
1454
- left: o,
1455
- right: o + t
1456
- };
1457
- if (a) {
1458
- let e = r - t;
1459
- return {
1460
- left: o - e,
1461
- right: o + t
1462
- };
1463
- }
1464
- return {
1465
- left: o,
1466
- right: o + r
1468
+ let n = this.getDateX(e.date), r = this.estimateMarkerWidth(e, t), i = e.anchor === "center", a;
1469
+ return a = e.anchor === "start" ? n : e.anchor === "end" ? n - r : n - t / 2, i ? {
1470
+ left: a,
1471
+ right: a + t
1472
+ } : {
1473
+ left: a,
1474
+ right: a + r
1467
1475
  };
1468
1476
  }
1469
1477
  calculateMarkerLanes(e, t) {
@@ -1549,6 +1557,33 @@ var W = class extends e {
1549
1557
  flex: none;
1550
1558
  position: relative;
1551
1559
  }
1560
+ .marker-wrapper {
1561
+ transition: transform 0.15s ease, filter 0.15s ease;
1562
+ user-select: none;
1563
+ -webkit-user-select: none;
1564
+ }
1565
+ .marker-wrapper.marker-anchor-end {
1566
+ transform: translateX(-100%);
1567
+ }
1568
+ .marker-wrapper:hover {
1569
+ transform: scale(1.3);
1570
+ filter: brightness(1.15) drop-shadow(0 2px 6px rgba(0,0,0,0.4)) drop-shadow(0 0 8px rgba(255,255,255,0.5));
1571
+ z-index: 10 !important;
1572
+ }
1573
+ .marker-wrapper.marker-anchor-end:hover {
1574
+ transform: translateX(-100%) scale(1.3);
1575
+ }
1576
+ .marker-wrapper.marker-selected {
1577
+ filter: brightness(1.2) drop-shadow(0 0 6px rgba(59,130,246,0.7)) drop-shadow(0 0 10px rgba(59,130,246,0.4));
1578
+ z-index: 10 !important;
1579
+ }
1580
+ .marker-wrapper.marker-selected .marker-icon {
1581
+ animation: marker-pulse 1.2s ease-in-out infinite;
1582
+ }
1583
+ @keyframes marker-pulse {
1584
+ 0%, 100% { opacity: 1; }
1585
+ 50% { opacity: 0.65; }
1586
+ }
1552
1587
  .grid-background {
1553
1588
  position: absolute;
1554
1589
  top: 0;
@@ -1560,7 +1595,7 @@ var W = class extends e {
1560
1595
  `;
1561
1596
  }
1562
1597
  handleDragStart(e) {
1563
- if (this.isSelected || this.dispatchEvent(new CustomEvent("row-clicked", {
1598
+ if (this.handleHeaderMouseLeave(), this.isSelected || this.dispatchEvent(new CustomEvent("row-clicked", {
1564
1599
  detail: {
1565
1600
  rowId: this.row.id,
1566
1601
  event: e
@@ -1626,6 +1661,26 @@ var W = class extends e {
1626
1661
  composed: !0
1627
1662
  }));
1628
1663
  }
1664
+ handleHeaderMouseEnter(e) {
1665
+ let t = this.option.customRendering?.rowHeaderTooltip;
1666
+ if (!t) return;
1667
+ let n = this.option.tooltipDelay ?? 500, i = e.currentTarget, a = () => {
1668
+ let e = t(this.row);
1669
+ if (!e) return;
1670
+ let n = document.createElement("div");
1671
+ n.style.position = "fixed", n.style.zIndex = "9999", n.style.pointerEvents = "none", n.style.opacity = "0", n.style.transition = "opacity 0.15s ease", n.style.maxWidth = "360px", n.style.borderRadius = "8px", n.style.padding = "8px 12px", n.style.fontSize = "12px", n.style.lineHeight = "1.5", n.style.boxShadow = "0 4px 12px rgba(0,0,0,0.15)";
1672
+ let a = F(this.theme, this.option.customTheme);
1673
+ n.style.backgroundColor = a.tooltipBg, n.style.color = a.tooltipText, typeof e == "string" ? n.textContent = e : e instanceof HTMLElement ? n.appendChild(e) : r(e, n), document.body.appendChild(n), this._rowHeaderTooltipEl = n;
1674
+ let o = i.getBoundingClientRect(), s = n.getBoundingClientRect(), c = o.right + 6, l = o.top;
1675
+ c + s.width > window.innerWidth - 6 && (c = o.left - s.width - 6), l + s.height > window.innerHeight - 6 && (l = window.innerHeight - s.height - 6), l < 6 && (l = 6), n.style.left = `${c}px`, n.style.top = `${l}px`, requestAnimationFrame(() => {
1676
+ n.style.opacity = "1";
1677
+ });
1678
+ };
1679
+ n > 0 ? this._rowHeaderTooltipTimer = window.setTimeout(a, n) : a();
1680
+ }
1681
+ handleHeaderMouseLeave() {
1682
+ this._rowHeaderTooltipTimer !== void 0 && (window.clearTimeout(this._rowHeaderTooltipTimer), this._rowHeaderTooltipTimer = void 0), this._rowHeaderTooltipEl &&= (this._rowHeaderTooltipEl.remove(), null);
1683
+ }
1629
1684
  updated(e) {
1630
1685
  if (super.updated(e), !(e.has("row") || e.has("option") || e.has("isSelected") || e.has("theme"))) return;
1631
1686
  let t = this.shadowRoot?.querySelector(".row-header-content");
@@ -1762,6 +1817,8 @@ var W = class extends e {
1762
1817
  @click="${this.handleHeaderClick}"
1763
1818
  @dblclick="${this.handleHeaderDblClick}"
1764
1819
  @contextmenu="${this.handleHeaderContextMenu}"
1820
+ @mouseenter="${this.handleHeaderMouseEnter}"
1821
+ @mouseleave="${this.handleHeaderMouseLeave}"
1765
1822
  >
1766
1823
  <div
1767
1824
  class="row-header-content"
@@ -1806,41 +1863,63 @@ var W = class extends e {
1806
1863
  `;
1807
1864
  })}
1808
1865
  ${f.map(({ marker: e, lane: t }) => {
1809
- let r = this.getDateX(e.date), i = e.color ?? "#ef4444", a = e.anchor === "center", o = (a ? m / 2 - l : (m - l) / 2) + t * d, s = e.anchor === "start" ? r : e.anchor === "end" ? r - l : r - l / 2, c = e.anchor === "end";
1866
+ let r = this.getDateX(e.date), i = e.color ?? "#ef4444", a = this.resolveMarkerFontSize(e.fontSize), s = Math.min(o, Math.max(8, Math.round(a * 1.2))), c = e.anchor === "center", l = (c ? m / 2 - s : (m - s) / 2) + t * d, u = e.anchor === "start" || e.anchor === "end" ? r : r - s / 2, f = e.anchor === "end", p = f;
1810
1867
  return n`
1811
1868
  <div
1812
- class="marker-wrapper"
1869
+ class="marker-wrapper${this.row.selectedMarkerId === e.id ? " marker-selected" : ""}${f ? " marker-anchor-end" : ""}"
1813
1870
  style="
1814
1871
  position: absolute;
1815
- left: ${s}px;
1816
- top: ${o}px;
1872
+ left: ${u}px;
1873
+ top: ${l}px;
1817
1874
  z-index: 2;
1818
1875
  display: flex;
1819
- ${a ? `flex-direction: column; align-items: center; width: ${l}px; overflow: visible;` : `align-items: center; ${c ? "flex-direction: row-reverse;" : ""}`}
1876
+ ${c ? `flex-direction: column; align-items: center; width: ${s}px; overflow: visible;` : `align-items: center; ${p ? "flex-direction: row-reverse;" : ""}`}
1820
1877
  pointer-events: auto;
1821
- cursor: default;
1878
+ cursor: pointer;
1822
1879
  white-space: nowrap;
1823
1880
  "
1824
1881
  title="${e.name ?? ""}"
1882
+ @dblclick="${(t) => {
1883
+ t.preventDefault(), t.stopPropagation(), window.getSelection()?.removeAllRanges(), this.dispatchEvent(new CustomEvent("marker-dblclick", {
1884
+ detail: {
1885
+ marker: e,
1886
+ rowId: this.row.id,
1887
+ event: t
1888
+ },
1889
+ bubbles: !0,
1890
+ composed: !0
1891
+ }));
1892
+ }}"
1893
+ @contextmenu="${(t) => {
1894
+ t.preventDefault(), t.stopPropagation(), this.dispatchEvent(new CustomEvent("marker-contextmenu", {
1895
+ detail: {
1896
+ marker: e,
1897
+ rowId: this.row.id,
1898
+ event: t
1899
+ },
1900
+ bubbles: !0,
1901
+ composed: !0
1902
+ }));
1903
+ }}"
1825
1904
  >
1826
1905
  <svg
1827
1906
  class="marker-icon"
1828
- width="${l}"
1829
- height="${l}"
1830
- viewBox="0 0 ${l} ${l}"
1907
+ width="${s}"
1908
+ height="${s}"
1909
+ viewBox="0 0 ${s} ${s}"
1831
1910
  style="
1832
1911
  flex-shrink: 0;
1833
1912
  filter: drop-shadow(0 1px 2px rgba(0,0,0,0.3));
1834
1913
  ${e.style ?? ""}
1835
1914
  "
1836
1915
  >
1837
- <path d="${this.getMarkerPath(e.type, l)}" fill="${i}" />
1916
+ <path d="${this.getMarkerPath(e.type, s)}" fill="${i}" />
1838
1917
  </svg>
1839
1918
  ${e.name ? n`<span style="
1840
- font-size: 10px;
1919
+ font-size: ${a}px;
1841
1920
  color: ${i};
1842
1921
  line-height: 1;
1843
- ${a ? "padding: 1px 0 0 0;" : "padding: 0 2px;"}
1922
+ ${c ? "padding: 1px 0 0 0;" : "padding: 0 2px;"}
1844
1923
  ">${e.name}</span>` : ""}
1845
1924
  </div>
1846
1925
  `;
@@ -2024,9 +2103,12 @@ var K = t`
2024
2103
  position: absolute;
2025
2104
  z-index: 59;
2026
2105
  pointer-events: auto;
2027
- transition: opacity 0.2s ease;
2106
+ transition: opacity 0.2s ease, z-index 0s;
2028
2107
  cursor: default;
2029
2108
  }
2109
+ .milestone-line.milestone-hovered {
2110
+ z-index: 200;
2111
+ }
2030
2112
  .cursor-line {
2031
2113
  position: absolute;
2032
2114
  width: 2px;
@@ -2387,6 +2469,8 @@ var Z = class extends e {
2387
2469
  <div class="tooltip-row">${t.tooltip.duration(a)}</div>
2388
2470
  `, e);
2389
2471
  }
2472
+ let i = e.getBoundingClientRect(), a = this.tooltip.x, o = this.tooltip.y;
2473
+ i.right > window.innerWidth - 6 && (a = window.innerWidth - 6 - i.width / 2), i.left < 6 && (a = 6 + i.width / 2), i.top < 6 && (e.style.transform = "translate(-50%, 0)", e.style.marginTop = "6px"), (a !== this.tooltip.x || o !== this.tooltip.y) && (e.style.left = `${a}px`, e.style.top = `${o}px`);
2390
2474
  }
2391
2475
  }
2392
2476
  }
@@ -3397,7 +3481,7 @@ var Z = class extends e {
3397
3481
  ` : ""}
3398
3482
  ${(this.option.calendar.milestones ?? []).map((e) => n`
3399
3483
  <div
3400
- class="milestone-line"
3484
+ class="milestone-line ${this.hoveredMilestoneId === e.id ? "milestone-hovered" : ""}"
3401
3485
  style="
3402
3486
  top: ${this.calendarHeight}px;
3403
3487
  left: ${this.getDateX(e.start) + o}px;
@@ -359,6 +359,9 @@
359
359
  transition: opacity 0.2s ease;
360
360
  cursor: default;
361
361
  }
362
+ .milestone-badge.milestone-hovered {
363
+ z-index: 200;
364
+ }
362
365
  .milestone-connector {
363
366
  position: absolute;
364
367
  top: 19px;
@@ -369,6 +372,9 @@
369
372
  transition: opacity 0.2s ease;
370
373
  cursor: default;
371
374
  }
375
+ .milestone-connector.milestone-hovered {
376
+ z-index: 199;
377
+ }
372
378
  `}getDateX(e){return P(e,this.option.calendar.start,this.option.calendar.pxPerDay,this.option.calendar.pxPerMonth)}formatTime(e){return`${e.getHours().toString().padStart(2,`0`)}:${e.getMinutes().toString().padStart(2,`0`)}`}_buildWeeks(e,t){let n=e=>{let n=new Date(e.getTime());n.setHours(0,0,0,0);let r=(n.getDay()-t+7)%7,i=new Date(n.getTime());i.setDate(i.getDate()-r);let a=new Date(i.getFullYear(),0,1),o=Math.floor((i.getTime()-a.getTime())/864e5);return Math.floor(o/7)+1},r=[];return e.forEach(e=>{let i=e.getDay()===t,a=r[r.length-1];a&&!i?a.count++:r.push({weekNumber:n(e),startDate:new Date(e),count:1})}),r}render(){let e=L(this.theme,this.option.customTheme),n=this.option.calendar.start.getTime(),i=this.option.calendar.end.getTime(),a=this.option.calendar.pxPerDay,o=this.option.calendar.pxPerMonth,s=this.option.calendar.weekStartDay??1,c=!this._cachedDays||n!==this._cachedStartTime||i!==this._cachedEndTime,l=a!==this._cachedPxPerDay||o!==this._cachedPxPerMonth;if(c){this._cachedStartTime=n,this._cachedEndTime=i,this._cachedPxPerDay=a,this._cachedPxPerMonth=o;let e=Array.from({length:Math.ceil(this.totalDays)},(e,t)=>{let n=new Date(this.option.calendar.start);return n.setDate(n.getDate()+t),n});this._cachedDays=e;let t=[];e.forEach(e=>{let n=e.getFullYear(),r=e.getMonth(),i=t[t.length-1];if(i&&i.year===n&&i.month===r)i.count++,i.end=new Date(e),i.end.setDate(i.end.getDate()+1);else{let i=new Date(e);i.setHours(0,0,0,0);let a=new Date(e);a.setDate(a.getDate()+1),t.push({year:n,month:r,count:1,start:i,end:a})}}),t.forEach(e=>{e.start&&e.end&&(e.width=this.getDateX(e.end)-this.getDateX(e.start))}),this._cachedMonths=t;let r=[];e.forEach(e=>{let t=e.getFullYear(),n=r[r.length-1];if(n&&n.year===t)n.count++,n.end=new Date(e),n.end.setDate(n.end.getDate()+1);else{let n=new Date(e);n.setHours(0,0,0,0);let i=new Date(e);i.setDate(i.getDate()+1),r.push({year:t,count:1,start:n,end:i})}}),r.forEach(e=>{e.start&&e.end&&(e.width=this.getDateX(e.end)-this.getDateX(e.start))}),this._cachedYears=r,this._cachedWeekStartDay=s,this._cachedWeeks=this._buildWeeks(e,s)}else l?(this._cachedPxPerDay=a,this._cachedPxPerMonth=o,this._cachedMonths.forEach(e=>{e.start&&e.end&&(e.width=this.getDateX(e.end)-this.getDateX(e.start))}),this._cachedYears.forEach(e=>{e.start&&e.end&&(e.width=this.getDateX(e.end)-this.getDateX(e.start))}),s!==this._cachedWeekStartDay&&(this._cachedWeekStartDay=s,this._cachedWeeks=this._buildWeeks(this._cachedDays,s))):s!==this._cachedWeekStartDay&&(this._cachedWeekStartDay=s,this._cachedWeeks=this._buildWeeks(this._cachedDays,s));let u=this._cachedDays,d=this._cachedMonths,f=this._cachedYears,p=`
373
379
  background-image: linear-gradient(90deg, transparent ${this.option.calendar.pxPerDay-1}px, ${e.border} ${this.option.calendar.pxPerDay-1}px);
374
380
  background-size: ${this.option.calendar.pxPerDay}px 100%;
@@ -508,7 +514,7 @@
508
514
  `:``}
509
515
  ${(this.option.calendar.milestones??[]).map(e=>t.html`
510
516
  <div
511
- class="milestone-connector"
517
+ class="milestone-connector ${this.hoveredMilestoneId===e.id?`milestone-hovered`:``}"
512
518
  style="
513
519
  left: ${this.getDateX(e.start)+1}px;
514
520
  width: ${e.width??2}px;
@@ -519,7 +525,7 @@
519
525
  @mouseleave="${()=>{this.dispatchEvent(new CustomEvent(`milestone-hover-change`,{detail:{milestoneId:null},bubbles:!0,composed:!0}))}}"
520
526
  ></div>
521
527
  <div
522
- class="milestone-badge"
528
+ class="milestone-badge ${this.hoveredMilestoneId===e.id?`milestone-hovered`:``}"
523
529
  style="
524
530
  left: ${this.getDateX(e.start)}px;
525
531
  background-color: ${e.color};
@@ -561,7 +567,7 @@
561
567
  ${this._cachedCells.map(({width:e,color:n})=>t.html`<div
562
568
  style="width: ${e}px; background-color: ${n}; flex-shrink: 0;"
563
569
  ></div>`)}
564
- `}};H([(0,n.property)({type:Object})],G.prototype,`option`,void 0),H([(0,n.property)({type:String})],G.prototype,`theme`,void 0),H([(0,n.property)({type:String})],G.prototype,`rowId`,void 0),G=H([(0,n.customElement)(`gantt-row-background`)],G);var K=class extends t.LitElement{constructor(...e){super(...e),this.isDragTarget=!1,this.draggingTask=null,this.draggingTaskIds=[],this.multiDragDx=0,this.multiDragDy=0,this.multiDragSameRow=!1,this.externalDragTask=null,this.theme=`light`,this.isSelected=!1,this.dropPosition=null,this.selectedTaskIds=[],this.focusedTaskId=null,this.isExporting=!1,this.criticalPathTaskIds=[],this._cachedMonthGridLines=null,this._cachedMonthGridStartTime=0,this._cachedMonthGridEndTime=0,this._cachedMonthGridPxPerDay=0,this._cachedMonthGridPxPerMonth=0}getDateX(e){return P(e,this.option.calendar.start,this.option.calendar.pxPerDay,this.option.calendar.pxPerMonth)}getMarkerPath(e,t){let n=t/2;switch(e){case`triangle-up`:return`M 0 ${t} L ${n} 0 L ${t} ${t} Z`;case`triangle-down`:return`M 0 0 L ${t} 0 L ${n} ${t} Z`;case`triangle-left`:return`M ${t} 0 L 0 ${n} L ${t} ${t} Z`;case`triangle-right`:return`M 0 0 L ${t} ${n} L 0 ${t} Z`;case`diamond`:return`M ${n} 0 L ${t} ${n} L ${n} ${t} L 0 ${n} Z`;case`square`:return`M 0 0 L ${t} 0 L ${t} ${t} L 0 ${t} Z`;default:return`M 0 ${t} L ${n} 0 L ${t} ${t} Z`}}estimateMarkerWidth(e,t){let n=e.name?e.name.length*7+4:0;return e.anchor===`center`?t:t+n}getMarkerXRange(e,t){let n=this.getDateX(e.date),r=this.estimateMarkerWidth(e,t),i=e.anchor===`center`,a=e.anchor===`end`,o;if(o=e.anchor===`start`?n:e.anchor===`end`?n-t:n-t/2,i)return{left:o,right:o+t};if(a){let e=r-t;return{left:o-e,right:o+t}}return{left:o,right:o+r}}calculateMarkerLanes(e,t){if(!e.length)return[];let n=e.map(e=>({marker:e,range:this.getMarkerXRange(e,t)})).sort((e,t)=>e.range.left-t.range.left),r=[],i=[];for(let e of n){let t=-1;for(let n=0;n<r.length;n++)if(e.range.left>=r[n]+2){r[n]=e.range.right,t=n;break}t===-1&&(r.push(e.range.right),t=r.length-1),i.push({marker:e.marker,lane:t})}return i}static{this.styles=t.css`
570
+ `}};H([(0,n.property)({type:Object})],G.prototype,`option`,void 0),H([(0,n.property)({type:String})],G.prototype,`theme`,void 0),H([(0,n.property)({type:String})],G.prototype,`rowId`,void 0),G=H([(0,n.customElement)(`gantt-row-background`)],G);var K=class extends t.LitElement{constructor(...e){super(...e),this.isDragTarget=!1,this.draggingTask=null,this.draggingTaskIds=[],this.multiDragDx=0,this.multiDragDy=0,this.multiDragSameRow=!1,this.externalDragTask=null,this.theme=`light`,this.isSelected=!1,this.dropPosition=null,this.selectedTaskIds=[],this.focusedTaskId=null,this.isExporting=!1,this.criticalPathTaskIds=[],this._cachedMonthGridLines=null,this._cachedMonthGridStartTime=0,this._cachedMonthGridEndTime=0,this._cachedMonthGridPxPerDay=0,this._cachedMonthGridPxPerMonth=0,this._rowHeaderTooltipEl=null}getDateX(e){return P(e,this.option.calendar.start,this.option.calendar.pxPerDay,this.option.calendar.pxPerMonth)}getMarkerPath(e,t){let n=t/2;switch(e){case`triangle-up`:return`M 0 ${t} L ${n} 0 L ${t} ${t} Z`;case`triangle-down`:return`M 0 0 L ${t} 0 L ${n} ${t} Z`;case`triangle-left`:return`M ${t} 0 L 0 ${n} L ${t} ${t} Z`;case`triangle-right`:return`M 0 0 L ${t} ${n} L 0 ${t} Z`;case`diamond`:return`M ${n} 0 L ${t} ${n} L ${n} ${t} L 0 ${n} Z`;case`square`:return`M 0 0 L ${t} 0 L ${t} ${t} L 0 ${t} Z`;default:return`M 0 ${t} L ${n} 0 L ${t} ${t} Z`}}resolveMarkerFontSize(e){switch(e){case`xs`:return 8;case`sm`:return 10;case`md`:return 12;case`lg`:return 14;case`xl`:return 18;default:return 10}}estimateMarkerWidth(e,t){let n=this.resolveMarkerFontSize(e.fontSize)*.7,r=e.name?e.name.length*n+4:0;return e.anchor===`center`?t:t+r}getMarkerXRange(e,t){let n=this.getDateX(e.date),r=this.estimateMarkerWidth(e,t),i=e.anchor===`center`,a;return a=e.anchor===`start`?n:e.anchor===`end`?n-r:n-t/2,i?{left:a,right:a+t}:{left:a,right:a+r}}calculateMarkerLanes(e,t){if(!e.length)return[];let n=e.map(e=>({marker:e,range:this.getMarkerXRange(e,t)})).sort((e,t)=>e.range.left-t.range.left),r=[],i=[];for(let e of n){let t=-1;for(let n=0;n<r.length;n++)if(e.range.left>=r[n]+2){r[n]=e.range.right,t=n;break}t===-1&&(r.push(e.range.right),t=r.length-1),i.push({marker:e.marker,lane:t})}return i}static{this.styles=t.css`
565
571
  :host {
566
572
  display: block;
567
573
  width: fit-content;
@@ -624,6 +630,33 @@
624
630
  flex: none;
625
631
  position: relative;
626
632
  }
633
+ .marker-wrapper {
634
+ transition: transform 0.15s ease, filter 0.15s ease;
635
+ user-select: none;
636
+ -webkit-user-select: none;
637
+ }
638
+ .marker-wrapper.marker-anchor-end {
639
+ transform: translateX(-100%);
640
+ }
641
+ .marker-wrapper:hover {
642
+ transform: scale(1.3);
643
+ filter: brightness(1.15) drop-shadow(0 2px 6px rgba(0,0,0,0.4)) drop-shadow(0 0 8px rgba(255,255,255,0.5));
644
+ z-index: 10 !important;
645
+ }
646
+ .marker-wrapper.marker-anchor-end:hover {
647
+ transform: translateX(-100%) scale(1.3);
648
+ }
649
+ .marker-wrapper.marker-selected {
650
+ filter: brightness(1.2) drop-shadow(0 0 6px rgba(59,130,246,0.7)) drop-shadow(0 0 10px rgba(59,130,246,0.4));
651
+ z-index: 10 !important;
652
+ }
653
+ .marker-wrapper.marker-selected .marker-icon {
654
+ animation: marker-pulse 1.2s ease-in-out infinite;
655
+ }
656
+ @keyframes marker-pulse {
657
+ 0%, 100% { opacity: 1; }
658
+ 50% { opacity: 0.65; }
659
+ }
627
660
  .grid-background {
628
661
  position: absolute;
629
662
  top: 0;
@@ -632,7 +665,7 @@
632
665
  height: 100%;
633
666
  pointer-events: none;
634
667
  }
635
- `}handleDragStart(e){if(this.isSelected||this.dispatchEvent(new CustomEvent(`row-clicked`,{detail:{rowId:this.row.id,event:e},bubbles:!0,composed:!0})),e.dataTransfer){e.dataTransfer.setData(`text/plain`,this.row.id),e.dataTransfer.effectAllowed=`move`;let t=L(this.theme,this.option.customTheme),n=document.createElement(`div`);n.style.position=`absolute`,n.style.top=`-1000px`,n.style.left=`-1000px`,n.style.display=`flex`,n.style.flexDirection=`column`,n.style.zIndex=`9999`,n.style.width=`fit-content`,n.style.boxShadow=`0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)`,n.style.border=`1px solid ${t.border}`,n.style.borderRadius=`4px`,n.style.overflow=`hidden`;let r=[];if(this.isSelected){let e=this.getRootNode(),t=Array.from(e.querySelectorAll(`gantt-row[isselected]`));r=t.length>0?t:[this]}else r=[this];let i=r.slice(0,10);if(i.forEach((e,r)=>{let a=e.shadowRoot?.querySelector(`.row-header`);if(a){let o=a.cloneNode(!0),s=window.getComputedStyle(a);o.style.width=s.width,o.style.minWidth=s.minWidth,o.style.height=`${e.offsetHeight}px`,o.style.boxSizing=s.boxSizing,o.style.background=s.backgroundColor,o.style.color=s.color,o.style.fontSize=s.fontSize,o.style.display=s.display,o.style.alignItems=s.alignItems,o.style.padding=s.padding,o.style.border=`none`,o.style.borderBottom=r<i.length-1?`1px solid ${t.border}`:`none`,o.style.cursor=`grabbing`,n.appendChild(o)}}),r.length>10){let e=document.createElement(`div`);e.style.padding=`4px 8px`,e.style.background=t.bg,e.style.color=t.text,e.style.fontSize=`11px`,e.style.textAlign=`center`,e.textContent=`+ ${r.length-10} more`,n.appendChild(e)}document.body.appendChild(n),e.dataTransfer.setDragImage(n,0,0),setTimeout(()=>{document.body.removeChild(n)},0)}}handleHeaderClick(e){this.dispatchEvent(new CustomEvent(`row-clicked`,{detail:{rowId:this.row.id,event:e},bubbles:!0,composed:!0})),e.stopPropagation()}handleHeaderContextMenu(e){e.preventDefault(),this.dispatchEvent(new CustomEvent(`row-header-contextmenu`,{detail:{rowId:this.row.id,row:this.row,event:e,target:e.currentTarget},bubbles:!0,composed:!0}))}handleHeaderDblClick(e){this.dispatchEvent(new CustomEvent(`row-header-dblclick`,{detail:{rowId:this.row.id,row:this.row,event:e,target:e.currentTarget},bubbles:!0,composed:!0}))}updated(e){if(super.updated(e),!(e.has(`row`)||e.has(`option`)||e.has(`isSelected`)||e.has(`theme`)))return;let n=this.shadowRoot?.querySelector(`.row-header-content`);n&&(0,t.render)(this.option.customRendering?.rowHeaderContent?this.option.customRendering.rowHeaderContent(this.row):this.row.name,n)}render(){let e=L(this.theme,this.option.customTheme),n=[...this.row.tasks];if(this.externalDragTask){let e={...this.externalDragTask.task,start:this.externalDragTask.currentStart,end:this.externalDragTask.currentEnd,style:`${this.externalDragTask.task.style||``}; opacity: 0.6; pointer-events: none;`};n=[...n,e]}let r,a,o=this.row.tasks.find(e=>this.draggingTask&&e.id===this.draggingTask.id);if(this.draggingTask?.mode===`copy`&&o){let e=n.filter(e=>e.id!==this.draggingTask.id);e.push({...o,id:`${o.id}-static`,movable:`none`,resizable:!1,style:`${o.style||``}; opacity: 0.5;`});let t=I(e);r=t.tasksWithLanes,a=t.laneCount;let i=r.find(e=>e.id===`${o.id}-static`);i&&r.push({...o,lane:i.lane})}else{let e=I(n);r=e.tasksWithLanes,a=e.laneCount}let s=this.option.bar?.height??28,c=this.option.bar?.margin??4,l=this.row.markers??[],u=Math.min(s,12),d=u+2,f=this.calculateMarkerLanes(l,u),p=f.length>0?Math.max(...f.map(e=>e.lane))+1:0,m=a*(s+c)+c,h=m+(p>1?(p-1)*d:0);this.style.height=`${h}px`;let g=``,_=null,v=this.option.calendar.start.getTime(),y=this.option.calendar.end.getTime(),b=this.option.calendar.pxPerDay,x=this.option.calendar.pxPerMonth??0;if(!this._cachedMonthGridLines||v!==this._cachedMonthGridStartTime||y!==this._cachedMonthGridEndTime||b!==this._cachedMonthGridPxPerDay||x!==this._cachedMonthGridPxPerMonth){this._cachedMonthGridStartTime=v,this._cachedMonthGridEndTime=y,this._cachedMonthGridPxPerDay=b,this._cachedMonthGridPxPerMonth=x;let e=new Date(this.option.calendar.start),t=this.getDateX(e),n=this.option.calendar.end,r=new Date(n.getFullYear(),n.getMonth()+1,1),i=this.option.calendar.pxPerMonth===void 0?this.getDateX(n):this.getDateX(r),a=[],o=new Date(e);for(o.setDate(1),o.setHours(0,0,0,0);o<=r;){let e=this.getDateX(o);if(e>t&&e<=i){let t=o.getMonth()===0;a.push({left:e,isYearBoundary:t})}o.setMonth(o.getMonth()+1)}this._cachedMonthGridLines=a}if(_=this._cachedMonthGridLines,this.option.calendar.showMonthsRow)g=``;else if(this.option.calendar.showTime){let t=this.option.calendar.pxPerDay/24,n=this.option.snapDuration??60,r=this.option.calendar.pxPerDay/1440*n,i=this.option.calendar.pxPerDay,a=this.option.customTheme?.showTimeDateLine??e.monthGridLine??e.gridLine,o=this.option.calendar.start,s=(o.getHours()*60*60*1e3+o.getMinutes()*60*1e3+o.getSeconds()*1e3)/(1440*60*1e3)*i,c=s%t,l=s%r,u=s===0?`0px 0`:`${-s}px 0`,d=c===0?`0px 0`:`${-c}px 0`,f=l===0?`0px 0`:`${-l}px 0`,p=[`linear-gradient(90deg, transparent ${i-1}px, ${a} ${i-1}px)`,`linear-gradient(90deg, transparent ${t-1}px, ${e.gridLine} ${t-1}px)`,`linear-gradient(90deg, transparent ${r-1}px, ${e.subGridLine} ${r-1}px)`],m=[`${i}px 100%`,`${t}px 100%`,`${r}px 100%`],h=[u,d,f];g=`
668
+ `}handleDragStart(e){if(this.handleHeaderMouseLeave(),this.isSelected||this.dispatchEvent(new CustomEvent(`row-clicked`,{detail:{rowId:this.row.id,event:e},bubbles:!0,composed:!0})),e.dataTransfer){e.dataTransfer.setData(`text/plain`,this.row.id),e.dataTransfer.effectAllowed=`move`;let t=L(this.theme,this.option.customTheme),n=document.createElement(`div`);n.style.position=`absolute`,n.style.top=`-1000px`,n.style.left=`-1000px`,n.style.display=`flex`,n.style.flexDirection=`column`,n.style.zIndex=`9999`,n.style.width=`fit-content`,n.style.boxShadow=`0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06)`,n.style.border=`1px solid ${t.border}`,n.style.borderRadius=`4px`,n.style.overflow=`hidden`;let r=[];if(this.isSelected){let e=this.getRootNode(),t=Array.from(e.querySelectorAll(`gantt-row[isselected]`));r=t.length>0?t:[this]}else r=[this];let i=r.slice(0,10);if(i.forEach((e,r)=>{let a=e.shadowRoot?.querySelector(`.row-header`);if(a){let o=a.cloneNode(!0),s=window.getComputedStyle(a);o.style.width=s.width,o.style.minWidth=s.minWidth,o.style.height=`${e.offsetHeight}px`,o.style.boxSizing=s.boxSizing,o.style.background=s.backgroundColor,o.style.color=s.color,o.style.fontSize=s.fontSize,o.style.display=s.display,o.style.alignItems=s.alignItems,o.style.padding=s.padding,o.style.border=`none`,o.style.borderBottom=r<i.length-1?`1px solid ${t.border}`:`none`,o.style.cursor=`grabbing`,n.appendChild(o)}}),r.length>10){let e=document.createElement(`div`);e.style.padding=`4px 8px`,e.style.background=t.bg,e.style.color=t.text,e.style.fontSize=`11px`,e.style.textAlign=`center`,e.textContent=`+ ${r.length-10} more`,n.appendChild(e)}document.body.appendChild(n),e.dataTransfer.setDragImage(n,0,0),setTimeout(()=>{document.body.removeChild(n)},0)}}handleHeaderClick(e){this.dispatchEvent(new CustomEvent(`row-clicked`,{detail:{rowId:this.row.id,event:e},bubbles:!0,composed:!0})),e.stopPropagation()}handleHeaderContextMenu(e){e.preventDefault(),this.dispatchEvent(new CustomEvent(`row-header-contextmenu`,{detail:{rowId:this.row.id,row:this.row,event:e,target:e.currentTarget},bubbles:!0,composed:!0}))}handleHeaderDblClick(e){this.dispatchEvent(new CustomEvent(`row-header-dblclick`,{detail:{rowId:this.row.id,row:this.row,event:e,target:e.currentTarget},bubbles:!0,composed:!0}))}handleHeaderMouseEnter(e){let n=this.option.customRendering?.rowHeaderTooltip;if(!n)return;let r=this.option.tooltipDelay??500,i=e.currentTarget,a=()=>{let e=n(this.row);if(!e)return;let r=document.createElement(`div`);r.style.position=`fixed`,r.style.zIndex=`9999`,r.style.pointerEvents=`none`,r.style.opacity=`0`,r.style.transition=`opacity 0.15s ease`,r.style.maxWidth=`360px`,r.style.borderRadius=`8px`,r.style.padding=`8px 12px`,r.style.fontSize=`12px`,r.style.lineHeight=`1.5`,r.style.boxShadow=`0 4px 12px rgba(0,0,0,0.15)`;let a=L(this.theme,this.option.customTheme);r.style.backgroundColor=a.tooltipBg,r.style.color=a.tooltipText,typeof e==`string`?r.textContent=e:e instanceof HTMLElement?r.appendChild(e):(0,t.render)(e,r),document.body.appendChild(r),this._rowHeaderTooltipEl=r;let o=i.getBoundingClientRect(),s=r.getBoundingClientRect(),c=o.right+6,l=o.top;c+s.width>window.innerWidth-6&&(c=o.left-s.width-6),l+s.height>window.innerHeight-6&&(l=window.innerHeight-s.height-6),l<6&&(l=6),r.style.left=`${c}px`,r.style.top=`${l}px`,requestAnimationFrame(()=>{r.style.opacity=`1`})};r>0?this._rowHeaderTooltipTimer=window.setTimeout(a,r):a()}handleHeaderMouseLeave(){this._rowHeaderTooltipTimer!==void 0&&(window.clearTimeout(this._rowHeaderTooltipTimer),this._rowHeaderTooltipTimer=void 0),this._rowHeaderTooltipEl&&=(this._rowHeaderTooltipEl.remove(),null)}updated(e){if(super.updated(e),!(e.has(`row`)||e.has(`option`)||e.has(`isSelected`)||e.has(`theme`)))return;let n=this.shadowRoot?.querySelector(`.row-header-content`);n&&(0,t.render)(this.option.customRendering?.rowHeaderContent?this.option.customRendering.rowHeaderContent(this.row):this.row.name,n)}render(){let e=L(this.theme,this.option.customTheme),n=[...this.row.tasks];if(this.externalDragTask){let e={...this.externalDragTask.task,start:this.externalDragTask.currentStart,end:this.externalDragTask.currentEnd,style:`${this.externalDragTask.task.style||``}; opacity: 0.6; pointer-events: none;`};n=[...n,e]}let r,a,o=this.row.tasks.find(e=>this.draggingTask&&e.id===this.draggingTask.id);if(this.draggingTask?.mode===`copy`&&o){let e=n.filter(e=>e.id!==this.draggingTask.id);e.push({...o,id:`${o.id}-static`,movable:`none`,resizable:!1,style:`${o.style||``}; opacity: 0.5;`});let t=I(e);r=t.tasksWithLanes,a=t.laneCount;let i=r.find(e=>e.id===`${o.id}-static`);i&&r.push({...o,lane:i.lane})}else{let e=I(n);r=e.tasksWithLanes,a=e.laneCount}let s=this.option.bar?.height??28,c=this.option.bar?.margin??4,l=this.row.markers??[],u=Math.min(s,12),d=u+2,f=this.calculateMarkerLanes(l,u),p=f.length>0?Math.max(...f.map(e=>e.lane))+1:0,m=a*(s+c)+c,h=m+(p>1?(p-1)*d:0);this.style.height=`${h}px`;let g=``,_=null,v=this.option.calendar.start.getTime(),y=this.option.calendar.end.getTime(),b=this.option.calendar.pxPerDay,x=this.option.calendar.pxPerMonth??0;if(!this._cachedMonthGridLines||v!==this._cachedMonthGridStartTime||y!==this._cachedMonthGridEndTime||b!==this._cachedMonthGridPxPerDay||x!==this._cachedMonthGridPxPerMonth){this._cachedMonthGridStartTime=v,this._cachedMonthGridEndTime=y,this._cachedMonthGridPxPerDay=b,this._cachedMonthGridPxPerMonth=x;let e=new Date(this.option.calendar.start),t=this.getDateX(e),n=this.option.calendar.end,r=new Date(n.getFullYear(),n.getMonth()+1,1),i=this.option.calendar.pxPerMonth===void 0?this.getDateX(n):this.getDateX(r),a=[],o=new Date(e);for(o.setDate(1),o.setHours(0,0,0,0);o<=r;){let e=this.getDateX(o);if(e>t&&e<=i){let t=o.getMonth()===0;a.push({left:e,isYearBoundary:t})}o.setMonth(o.getMonth()+1)}this._cachedMonthGridLines=a}if(_=this._cachedMonthGridLines,this.option.calendar.showMonthsRow)g=``;else if(this.option.calendar.showTime){let t=this.option.calendar.pxPerDay/24,n=this.option.snapDuration??60,r=this.option.calendar.pxPerDay/1440*n,i=this.option.calendar.pxPerDay,a=this.option.customTheme?.showTimeDateLine??e.monthGridLine??e.gridLine,o=this.option.calendar.start,s=(o.getHours()*60*60*1e3+o.getMinutes()*60*1e3+o.getSeconds()*1e3)/(1440*60*1e3)*i,c=s%t,l=s%r,u=s===0?`0px 0`:`${-s}px 0`,d=c===0?`0px 0`:`${-c}px 0`,f=l===0?`0px 0`:`${-l}px 0`,p=[`linear-gradient(90deg, transparent ${i-1}px, ${a} ${i-1}px)`,`linear-gradient(90deg, transparent ${t-1}px, ${e.gridLine} ${t-1}px)`,`linear-gradient(90deg, transparent ${r-1}px, ${e.subGridLine} ${r-1}px)`],m=[`${i}px 100%`,`${t}px 100%`,`${r}px 100%`],h=[u,d,f];g=`
636
669
  background-image: ${p.join(`, `)};
637
670
  background-size: ${m.join(`, `)};
638
671
  background-position: ${h.join(`, `)};
@@ -691,6 +724,8 @@
691
724
  @click="${this.handleHeaderClick}"
692
725
  @dblclick="${this.handleHeaderDblClick}"
693
726
  @contextmenu="${this.handleHeaderContextMenu}"
727
+ @mouseenter="${this.handleHeaderMouseEnter}"
728
+ @mouseleave="${this.handleHeaderMouseLeave}"
694
729
  >
695
730
  <div
696
731
  class="row-header-content"
@@ -718,40 +753,42 @@
718
753
  .isCriticalPath="${this.criticalPathTaskIds.includes(e.id)}"
719
754
  />
720
755
  `})}
721
- ${f.map(({marker:e,lane:n})=>{let r=this.getDateX(e.date),i=e.color??`#ef4444`,a=e.anchor===`center`,o=(a?m/2-u:(m-u)/2)+n*d,s=e.anchor===`start`?r:e.anchor===`end`?r-u:r-u/2,c=e.anchor===`end`;return t.html`
756
+ ${f.map(({marker:e,lane:n})=>{let r=this.getDateX(e.date),i=e.color??`#ef4444`,a=this.resolveMarkerFontSize(e.fontSize),o=Math.min(s,Math.max(8,Math.round(a*1.2))),c=e.anchor===`center`,l=(c?m/2-o:(m-o)/2)+n*d,u=e.anchor===`start`||e.anchor===`end`?r:r-o/2,f=e.anchor===`end`,p=f;return t.html`
722
757
  <div
723
- class="marker-wrapper"
758
+ class="marker-wrapper${this.row.selectedMarkerId===e.id?` marker-selected`:``}${f?` marker-anchor-end`:``}"
724
759
  style="
725
760
  position: absolute;
726
- left: ${s}px;
727
- top: ${o}px;
761
+ left: ${u}px;
762
+ top: ${l}px;
728
763
  z-index: 2;
729
764
  display: flex;
730
- ${a?`flex-direction: column; align-items: center; width: ${u}px; overflow: visible;`:`align-items: center; ${c?`flex-direction: row-reverse;`:``}`}
765
+ ${c?`flex-direction: column; align-items: center; width: ${o}px; overflow: visible;`:`align-items: center; ${p?`flex-direction: row-reverse;`:``}`}
731
766
  pointer-events: auto;
732
- cursor: default;
767
+ cursor: pointer;
733
768
  white-space: nowrap;
734
769
  "
735
770
  title="${e.name??``}"
771
+ @dblclick="${t=>{t.preventDefault(),t.stopPropagation(),window.getSelection()?.removeAllRanges(),this.dispatchEvent(new CustomEvent(`marker-dblclick`,{detail:{marker:e,rowId:this.row.id,event:t},bubbles:!0,composed:!0}))}}"
772
+ @contextmenu="${t=>{t.preventDefault(),t.stopPropagation(),this.dispatchEvent(new CustomEvent(`marker-contextmenu`,{detail:{marker:e,rowId:this.row.id,event:t},bubbles:!0,composed:!0}))}}"
736
773
  >
737
774
  <svg
738
775
  class="marker-icon"
739
- width="${u}"
740
- height="${u}"
741
- viewBox="0 0 ${u} ${u}"
776
+ width="${o}"
777
+ height="${o}"
778
+ viewBox="0 0 ${o} ${o}"
742
779
  style="
743
780
  flex-shrink: 0;
744
781
  filter: drop-shadow(0 1px 2px rgba(0,0,0,0.3));
745
782
  ${e.style??``}
746
783
  "
747
784
  >
748
- <path d="${this.getMarkerPath(e.type,u)}" fill="${i}" />
785
+ <path d="${this.getMarkerPath(e.type,o)}" fill="${i}" />
749
786
  </svg>
750
787
  ${e.name?t.html`<span style="
751
- font-size: 10px;
788
+ font-size: ${a}px;
752
789
  color: ${i};
753
790
  line-height: 1;
754
- ${a?`padding: 1px 0 0 0;`:`padding: 0 2px;`}
791
+ ${c?`padding: 1px 0 0 0;`:`padding: 0 2px;`}
755
792
  ">${e.name}</span>`:``}
756
793
  </div>
757
794
  `})}
@@ -886,9 +923,12 @@
886
923
  position: absolute;
887
924
  z-index: 59;
888
925
  pointer-events: auto;
889
- transition: opacity 0.2s ease;
926
+ transition: opacity 0.2s ease, z-index 0s;
890
927
  cursor: default;
891
928
  }
929
+ .milestone-line.milestone-hovered {
930
+ z-index: 200;
931
+ }
892
932
  .cursor-line {
893
933
  position: absolute;
894
934
  width: 2px;
@@ -954,7 +994,7 @@
954
994
  ${n.dateFormat(this.tooltip.task.start)} - ${n.dateFormat(this.tooltip.task.end)}
955
995
  </div>
956
996
  <div class="tooltip-row">${n.tooltip.duration(i)}</div>
957
- `,e)}}}}updateDragOverlay(){if(!this.dragOverlayInfo||this.option.showDragInfoOverlay===!1)return;let e=L(this.theme,this.option.customTheme),n=this.shadowRoot?.querySelector(`.drag-info-overlay`);if(!n)return;n.classList.toggle(`visible`,this.dragOverlayInfo.visible);let{targetRow:r}=this.dragOverlayInfo,i=this.option.customRendering?.dragInfo?this.option.customRendering.dragInfo({id:this.dragOverlayInfo.id,name:this.dragOverlayInfo.name,start:this.dragOverlayInfo.start,end:this.dragOverlayInfo.end},this.dragOverlayInfo.currentStart,this.dragOverlayInfo.currentEnd,r):void 0;if(i)(0,t.render)(i,n);else{let i=this.option.locale??j,a=!!this.option.calendar.pxPerMonth,o,s;if(a){let e=new Date(this.dragOverlayInfo.currentEnd);e.setMonth(e.getMonth()-1),o=i.yearMonthFormat(this.dragOverlayInfo.currentStart),s=i.yearMonthFormat(e)}else o=i.dateTimeFormat(this.dragOverlayInfo.currentStart),s=i.dateTimeFormat(this.dragOverlayInfo.currentEnd);(0,t.render)(t.html`
997
+ `,e)}let r=e.getBoundingClientRect(),i=this.tooltip.x,a=this.tooltip.y;r.right>window.innerWidth-6&&(i=window.innerWidth-6-r.width/2),r.left<6&&(i=6+r.width/2),r.top<6&&(e.style.transform=`translate(-50%, 0)`,e.style.marginTop=`6px`),(i!==this.tooltip.x||a!==this.tooltip.y)&&(e.style.left=`${i}px`,e.style.top=`${a}px`)}}}updateDragOverlay(){if(!this.dragOverlayInfo||this.option.showDragInfoOverlay===!1)return;let e=L(this.theme,this.option.customTheme),n=this.shadowRoot?.querySelector(`.drag-info-overlay`);if(!n)return;n.classList.toggle(`visible`,this.dragOverlayInfo.visible);let{targetRow:r}=this.dragOverlayInfo,i=this.option.customRendering?.dragInfo?this.option.customRendering.dragInfo({id:this.dragOverlayInfo.id,name:this.dragOverlayInfo.name,start:this.dragOverlayInfo.start,end:this.dragOverlayInfo.end},this.dragOverlayInfo.currentStart,this.dragOverlayInfo.currentEnd,r):void 0;if(i)(0,t.render)(i,n);else{let i=this.option.locale??j,a=!!this.option.calendar.pxPerMonth,o,s;if(a){let e=new Date(this.dragOverlayInfo.currentEnd);e.setMonth(e.getMonth()-1),o=i.yearMonthFormat(this.dragOverlayInfo.currentStart),s=i.yearMonthFormat(e)}else o=i.dateTimeFormat(this.dragOverlayInfo.currentStart),s=i.dateTimeFormat(this.dragOverlayInfo.currentEnd);(0,t.render)(t.html`
958
998
  <div style="font-weight: bold;">
959
999
  ${this.dragOverlayInfo.name||i.dragOverlay.noTitle}
960
1000
  </div>
@@ -1076,7 +1116,7 @@
1076
1116
  `:``}
1077
1117
  ${(this.option.calendar.milestones??[]).map(e=>t.html`
1078
1118
  <div
1079
- class="milestone-line"
1119
+ class="milestone-line ${this.hoveredMilestoneId===e.id?`milestone-hovered`:``}"
1080
1120
  style="
1081
1121
  top: ${this.calendarHeight}px;
1082
1122
  left: ${this.getDateX(e.start)+o}px;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mogura/moguchart-core",
3
- "version": "0.7.0",
3
+ "version": "0.8.0",
4
4
  "description": "A lightweight, framework-agnostic Gantt chart Web Component built with Lit. Works with Vue, React, Angular, Svelte, and more.",
5
5
  "license": "MIT",
6
6
  "author": "Murakami Hiroyuki",
@@ -41,18 +41,6 @@
41
41
  "require": "./dist/moguchart-core.umd.js"
42
42
  }
43
43
  },
44
- "scripts": {
45
- "dev": "vite",
46
- "build": "vite build && pnpm exec tsc -p tsconfig.build.json",
47
- "build:demo": "BUILD_MODE=demo vite build && pnpm exec tsc",
48
- "preview": "vite preview",
49
- "prepublishOnly": "pnpm run build",
50
- "test": "vitest",
51
- "test:run": "vitest run",
52
- "test:ui": "vitest --ui",
53
- "test:coverage": "vitest run --coverage",
54
- "refresh:packages": "rm -rf node_modules pnpm-lock.yaml && pnpm i"
55
- },
56
44
  "devDependencies": {
57
45
  "@holiday-jp/holiday_jp": "^2.5.1",
58
46
  "@types/lodash-es": "^4.17.12",
@@ -72,5 +60,16 @@
72
60
  "html2canvas-pro": "^2.0.2",
73
61
  "jspdf": "^4.2.1",
74
62
  "lodash-es": "^4.17.21"
63
+ },
64
+ "scripts": {
65
+ "dev": "vite",
66
+ "build": "vite build && pnpm exec tsc -p tsconfig.build.json",
67
+ "build:demo": "BUILD_MODE=demo vite build && pnpm exec tsc",
68
+ "preview": "vite preview",
69
+ "test": "vitest",
70
+ "test:run": "vitest run",
71
+ "test:ui": "vitest --ui",
72
+ "test:coverage": "vitest run --coverage",
73
+ "refresh:packages": "rm -rf node_modules pnpm-lock.yaml && pnpm i"
75
74
  }
76
75
  }