web-mojo 2.2.100 → 2.2.102

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 (195) hide show
  1. package/CHANGELOG.md +598 -0
  2. package/README.md +2 -2
  3. package/dist/admin-models.cjs.js +2 -0
  4. package/dist/admin-models.cjs.js.map +1 -0
  5. package/dist/admin-models.es.js +2 -0
  6. package/dist/admin-models.es.js.map +1 -0
  7. package/dist/admin.cjs.js +1 -1
  8. package/dist/admin.css +42 -0
  9. package/dist/admin.es.js +1 -1
  10. package/dist/auth.cjs.js +1 -1
  11. package/dist/auth.es.js +1 -1
  12. package/dist/charts.cjs.js +1 -1
  13. package/dist/charts.cjs.js.map +1 -1
  14. package/dist/charts.css +897 -1
  15. package/dist/charts.es.js +1 -1
  16. package/dist/charts.es.js.map +1 -1
  17. package/dist/chat.css +96 -0
  18. package/dist/chunks/AssistantPanelView-CMRTtoqS.js +2 -0
  19. package/dist/chunks/AssistantPanelView-CMRTtoqS.js.map +1 -0
  20. package/dist/chunks/AssistantPanelView-CaVkWhVD.js +2 -0
  21. package/dist/chunks/AssistantPanelView-CaVkWhVD.js.map +1 -0
  22. package/dist/chunks/ChatView-B73uox2v.js +2 -0
  23. package/dist/chunks/ChatView-B73uox2v.js.map +1 -0
  24. package/dist/chunks/ChatView-W8daOwIo.js +2 -0
  25. package/dist/chunks/ChatView-W8daOwIo.js.map +1 -0
  26. package/dist/chunks/Collection-BZlmtcuL.js +2 -0
  27. package/dist/chunks/Collection-BZlmtcuL.js.map +1 -0
  28. package/dist/chunks/Collection-Bwoq6muu.js +2 -0
  29. package/dist/chunks/Collection-Bwoq6muu.js.map +1 -0
  30. package/dist/chunks/ContextMenu-BPPtuqKk.js +2 -0
  31. package/dist/chunks/ContextMenu-BPPtuqKk.js.map +1 -0
  32. package/dist/chunks/ContextMenu-q76hjQb6.js +2 -0
  33. package/dist/chunks/ContextMenu-q76hjQb6.js.map +1 -0
  34. package/dist/chunks/DataView-BbrwHMV4.js +2 -0
  35. package/dist/chunks/{DataView-6lhf855r.js.map → DataView-BbrwHMV4.js.map} +1 -1
  36. package/dist/chunks/DataView-k-7wmk5_.js +2 -0
  37. package/dist/chunks/{DataView-Bb83ww5U.js.map → DataView-k-7wmk5_.js.map} +1 -1
  38. package/dist/chunks/FormView-DPSuwWMq.js +3 -0
  39. package/dist/chunks/{FormView-DEROOklJ.js.map → FormView-DPSuwWMq.js.map} +1 -1
  40. package/dist/chunks/FormView-Dcy7XOtC.js +3 -0
  41. package/dist/chunks/{FormView-UmvPskWT.js.map → FormView-Dcy7XOtC.js.map} +1 -1
  42. package/dist/chunks/ListView-DHC-yBIw.js +2 -0
  43. package/dist/chunks/ListView-DHC-yBIw.js.map +1 -0
  44. package/dist/chunks/ListView-iGBsD4a7.js +2 -0
  45. package/dist/chunks/ListView-iGBsD4a7.js.map +1 -0
  46. package/dist/chunks/MetricsCountryMapView-CAD9wR_T.js +2 -0
  47. package/dist/chunks/MetricsCountryMapView-CAD9wR_T.js.map +1 -0
  48. package/dist/chunks/MetricsCountryMapView-Dzk3Yrzx.js +2 -0
  49. package/dist/chunks/MetricsCountryMapView-Dzk3Yrzx.js.map +1 -0
  50. package/dist/chunks/Modal-DBJU16cc.js +3 -0
  51. package/dist/chunks/Modal-DBJU16cc.js.map +1 -0
  52. package/dist/chunks/Modal-DuULCMFZ.js +3 -0
  53. package/dist/chunks/Modal-DuULCMFZ.js.map +1 -0
  54. package/dist/chunks/Passkeys-CGRZ8ZMv.js +2 -0
  55. package/dist/chunks/{Passkeys-CIRjqi7n.js.map → Passkeys-CGRZ8ZMv.js.map} +1 -1
  56. package/dist/chunks/Passkeys-Dr8-oSm9.js +2 -0
  57. package/dist/chunks/{Passkeys-BPV1gNkR.js.map → Passkeys-Dr8-oSm9.js.map} +1 -1
  58. package/dist/chunks/TokenManager-CFsr1qUV.js +2 -0
  59. package/dist/chunks/TokenManager-CFsr1qUV.js.map +1 -0
  60. package/dist/chunks/TokenManager-CHQxK_e5.js +2 -0
  61. package/dist/chunks/TokenManager-CHQxK_e5.js.map +1 -0
  62. package/dist/chunks/User-DNQhdBtI.js +2 -0
  63. package/dist/chunks/User-DNQhdBtI.js.map +1 -0
  64. package/dist/chunks/User-Dg7xpYEI.js +2 -0
  65. package/dist/chunks/User-Dg7xpYEI.js.map +1 -0
  66. package/dist/chunks/UserProfileView-B5nczdfw.js +2 -0
  67. package/dist/chunks/UserProfileView-B5nczdfw.js.map +1 -0
  68. package/dist/chunks/UserProfileView-Bpz3VZmP.js +2 -0
  69. package/dist/chunks/UserProfileView-Bpz3VZmP.js.map +1 -0
  70. package/dist/chunks/View-C5n3sIFi.js +2 -0
  71. package/dist/chunks/View-C5n3sIFi.js.map +1 -0
  72. package/dist/chunks/View-Yazho7OL.js +2 -0
  73. package/dist/chunks/View-Yazho7OL.js.map +1 -0
  74. package/dist/chunks/WebApp-CeiDNV6L.js +2 -0
  75. package/dist/chunks/WebApp-CeiDNV6L.js.map +1 -0
  76. package/dist/chunks/WebApp-irKlhuFX.js +2 -0
  77. package/dist/chunks/WebApp-irKlhuFX.js.map +1 -0
  78. package/dist/chunks/admin-BkxeK68u.js +2 -0
  79. package/dist/chunks/admin-BkxeK68u.js.map +1 -0
  80. package/dist/chunks/admin-vjoNbv_1.js +2 -0
  81. package/dist/chunks/admin-vjoNbv_1.js.map +1 -0
  82. package/dist/chunks/exportChart-DbsHDCxw.js +2 -0
  83. package/dist/chunks/exportChart-DbsHDCxw.js.map +1 -0
  84. package/dist/chunks/exportChart-Dk8D_du5.js +2 -0
  85. package/dist/chunks/exportChart-Dk8D_du5.js.map +1 -0
  86. package/dist/chunks/index-BNjCQA7q.js +2 -0
  87. package/dist/chunks/{index-CSmG_P2r.js.map → index-BNjCQA7q.js.map} +1 -1
  88. package/dist/chunks/index-DBsIDOAa.js +2 -0
  89. package/dist/chunks/{index-uo77m1wt.js.map → index-DBsIDOAa.js.map} +1 -1
  90. package/dist/chunks/{version-CRfGMZSI.js → version-B0cBv8MN.js} +2 -2
  91. package/dist/chunks/{version-CRfGMZSI.js.map → version-B0cBv8MN.js.map} +1 -1
  92. package/dist/chunks/{version-D-5X69D6.js → version-DtqCY0ZY.js} +2 -2
  93. package/dist/chunks/{version-D-5X69D6.js.map → version-DtqCY0ZY.js.map} +1 -1
  94. package/dist/core.css +306 -0
  95. package/dist/css/web-mojo.css +1 -1
  96. package/dist/docit.cjs.js +1 -1
  97. package/dist/docit.cjs.js.map +1 -1
  98. package/dist/docit.es.js +1 -1
  99. package/dist/docit.es.js.map +1 -1
  100. package/dist/index.cjs.js +1 -1
  101. package/dist/index.cjs.js.map +1 -1
  102. package/dist/index.es.js +1 -1
  103. package/dist/index.es.js.map +1 -1
  104. package/dist/lightbox.cjs.js +1 -1
  105. package/dist/lightbox.cjs.js.map +1 -1
  106. package/dist/lightbox.es.js +1 -1
  107. package/dist/lightbox.es.js.map +1 -1
  108. package/dist/map.cjs.js +1 -1
  109. package/dist/map.cjs.js.map +1 -1
  110. package/dist/map.es.js +1 -1
  111. package/dist/map.es.js.map +1 -1
  112. package/dist/portal.css +86 -0
  113. package/dist/timeline.cjs.js +1 -1
  114. package/dist/timeline.cjs.js.map +1 -1
  115. package/dist/timeline.es.js +1 -1
  116. package/dist/timeline.es.js.map +1 -1
  117. package/dist/user-profile.cjs.js +1 -1
  118. package/dist/user-profile.es.js +1 -1
  119. package/dist/web-mojo.lite.iife.js +4185 -3872
  120. package/dist/web-mojo.lite.iife.js.map +1 -1
  121. package/dist/web-mojo.lite.iife.min.js +301 -323
  122. package/dist/web-mojo.lite.iife.min.js.map +1 -1
  123. package/package.json +7 -2
  124. package/dist/chunks/AssistantPanelView-CZhZmVSG.js +0 -2
  125. package/dist/chunks/AssistantPanelView-CZhZmVSG.js.map +0 -1
  126. package/dist/chunks/AssistantPanelView-WFHYQjq7.js +0 -2
  127. package/dist/chunks/AssistantPanelView-WFHYQjq7.js.map +0 -1
  128. package/dist/chunks/ChatView-Bj3Tvx7a.js +0 -2
  129. package/dist/chunks/ChatView-Bj3Tvx7a.js.map +0 -1
  130. package/dist/chunks/ChatView-Uoqp80PU.js +0 -2
  131. package/dist/chunks/ChatView-Uoqp80PU.js.map +0 -1
  132. package/dist/chunks/Collection-C39Oy2q0.js +0 -2
  133. package/dist/chunks/Collection-C39Oy2q0.js.map +0 -1
  134. package/dist/chunks/Collection-CyK0u557.js +0 -2
  135. package/dist/chunks/Collection-CyK0u557.js.map +0 -1
  136. package/dist/chunks/ContextMenu-D-C7V6J6.js +0 -2
  137. package/dist/chunks/ContextMenu-D-C7V6J6.js.map +0 -1
  138. package/dist/chunks/ContextMenu-hjqR1pGW.js +0 -2
  139. package/dist/chunks/ContextMenu-hjqR1pGW.js.map +0 -1
  140. package/dist/chunks/DataView-6lhf855r.js +0 -2
  141. package/dist/chunks/DataView-Bb83ww5U.js +0 -2
  142. package/dist/chunks/Dialog-B0r9puaZ.js +0 -3
  143. package/dist/chunks/Dialog-B0r9puaZ.js.map +0 -1
  144. package/dist/chunks/Dialog-GzCkpMad.js +0 -3
  145. package/dist/chunks/Dialog-GzCkpMad.js.map +0 -1
  146. package/dist/chunks/FormView-DEROOklJ.js +0 -3
  147. package/dist/chunks/FormView-UmvPskWT.js +0 -3
  148. package/dist/chunks/ListView-D_hOtfWZ.js +0 -2
  149. package/dist/chunks/ListView-D_hOtfWZ.js.map +0 -1
  150. package/dist/chunks/ListView-Jkke6pU1.js +0 -2
  151. package/dist/chunks/ListView-Jkke6pU1.js.map +0 -1
  152. package/dist/chunks/MetricsCountryMapView-UdvJWArx.js +0 -2
  153. package/dist/chunks/MetricsCountryMapView-UdvJWArx.js.map +0 -1
  154. package/dist/chunks/MetricsCountryMapView-jLWCL6Hm.js +0 -2
  155. package/dist/chunks/MetricsCountryMapView-jLWCL6Hm.js.map +0 -1
  156. package/dist/chunks/MetricsMiniChartWidget-CV-McxOl.js +0 -2
  157. package/dist/chunks/MetricsMiniChartWidget-CV-McxOl.js.map +0 -1
  158. package/dist/chunks/MetricsMiniChartWidget-DG0DeDuR.js +0 -2
  159. package/dist/chunks/MetricsMiniChartWidget-DG0DeDuR.js.map +0 -1
  160. package/dist/chunks/MiniPieChart-B3sM4Bjv.js +0 -2
  161. package/dist/chunks/MiniPieChart-B3sM4Bjv.js.map +0 -1
  162. package/dist/chunks/MiniPieChart-DL5Rynvm.js +0 -2
  163. package/dist/chunks/MiniPieChart-DL5Rynvm.js.map +0 -1
  164. package/dist/chunks/MiniSeriesChart-C4DPVbU_.js +0 -2
  165. package/dist/chunks/MiniSeriesChart-C4DPVbU_.js.map +0 -1
  166. package/dist/chunks/MiniSeriesChart-DdNMLwfh.js +0 -2
  167. package/dist/chunks/MiniSeriesChart-DdNMLwfh.js.map +0 -1
  168. package/dist/chunks/Modal-jWZGSSOo.js +0 -2
  169. package/dist/chunks/Modal-jWZGSSOo.js.map +0 -1
  170. package/dist/chunks/Modal-xSaurlfZ.js +0 -2
  171. package/dist/chunks/Modal-xSaurlfZ.js.map +0 -1
  172. package/dist/chunks/Passkeys-BPV1gNkR.js +0 -2
  173. package/dist/chunks/Passkeys-CIRjqi7n.js +0 -2
  174. package/dist/chunks/TokenManager-CKgK0MIz.js +0 -2
  175. package/dist/chunks/TokenManager-CKgK0MIz.js.map +0 -1
  176. package/dist/chunks/TokenManager-Cu0YmxAx.js +0 -2
  177. package/dist/chunks/TokenManager-Cu0YmxAx.js.map +0 -1
  178. package/dist/chunks/UserProfileView-BXT8COCF.js +0 -2
  179. package/dist/chunks/UserProfileView-BXT8COCF.js.map +0 -1
  180. package/dist/chunks/UserProfileView-Slj-9C__.js +0 -2
  181. package/dist/chunks/UserProfileView-Slj-9C__.js.map +0 -1
  182. package/dist/chunks/WebApp-CXkNqtZX.js +0 -2
  183. package/dist/chunks/WebApp-CXkNqtZX.js.map +0 -1
  184. package/dist/chunks/WebApp-m6YeJFWY.js +0 -2
  185. package/dist/chunks/WebApp-m6YeJFWY.js.map +0 -1
  186. package/dist/chunks/WebSocketClient-BQAZr8C4.js +0 -2
  187. package/dist/chunks/WebSocketClient-BQAZr8C4.js.map +0 -1
  188. package/dist/chunks/WebSocketClient-YR5d82h8.js +0 -2
  189. package/dist/chunks/WebSocketClient-YR5d82h8.js.map +0 -1
  190. package/dist/chunks/admin-CpLR06pX.js +0 -2
  191. package/dist/chunks/admin-CpLR06pX.js.map +0 -1
  192. package/dist/chunks/admin-JtLeoEHZ.js +0 -2
  193. package/dist/chunks/admin-JtLeoEHZ.js.map +0 -1
  194. package/dist/chunks/index-CSmG_P2r.js +0 -2
  195. package/dist/chunks/index-uo77m1wt.js +0 -2
@@ -1 +0,0 @@
1
- {"version":3,"file":"MiniPieChart-B3sM4Bjv.js","sources":["../../src/extensions/charts/MiniPieChart.js"],"sourcesContent":["/**\n * MiniPieChart - Lightweight SVG pie chart component\n * Renders pie/doughnut charts with legend, no Chart.js dependency.\n * Uses SVG for crisp rendering at any size — perfect for inline/embedded use.\n */\n\nimport View from '@core/View.js';\nimport dataFormatter from '@core/utils/DataFormatter.js';\n\nconst DEFAULT_COLORS = [\n '#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF',\n '#FF9F40', '#C9CBCF', '#66BB6A', '#EF5350', '#AB47BC'\n];\n\nexport default class MiniPieChart extends View {\n constructor(options = {}) {\n super({\n className: 'mini-pie-chart',\n ...options\n });\n\n // Dimensions\n this.width = options.width || 200;\n this.height = options.height || 200;\n\n // Doughnut: 0 = solid pie, 0–1 = fraction of radius for hole\n this.cutout = options.cutout || 0;\n\n // Colors\n this.colors = options.colors || DEFAULT_COLORS;\n\n // Legend\n this.showLegend = options.showLegend !== false;\n this.legendPosition = options.legendPosition || 'right'; // 'right', 'bottom'\n\n // Data — accepts Chart.js format { labels, datasets } or simple [{label,value}]\n this._rawData = options.data || null;\n\n // Tooltip\n this.showTooltip = options.showTooltip !== false;\n\n // Value formatting\n this.valueFormatter = options.valueFormatter || null;\n this.dataFormatter = dataFormatter;\n\n // Internals\n this._segments = [];\n }\n\n // ── template ──────────────────────────────────────────────────────\n\n getTemplate() {\n const layoutClass = this.legendPosition === 'bottom'\n ? 'mini-pie-layout-bottom'\n : 'mini-pie-layout-right';\n\n return `\n <div class=\"mini-pie-wrapper ${layoutClass}\">\n <div class=\"mini-pie-svg-area\" style=\"width:${this.width}px; height:${this.height}px;\">\n <svg class=\"mini-pie-svg\" viewBox=\"0 0 ${this.width} ${this.height}\"\n width=\"100%\" height=\"100%\" preserveAspectRatio=\"xMidYMid meet\">\n </svg>\n ${this.showTooltip ? '<div class=\"mini-pie-tooltip\" style=\"display:none;\"></div>' : ''}\n </div>\n ${this.showLegend ? '<div class=\"mini-pie-legend\"></div>' : ''}\n </div>\n `;\n }\n\n // ── lifecycle ─────────────────────────────────────────────────────\n\n async onAfterRender() {\n this.svg = this.element.querySelector('.mini-pie-svg');\n this.tooltipEl = this.element.querySelector('.mini-pie-tooltip');\n this.legendEl = this.element.querySelector('.mini-pie-legend');\n\n if (this._rawData) {\n this._parseData(this._rawData);\n this._renderPie();\n this._renderLegend();\n }\n }\n\n // ── public API ────────────────────────────────────────────────────\n\n setData(data) {\n this._rawData = data;\n this._parseData(data);\n if (this.svg) {\n this._renderPie();\n this._renderLegend();\n }\n }\n\n // ── data normalisation ────────────────────────────────────────────\n\n _parseData(data) {\n let labels = [];\n let values = [];\n\n if (Array.isArray(data)) {\n // [{label, value}, ...]\n labels = data.map(d => d.label);\n values = data.map(d => d.value);\n } else if (data && data.labels && data.datasets) {\n // Chart.js style { labels, datasets: [{ data }] }\n labels = data.labels;\n values = data.datasets[0]?.data || [];\n } else if (data && typeof data === 'object') {\n // { A: 10, B: 20 }\n labels = Object.keys(data);\n values = Object.values(data);\n }\n\n const total = values.reduce((s, v) => s + (v || 0), 0);\n this._segments = labels.map((label, i) => ({\n label,\n value: values[i] || 0,\n pct: total > 0 ? ((values[i] || 0) / total * 100) : 0,\n color: this.colors[i % this.colors.length]\n }));\n }\n\n // ── SVG rendering ─────────────────────────────────────────────────\n\n _renderPie() {\n if (!this.svg) return;\n this.svg.innerHTML = '';\n\n const cx = this.width / 2;\n const cy = this.height / 2;\n const outerR = Math.min(cx, cy) - 4; // 4px breathing room\n const innerR = this.cutout > 0 ? outerR * this.cutout : 0;\n\n if (this._segments.length === 0) return;\n\n // Single-segment edge case\n if (this._segments.length === 1) {\n const seg = this._segments[0];\n if (innerR > 0) {\n // Doughnut ring\n const ring = this._svgEl('circle', {\n cx, cy, r: (outerR + innerR) / 2,\n fill: 'none',\n stroke: seg.color,\n 'stroke-width': outerR - innerR\n });\n this.svg.appendChild(ring);\n } else {\n const circle = this._svgEl('circle', {\n cx, cy, r: outerR, fill: seg.color\n });\n this.svg.appendChild(circle);\n }\n this._setupHover();\n return;\n }\n\n let angle = -Math.PI / 2; // start at 12 o'clock\n\n this._segments.forEach((seg, i) => {\n const sliceAngle = (seg.pct / 100) * Math.PI * 2;\n if (sliceAngle <= 0) return;\n\n const startAngle = angle;\n const endAngle = angle + sliceAngle;\n const largeArc = sliceAngle > Math.PI ? 1 : 0;\n\n const x1Outer = cx + outerR * Math.cos(startAngle);\n const y1Outer = cy + outerR * Math.sin(startAngle);\n const x2Outer = cx + outerR * Math.cos(endAngle);\n const y2Outer = cy + outerR * Math.sin(endAngle);\n\n let d;\n if (innerR > 0) {\n const x1Inner = cx + innerR * Math.cos(endAngle);\n const y1Inner = cy + innerR * Math.sin(endAngle);\n const x2Inner = cx + innerR * Math.cos(startAngle);\n const y2Inner = cy + innerR * Math.sin(startAngle);\n\n d = [\n `M ${x1Outer} ${y1Outer}`,\n `A ${outerR} ${outerR} 0 ${largeArc} 1 ${x2Outer} ${y2Outer}`,\n `L ${x1Inner} ${y1Inner}`,\n `A ${innerR} ${innerR} 0 ${largeArc} 0 ${x2Inner} ${y2Inner}`,\n 'Z'\n ].join(' ');\n } else {\n d = [\n `M ${cx} ${cy}`,\n `L ${x1Outer} ${y1Outer}`,\n `A ${outerR} ${outerR} 0 ${largeArc} 1 ${x2Outer} ${y2Outer}`,\n 'Z'\n ].join(' ');\n }\n\n const path = this._svgEl('path', {\n d,\n fill: seg.color,\n stroke: 'var(--bs-body-bg, #fff)',\n 'stroke-width': 1.5,\n 'data-index': i,\n class: 'mini-pie-segment'\n });\n\n this.svg.appendChild(path);\n angle = endAngle;\n });\n\n this._setupHover();\n }\n\n _setupHover() {\n if (!this.showTooltip || !this.svg || !this.tooltipEl) return;\n\n const paths = this.svg.querySelectorAll('path, circle');\n paths.forEach((el, idx) => {\n el.addEventListener('mouseenter', (e) => this._showTooltip(idx, e));\n el.addEventListener('mousemove', (e) => this._moveTooltip(e));\n el.addEventListener('mouseleave', () => this._hideTooltip());\n });\n }\n\n _showTooltip(index, event) {\n const seg = this._segments[index] || this._segments[0];\n if (!seg || !this.tooltipEl) return;\n\n let displayValue = seg.value;\n if (this.valueFormatter) {\n displayValue = this.dataFormatter.pipe(seg.value, this.valueFormatter);\n } else {\n displayValue = typeof seg.value === 'number' ? seg.value.toLocaleString() : seg.value;\n }\n\n this.tooltipEl.innerHTML = `\n <strong>${this._esc(seg.label)}</strong><br>\n ${displayValue} (${seg.pct.toFixed(1)}%)\n `;\n this.tooltipEl.style.display = 'block';\n this._moveTooltip(event);\n }\n\n _moveTooltip(event) {\n if (!this.tooltipEl || this.tooltipEl.style.display === 'none') return;\n const area = this.element.querySelector('.mini-pie-svg-area');\n if (!area) return;\n const areaRect = area.getBoundingClientRect();\n const x = event.clientX - areaRect.left;\n const y = event.clientY - areaRect.top;\n\n // Render once to measure, then clamp within container\n this.tooltipEl.style.left = '0px';\n this.tooltipEl.style.top = '0px';\n this.tooltipEl.style.transform = 'none';\n const tw = this.tooltipEl.offsetWidth;\n const th = this.tooltipEl.offsetHeight;\n const aw = areaRect.width;\n const ah = areaRect.height;\n\n let left = x - tw / 2;\n let top = y - th - 8;\n // Clamp horizontally\n if (left < 0) left = 0;\n if (left + tw > aw) left = aw - tw;\n // Flip below cursor if too close to top\n if (top < 0) top = y + 12;\n // Clamp bottom\n if (top + th > ah) top = ah - th;\n\n this.tooltipEl.style.left = `${left}px`;\n this.tooltipEl.style.top = `${top}px`;\n }\n\n _hideTooltip() {\n if (this.tooltipEl) this.tooltipEl.style.display = 'none';\n }\n\n // ── legend ────────────────────────────────────────────────────────\n\n _renderLegend() {\n if (!this.showLegend || !this.legendEl) return;\n this.legendEl.innerHTML = '';\n\n this._segments.forEach(seg => {\n const item = document.createElement('div');\n item.className = 'mini-pie-legend-item';\n item.innerHTML = `\n <span class=\"mini-pie-legend-swatch\" style=\"background:${seg.color};\"></span>\n <span class=\"mini-pie-legend-label\">${this._esc(seg.label)}</span>\n <span class=\"mini-pie-legend-value\">${seg.pct.toFixed(1)}%</span>\n `;\n this.legendEl.appendChild(item);\n });\n }\n\n // ── helpers ───────────────────────────────────────────────────────\n\n _svgEl(tag, attrs = {}) {\n const el = document.createElementNS('http://www.w3.org/2000/svg', tag);\n for (const [k, v] of Object.entries(attrs)) {\n el.setAttribute(k, String(v));\n }\n return el;\n }\n\n _esc(text) {\n const d = document.createElement('div');\n d.textContent = text;\n return d.innerHTML;\n }\n}\n"],"names":["DEFAULT_COLORS","MiniPieChart","View","constructor","options","super","className","this","width","height","cutout","colors","showLegend","legendPosition","_rawData","data","showTooltip","valueFormatter","dataFormatter","_segments","getTemplate","onAfterRender","svg","element","querySelector","tooltipEl","legendEl","_parseData","_renderPie","_renderLegend","setData","labels","values","Array","isArray","map","d","label","value","datasets","Object","keys","total","reduce","s","v","i","pct","color","length","innerHTML","cx","cy","outerR","Math","min","innerR","seg","ring","_svgEl","r","fill","stroke","appendChild","circle","_setupHover","angle","PI","forEach","sliceAngle","startAngle","endAngle","largeArc","x1Outer","cos","y1Outer","sin","x2Outer","y2Outer","x1Inner","y1Inner","x2Inner","y2Inner","join","path","class","querySelectorAll","el","idx","addEventListener","e","_showTooltip","_moveTooltip","_hideTooltip","index","event","displayValue","pipe","toLocaleString","_esc","toFixed","style","display","area","areaRect","getBoundingClientRect","x","clientX","left","y","clientY","top","transform","tw","offsetWidth","th","offsetHeight","aw","ah","item","document","createElement","tag","attrs","createElementNS","k","entries","setAttribute","String","text","textContent"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{V as t,d as e}from"./Collection-C39Oy2q0.js";const i=["#FF6384","#36A2EB","#FFCE56","#4BC0C0","#9966FF","#FF9F40","#C9CBCF","#66BB6A","#EF5350","#AB47BC"];class MiniPieChart extends t{constructor(t={}){super({className:"mini-pie-chart",...t}),this.width=t.width||200,this.height=t.height||200,this.cutout=t.cutout||0,this.colors=t.colors||i,this.showLegend=!1!==t.showLegend,this.legendPosition=t.legendPosition||"right",this._rawData=t.data||null,this.showTooltip=!1!==t.showTooltip,this.valueFormatter=t.valueFormatter||null,this.dataFormatter=e,this._segments=[]}getTemplate(){return`\n <div class="mini-pie-wrapper ${"bottom"===this.legendPosition?"mini-pie-layout-bottom":"mini-pie-layout-right"}">\n <div class="mini-pie-svg-area" style="width:${this.width}px; height:${this.height}px;">\n <svg class="mini-pie-svg" viewBox="0 0 ${this.width} ${this.height}"\n width="100%" height="100%" preserveAspectRatio="xMidYMid meet">\n </svg>\n ${this.showTooltip?'<div class="mini-pie-tooltip" style="display:none;"></div>':""}\n </div>\n ${this.showLegend?'<div class="mini-pie-legend"></div>':""}\n </div>\n `}async onAfterRender(){this.svg=this.element.querySelector(".mini-pie-svg"),this.tooltipEl=this.element.querySelector(".mini-pie-tooltip"),this.legendEl=this.element.querySelector(".mini-pie-legend"),this._rawData&&(this._parseData(this._rawData),this._renderPie(),this._renderLegend())}setData(t){this._rawData=t,this._parseData(t),this.svg&&(this._renderPie(),this._renderLegend())}_parseData(t){let e=[],i=[];Array.isArray(t)?(e=t.map(t=>t.label),i=t.map(t=>t.value)):t&&t.labels&&t.datasets?(e=t.labels,i=t.datasets[0]?.data||[]):t&&"object"==typeof t&&(e=Object.keys(t),i=Object.values(t));const s=i.reduce((t,e)=>t+(e||0),0);this._segments=e.map((t,e)=>({label:t,value:i[e]||0,pct:s>0?(i[e]||0)/s*100:0,color:this.colors[e%this.colors.length]}))}_renderPie(){if(!this.svg)return;this.svg.innerHTML="";const t=this.width/2,e=this.height/2,i=Math.min(t,e)-4,s=this.cutout>0?i*this.cutout:0;if(0===this._segments.length)return;if(1===this._segments.length){const o=this._segments[0];if(s>0){const l=this._svgEl("circle",{cx:t,cy:e,r:(i+s)/2,fill:"none",stroke:o.color,"stroke-width":i-s});this.svg.appendChild(l)}else{const s=this._svgEl("circle",{cx:t,cy:e,r:i,fill:o.color});this.svg.appendChild(s)}return void this._setupHover()}let o=-Math.PI/2;this._segments.forEach((l,n)=>{const h=l.pct/100*Math.PI*2;if(h<=0)return;const a=o,r=o+h,p=h>Math.PI?1:0,c=t+i*Math.cos(a),d=e+i*Math.sin(a),g=t+i*Math.cos(r),m=e+i*Math.sin(r);let v;if(s>0){const o=t+s*Math.cos(r),l=e+s*Math.sin(r),n=t+s*Math.cos(a),h=e+s*Math.sin(a);v=[`M ${c} ${d}`,`A ${i} ${i} 0 ${p} 1 ${g} ${m}`,`L ${o} ${l}`,`A ${s} ${s} 0 ${p} 0 ${n} ${h}`,"Z"].join(" ")}else v=[`M ${t} ${e}`,`L ${c} ${d}`,`A ${i} ${i} 0 ${p} 1 ${g} ${m}`,"Z"].join(" ");const u=this._svgEl("path",{d:v,fill:l.color,stroke:"var(--bs-body-bg, #fff)","stroke-width":1.5,"data-index":n,class:"mini-pie-segment"});this.svg.appendChild(u),o=r}),this._setupHover()}_setupHover(){this.showTooltip&&this.svg&&this.tooltipEl&&this.svg.querySelectorAll("path, circle").forEach((t,e)=>{t.addEventListener("mouseenter",t=>this._showTooltip(e,t)),t.addEventListener("mousemove",t=>this._moveTooltip(t)),t.addEventListener("mouseleave",()=>this._hideTooltip())})}_showTooltip(t,e){const i=this._segments[t]||this._segments[0];if(!i||!this.tooltipEl)return;let s=i.value;s=this.valueFormatter?this.dataFormatter.pipe(i.value,this.valueFormatter):"number"==typeof i.value?i.value.toLocaleString():i.value,this.tooltipEl.innerHTML=`\n <strong>${this._esc(i.label)}</strong><br>\n ${s} (${i.pct.toFixed(1)}%)\n `,this.tooltipEl.style.display="block",this._moveTooltip(e)}_moveTooltip(t){if(!this.tooltipEl||"none"===this.tooltipEl.style.display)return;const e=this.element.querySelector(".mini-pie-svg-area");if(!e)return;const i=e.getBoundingClientRect(),s=t.clientX-i.left,o=t.clientY-i.top;this.tooltipEl.style.left="0px",this.tooltipEl.style.top="0px",this.tooltipEl.style.transform="none";const l=this.tooltipEl.offsetWidth,n=this.tooltipEl.offsetHeight,h=i.width,a=i.height;let r=s-l/2,p=o-n-8;r<0&&(r=0),r+l>h&&(r=h-l),p<0&&(p=o+12),p+n>a&&(p=a-n),this.tooltipEl.style.left=`${r}px`,this.tooltipEl.style.top=`${p}px`}_hideTooltip(){this.tooltipEl&&(this.tooltipEl.style.display="none")}_renderLegend(){this.showLegend&&this.legendEl&&(this.legendEl.innerHTML="",this._segments.forEach(t=>{const e=document.createElement("div");e.className="mini-pie-legend-item",e.innerHTML=`\n <span class="mini-pie-legend-swatch" style="background:${t.color};"></span>\n <span class="mini-pie-legend-label">${this._esc(t.label)}</span>\n <span class="mini-pie-legend-value">${t.pct.toFixed(1)}%</span>\n `,this.legendEl.appendChild(e)}))}_svgEl(t,e={}){const i=document.createElementNS("http://www.w3.org/2000/svg",t);for(const[s,o]of Object.entries(e))i.setAttribute(s,String(o));return i}_esc(t){const e=document.createElement("div");return e.textContent=t,e.innerHTML}}export{MiniPieChart as default};
2
- //# sourceMappingURL=MiniPieChart-DL5Rynvm.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"MiniPieChart-DL5Rynvm.js","sources":["../../src/extensions/charts/MiniPieChart.js"],"sourcesContent":["/**\n * MiniPieChart - Lightweight SVG pie chart component\n * Renders pie/doughnut charts with legend, no Chart.js dependency.\n * Uses SVG for crisp rendering at any size — perfect for inline/embedded use.\n */\n\nimport View from '@core/View.js';\nimport dataFormatter from '@core/utils/DataFormatter.js';\n\nconst DEFAULT_COLORS = [\n '#FF6384', '#36A2EB', '#FFCE56', '#4BC0C0', '#9966FF',\n '#FF9F40', '#C9CBCF', '#66BB6A', '#EF5350', '#AB47BC'\n];\n\nexport default class MiniPieChart extends View {\n constructor(options = {}) {\n super({\n className: 'mini-pie-chart',\n ...options\n });\n\n // Dimensions\n this.width = options.width || 200;\n this.height = options.height || 200;\n\n // Doughnut: 0 = solid pie, 0–1 = fraction of radius for hole\n this.cutout = options.cutout || 0;\n\n // Colors\n this.colors = options.colors || DEFAULT_COLORS;\n\n // Legend\n this.showLegend = options.showLegend !== false;\n this.legendPosition = options.legendPosition || 'right'; // 'right', 'bottom'\n\n // Data — accepts Chart.js format { labels, datasets } or simple [{label,value}]\n this._rawData = options.data || null;\n\n // Tooltip\n this.showTooltip = options.showTooltip !== false;\n\n // Value formatting\n this.valueFormatter = options.valueFormatter || null;\n this.dataFormatter = dataFormatter;\n\n // Internals\n this._segments = [];\n }\n\n // ── template ──────────────────────────────────────────────────────\n\n getTemplate() {\n const layoutClass = this.legendPosition === 'bottom'\n ? 'mini-pie-layout-bottom'\n : 'mini-pie-layout-right';\n\n return `\n <div class=\"mini-pie-wrapper ${layoutClass}\">\n <div class=\"mini-pie-svg-area\" style=\"width:${this.width}px; height:${this.height}px;\">\n <svg class=\"mini-pie-svg\" viewBox=\"0 0 ${this.width} ${this.height}\"\n width=\"100%\" height=\"100%\" preserveAspectRatio=\"xMidYMid meet\">\n </svg>\n ${this.showTooltip ? '<div class=\"mini-pie-tooltip\" style=\"display:none;\"></div>' : ''}\n </div>\n ${this.showLegend ? '<div class=\"mini-pie-legend\"></div>' : ''}\n </div>\n `;\n }\n\n // ── lifecycle ─────────────────────────────────────────────────────\n\n async onAfterRender() {\n this.svg = this.element.querySelector('.mini-pie-svg');\n this.tooltipEl = this.element.querySelector('.mini-pie-tooltip');\n this.legendEl = this.element.querySelector('.mini-pie-legend');\n\n if (this._rawData) {\n this._parseData(this._rawData);\n this._renderPie();\n this._renderLegend();\n }\n }\n\n // ── public API ────────────────────────────────────────────────────\n\n setData(data) {\n this._rawData = data;\n this._parseData(data);\n if (this.svg) {\n this._renderPie();\n this._renderLegend();\n }\n }\n\n // ── data normalisation ────────────────────────────────────────────\n\n _parseData(data) {\n let labels = [];\n let values = [];\n\n if (Array.isArray(data)) {\n // [{label, value}, ...]\n labels = data.map(d => d.label);\n values = data.map(d => d.value);\n } else if (data && data.labels && data.datasets) {\n // Chart.js style { labels, datasets: [{ data }] }\n labels = data.labels;\n values = data.datasets[0]?.data || [];\n } else if (data && typeof data === 'object') {\n // { A: 10, B: 20 }\n labels = Object.keys(data);\n values = Object.values(data);\n }\n\n const total = values.reduce((s, v) => s + (v || 0), 0);\n this._segments = labels.map((label, i) => ({\n label,\n value: values[i] || 0,\n pct: total > 0 ? ((values[i] || 0) / total * 100) : 0,\n color: this.colors[i % this.colors.length]\n }));\n }\n\n // ── SVG rendering ─────────────────────────────────────────────────\n\n _renderPie() {\n if (!this.svg) return;\n this.svg.innerHTML = '';\n\n const cx = this.width / 2;\n const cy = this.height / 2;\n const outerR = Math.min(cx, cy) - 4; // 4px breathing room\n const innerR = this.cutout > 0 ? outerR * this.cutout : 0;\n\n if (this._segments.length === 0) return;\n\n // Single-segment edge case\n if (this._segments.length === 1) {\n const seg = this._segments[0];\n if (innerR > 0) {\n // Doughnut ring\n const ring = this._svgEl('circle', {\n cx, cy, r: (outerR + innerR) / 2,\n fill: 'none',\n stroke: seg.color,\n 'stroke-width': outerR - innerR\n });\n this.svg.appendChild(ring);\n } else {\n const circle = this._svgEl('circle', {\n cx, cy, r: outerR, fill: seg.color\n });\n this.svg.appendChild(circle);\n }\n this._setupHover();\n return;\n }\n\n let angle = -Math.PI / 2; // start at 12 o'clock\n\n this._segments.forEach((seg, i) => {\n const sliceAngle = (seg.pct / 100) * Math.PI * 2;\n if (sliceAngle <= 0) return;\n\n const startAngle = angle;\n const endAngle = angle + sliceAngle;\n const largeArc = sliceAngle > Math.PI ? 1 : 0;\n\n const x1Outer = cx + outerR * Math.cos(startAngle);\n const y1Outer = cy + outerR * Math.sin(startAngle);\n const x2Outer = cx + outerR * Math.cos(endAngle);\n const y2Outer = cy + outerR * Math.sin(endAngle);\n\n let d;\n if (innerR > 0) {\n const x1Inner = cx + innerR * Math.cos(endAngle);\n const y1Inner = cy + innerR * Math.sin(endAngle);\n const x2Inner = cx + innerR * Math.cos(startAngle);\n const y2Inner = cy + innerR * Math.sin(startAngle);\n\n d = [\n `M ${x1Outer} ${y1Outer}`,\n `A ${outerR} ${outerR} 0 ${largeArc} 1 ${x2Outer} ${y2Outer}`,\n `L ${x1Inner} ${y1Inner}`,\n `A ${innerR} ${innerR} 0 ${largeArc} 0 ${x2Inner} ${y2Inner}`,\n 'Z'\n ].join(' ');\n } else {\n d = [\n `M ${cx} ${cy}`,\n `L ${x1Outer} ${y1Outer}`,\n `A ${outerR} ${outerR} 0 ${largeArc} 1 ${x2Outer} ${y2Outer}`,\n 'Z'\n ].join(' ');\n }\n\n const path = this._svgEl('path', {\n d,\n fill: seg.color,\n stroke: 'var(--bs-body-bg, #fff)',\n 'stroke-width': 1.5,\n 'data-index': i,\n class: 'mini-pie-segment'\n });\n\n this.svg.appendChild(path);\n angle = endAngle;\n });\n\n this._setupHover();\n }\n\n _setupHover() {\n if (!this.showTooltip || !this.svg || !this.tooltipEl) return;\n\n const paths = this.svg.querySelectorAll('path, circle');\n paths.forEach((el, idx) => {\n el.addEventListener('mouseenter', (e) => this._showTooltip(idx, e));\n el.addEventListener('mousemove', (e) => this._moveTooltip(e));\n el.addEventListener('mouseleave', () => this._hideTooltip());\n });\n }\n\n _showTooltip(index, event) {\n const seg = this._segments[index] || this._segments[0];\n if (!seg || !this.tooltipEl) return;\n\n let displayValue = seg.value;\n if (this.valueFormatter) {\n displayValue = this.dataFormatter.pipe(seg.value, this.valueFormatter);\n } else {\n displayValue = typeof seg.value === 'number' ? seg.value.toLocaleString() : seg.value;\n }\n\n this.tooltipEl.innerHTML = `\n <strong>${this._esc(seg.label)}</strong><br>\n ${displayValue} (${seg.pct.toFixed(1)}%)\n `;\n this.tooltipEl.style.display = 'block';\n this._moveTooltip(event);\n }\n\n _moveTooltip(event) {\n if (!this.tooltipEl || this.tooltipEl.style.display === 'none') return;\n const area = this.element.querySelector('.mini-pie-svg-area');\n if (!area) return;\n const areaRect = area.getBoundingClientRect();\n const x = event.clientX - areaRect.left;\n const y = event.clientY - areaRect.top;\n\n // Render once to measure, then clamp within container\n this.tooltipEl.style.left = '0px';\n this.tooltipEl.style.top = '0px';\n this.tooltipEl.style.transform = 'none';\n const tw = this.tooltipEl.offsetWidth;\n const th = this.tooltipEl.offsetHeight;\n const aw = areaRect.width;\n const ah = areaRect.height;\n\n let left = x - tw / 2;\n let top = y - th - 8;\n // Clamp horizontally\n if (left < 0) left = 0;\n if (left + tw > aw) left = aw - tw;\n // Flip below cursor if too close to top\n if (top < 0) top = y + 12;\n // Clamp bottom\n if (top + th > ah) top = ah - th;\n\n this.tooltipEl.style.left = `${left}px`;\n this.tooltipEl.style.top = `${top}px`;\n }\n\n _hideTooltip() {\n if (this.tooltipEl) this.tooltipEl.style.display = 'none';\n }\n\n // ── legend ────────────────────────────────────────────────────────\n\n _renderLegend() {\n if (!this.showLegend || !this.legendEl) return;\n this.legendEl.innerHTML = '';\n\n this._segments.forEach(seg => {\n const item = document.createElement('div');\n item.className = 'mini-pie-legend-item';\n item.innerHTML = `\n <span class=\"mini-pie-legend-swatch\" style=\"background:${seg.color};\"></span>\n <span class=\"mini-pie-legend-label\">${this._esc(seg.label)}</span>\n <span class=\"mini-pie-legend-value\">${seg.pct.toFixed(1)}%</span>\n `;\n this.legendEl.appendChild(item);\n });\n }\n\n // ── helpers ───────────────────────────────────────────────────────\n\n _svgEl(tag, attrs = {}) {\n const el = document.createElementNS('http://www.w3.org/2000/svg', tag);\n for (const [k, v] of Object.entries(attrs)) {\n el.setAttribute(k, String(v));\n }\n return el;\n }\n\n _esc(text) {\n const d = document.createElement('div');\n d.textContent = text;\n return d.innerHTML;\n }\n}\n"],"names":["DEFAULT_COLORS","MiniPieChart","View","constructor","options","super","className","this","width","height","cutout","colors","showLegend","legendPosition","_rawData","data","showTooltip","valueFormatter","dataFormatter","_segments","getTemplate","onAfterRender","svg","element","querySelector","tooltipEl","legendEl","_parseData","_renderPie","_renderLegend","setData","labels","values","Array","isArray","map","d","label","value","datasets","Object","keys","total","reduce","s","v","i","pct","color","length","innerHTML","cx","cy","outerR","Math","min","innerR","seg","ring","_svgEl","r","fill","stroke","appendChild","circle","_setupHover","angle","PI","forEach","sliceAngle","startAngle","endAngle","largeArc","x1Outer","cos","y1Outer","sin","x2Outer","y2Outer","x1Inner","y1Inner","x2Inner","y2Inner","join","path","class","querySelectorAll","el","idx","addEventListener","e","_showTooltip","_moveTooltip","_hideTooltip","index","event","displayValue","pipe","toLocaleString","_esc","toFixed","style","display","area","areaRect","getBoundingClientRect","x","clientX","left","y","clientY","top","transform","tw","offsetWidth","th","offsetHeight","aw","ah","item","document","createElement","tag","attrs","createElementNS","k","entries","setAttribute","String","text","textContent"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{V as t,d as s}from"./Collection-C39Oy2q0.js";const e=["#36A2EB","#FF6384","#FFCE56","#4BC0C0","#9966FF","#FF9F40","#66BB6A","#EF5350","#AB47BC","#26C6DA"],i=["rgba(54,162,235,0.15)","rgba(255,99,132,0.15)","rgba(255,206,86,0.15)","rgba(75,192,192,0.15)","rgba(153,102,255,0.15)","rgba(255,159,64,0.15)","rgba(102,187,106,0.15)","rgba(239,83,80,0.15)","rgba(171,71,188,0.15)","rgba(38,198,218,0.15)"];class MiniSeriesChart extends t{constructor(t={}){super({className:"mini-series-chart",...t}),this.chartType=t.chartType||"line",this.width=t.width||"100%",this.height=t.height||200,this.padTop=10,this.padRight=12,this.padBottom=24,this.padLeft=40,this.strokeWidth=t.strokeWidth||2,this.smoothing=t.smoothing||.3,this.showDots=!1!==t.showDots,this.dotRadius=t.dotRadius||3,this.fill=t.fill??"area"===this.chartType,this.barGap=t.barGap||2,this.groupGap=t.groupGap||6,this.showGrid=!1!==t.showGrid,this.gridLines=t.gridLines||5,this.showLegend=!1!==t.showLegend,this.legendPosition=t.legendPosition||"top",this.showTooltip=!1!==t.showTooltip,this.colors=t.colors||e,this.fillColors=t.fillColors||i,this.valueFormatter=t.valueFormatter||null,this.dataFormatter=s,this._rawData=t.data||null,this._labels=[],this._datasets=[]}getTemplate(){const t="number"==typeof this.width?`${this.width}px`:this.width,s="number"==typeof this.height?`${this.height}px`:this.height;return`\n <div class="mini-series-wrapper">\n ${this.showLegend?'<div class="mini-series-legend"></div>':""}\n <div class="mini-series-svg-area" style="width:${t}; height:${s}; position:relative;">\n <svg class="mini-series-svg" width="100%" height="100%"\n preserveAspectRatio="none" style="display:block;">\n </svg>\n ${this.showTooltip?'<div class="mini-series-tooltip" style="display:none;"></div>':""}\n </div>\n </div>\n `}async onAfterRender(){this.svg=this.element.querySelector(".mini-series-svg"),this.tooltipEl=this.element.querySelector(".mini-series-tooltip"),this.legendEl=this.element.querySelector(".mini-series-legend"),this._updateDimensions(),this._setupResizeObserver(),this._rawData&&(this._parseData(this._rawData),this._renderChart(),this._renderLegend())}setData(t){this._rawData=t,this._parseData(t),this.svg&&(this._renderChart(),this._renderLegend())}_updateDimensions(){if(!this.svg)return;const t=this.svg.getBoundingClientRect();this._w=t.width||300,this._h=t.height||("number"==typeof this.height?this.height:200),this.svg.setAttribute("viewBox",`0 0 ${this._w} ${this._h}`)}_setupResizeObserver(){"undefined"!=typeof ResizeObserver&&(this._resizeObserver=new ResizeObserver(()=>{this._updateDimensions(),this._datasets.length>0&&this._renderChart()}),this.svg&&this._resizeObserver.observe(this.svg))}_parseData(t){if(!t)return this._labels=[],void(this._datasets=[]);t.labels&&t.datasets?(this._labels=t.labels||[],this._datasets=t.datasets.map((t,s)=>({label:t.label||`Series ${s+1}`,data:t.data||[],color:t.borderColor||t.color||this.colors[s%this.colors.length],fillColor:t.backgroundColor||this.fillColors[s%this.fillColors.length]}))):(this._labels=[],this._datasets=[])}get _plotLeft(){return this.padLeft}get _plotTop(){return this.padTop}get _plotRight(){return this._w-this.padRight}get _plotBottom(){return this._h-this.padBottom}get _plotW(){return this._plotRight-this._plotLeft}get _plotH(){return this._plotBottom-this._plotTop}_calcBounds(){let t=1/0,s=-1/0;for(const i of this._datasets)for(const e of i.data)e<t&&(t=e),e>s&&(s=e);isFinite(t)||(t=0,s=1),t===s&&(t-=1,s+=1);const e=s-t;return s+=.05*e,t>0&&(t=Math.max(0,t-.05*e)),{min:t,max:s}}_yToPixel(t,s,e){return this._plotBottom-(t-s)/(e-s)*this._plotH}_xToPixel(t,s){return s<=1?this._plotLeft+this._plotW/2:this._plotLeft+t/(s-1)*this._plotW}_renderChart(){if(!this.svg)return;if(this._updateDimensions(),this.svg.innerHTML="",0===this._datasets.length)return;const{min:t,max:s}=this._calcBounds(),e=this._labels.length||this._datasets[0]?.data.length||0;this._renderGrid(t,s),this._renderAxes(t,s,e),"bar"===this.chartType?this._renderBars(t,s,e):this._renderLines(t,s,e),this._attachHoverListeners()}_renderGrid(t,s){if(!this.showGrid)return;const e=this.gridLines;for(let i=0;i<=e;i++){const t=this._plotTop+i/e*this._plotH,s=this._svgEl("line",{x1:this._plotLeft,y1:t,x2:this._plotRight,y2:t,stroke:"var(--bs-border-color, #dee2e6)","stroke-width":.5,"stroke-dasharray":"3,3"});this.svg.appendChild(s)}}_renderAxes(t,s,e){const i=this.gridLines;for(let r=0;r<=i;r++){const e=s-r/i*(s-t),o=this._plotTop+r/i*this._plotH,h=this._formatAxisValue(e),l=this._svgEl("text",{x:this._plotLeft-4,y:o+3,"text-anchor":"end","font-size":"10",fill:"var(--bs-secondary-color, #6c757d)"});l.textContent=h,this.svg.appendChild(l)}const o=Math.floor(this._plotW/50),h=Math.max(1,Math.ceil(e/o));for(let r=0;r<e;r+=h){const t=this._xToPixel(r,e),s=this._svgEl("text",{x:t,y:this._plotBottom+14,"text-anchor":"middle","font-size":"10",fill:"var(--bs-secondary-color, #6c757d)"}),i=this._labels[r]||"";s.textContent=String(i).length>10?String(i).substring(0,9)+"…":i,this.svg.appendChild(s)}}_renderLines(t,s,e){this._datasets.forEach((i,o)=>{const h=i.data.map((i,o)=>({x:this._xToPixel(o,e),y:this._yToPixel(i,t,s)}));if(this.fill&&h.length>1){const t=this._buildLinePath(h)+` L ${h[h.length-1].x},${this._plotBottom} L ${h[0].x},${this._plotBottom} Z`,s=this._svgEl("path",{d:t,fill:i.fillColor,stroke:"none"});this.svg.appendChild(s)}if(h.length>1){const t=this._svgEl("path",{d:this._buildLinePath(h),fill:"none",stroke:i.color,"stroke-width":this.strokeWidth,"stroke-linecap":"round","stroke-linejoin":"round"});this.svg.appendChild(t)}this.showDots&&h.forEach((t,s)=>{const e=this._svgEl("circle",{cx:t.x,cy:t.y,r:this.dotRadius,fill:i.color,class:"mini-series-dot","data-col":s});this.svg.appendChild(e)})})}_renderBars(t,s,e){const i=this._datasets.length,o=this._plotW/e,h=o-this.groupGap,r=Math.max(1,(h-(i-1)*this.barGap)/i),l=this._yToPixel(Math.max(0,t),t,s);this._datasets.forEach((e,i)=>{e.data.forEach((h,n)=>{const a=this._plotLeft+n*o+this.groupGap/2+i*(r+this.barGap),d=this._yToPixel(h,t,s),p=Math.abs(l-d),g=this._svgEl("rect",{x:a,y:Math.min(d,l),width:r,height:Math.max(p,.5),fill:e.color,rx:1,class:"mini-series-bar","data-col":n});this.svg.appendChild(g)})})}_buildLinePath(t){if(0===t.length)return"";if(this.smoothing>0&&t.length>=2){let s=`M ${t[0].x},${t[0].y}`;for(let e=0;e<t.length-1;e++){const i=t[e],o=t[e+1],h=i.x+(o.x-i.x)*this.smoothing,r=o.x-(o.x-i.x)*this.smoothing;s+=` C ${h},${i.y} ${r},${o.y} ${o.x},${o.y}`}return s}return t.map((t,s)=>`${0===s?"M":"L"} ${t.x},${t.y}`).join(" ")}_attachHoverListeners(){this.showTooltip&&this.svg&&this.svg.querySelectorAll(".mini-series-bar, .mini-series-dot").forEach(t=>{const s=parseInt(t.getAttribute("data-col"),10);isNaN(s)||(t.addEventListener("mouseenter",t=>this._showTooltip(s,t)),t.addEventListener("mousemove",t=>this._moveTooltip(t)),t.addEventListener("mouseleave",()=>this._hideTooltip()))})}_showTooltip(t,s){if(!this.tooltipEl)return;const e=this._labels[t]||`#${t+1}`;let i=`<div class="mini-series-tooltip-label">${this._esc(String(e))}</div>`;this._datasets.forEach(s=>{const e=s.data[t];let o=e;this.valueFormatter?o=this.dataFormatter.pipe(e,this.valueFormatter):"number"==typeof e&&(o=e.toLocaleString()),i+=`<div class="mini-series-tooltip-row">\n <span class="mini-series-tooltip-swatch" style="background:${s.color}"></span>\n <span>${this._esc(s.label)}:</span>\n <strong>${o}</strong>\n </div>`}),this.tooltipEl.innerHTML=i,this.tooltipEl.style.display="block",this._moveTooltip(s)}_moveTooltip(t){if(!this.tooltipEl||"none"===this.tooltipEl.style.display)return;const s=this.element.querySelector(".mini-series-svg-area");if(!s)return;const e=s.getBoundingClientRect(),i=t.clientX-e.left,o=t.clientY-e.top;this.tooltipEl.style.left="0px",this.tooltipEl.style.top="0px",this.tooltipEl.style.transform="none";const h=this.tooltipEl.offsetWidth,r=this.tooltipEl.offsetHeight,l=e.width,n=e.height;let a=i-h/2,d=o-r-8;a<0&&(a=0),a+h>l&&(a=l-h),d<0&&(d=o+12),d+r>n&&(d=n-r),this.tooltipEl.style.left=`${a}px`,this.tooltipEl.style.top=`${d}px`}_hideTooltip(){this.tooltipEl&&(this.tooltipEl.style.display="none")}_renderLegend(){this.showLegend&&this.legendEl&&(this.legendEl.innerHTML="",this._datasets.forEach(t=>{const s=document.createElement("span");s.className="mini-series-legend-item",s.innerHTML=`\n <span class="mini-series-legend-swatch" style="background:${t.color};"></span>\n <span class="mini-series-legend-label">${this._esc(t.label)}</span>\n `,this.legendEl.appendChild(s)}))}_formatAxisValue(t){return this.valueFormatter?this.dataFormatter.pipe(t,this.valueFormatter):Math.abs(t)>=1e6?(t/1e6).toFixed(1)+"M":Math.abs(t)>=1e3?(t/1e3).toFixed(1)+"K":Number.isInteger(t)?String(t):t.toFixed(1)}_svgEl(t,s={}){const e=document.createElementNS("http://www.w3.org/2000/svg",t);for(const[i,o]of Object.entries(s))e.setAttribute(i,String(o));return e}_esc(t){const s=document.createElement("div");return s.textContent=t,s.innerHTML}async onBeforeDestroy(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),await super.onBeforeDestroy()}}export{MiniSeriesChart as default};
2
- //# sourceMappingURL=MiniSeriesChart-C4DPVbU_.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"MiniSeriesChart-C4DPVbU_.js","sources":["../../src/extensions/charts/MiniSeriesChart.js"],"sourcesContent":["/**\n * MiniSeriesChart - Lightweight SVG multi-series chart component\n * Renders line, bar, and area charts with labels, legend, and tooltips.\n * No Chart.js dependency — uses SVG for crisp, predictable sizing.\n */\n\nimport View from '@core/View.js';\nimport dataFormatter from '@core/utils/DataFormatter.js';\n\nconst SERIES_COLORS = [\n '#36A2EB', '#FF6384', '#FFCE56', '#4BC0C0', '#9966FF',\n '#FF9F40', '#66BB6A', '#EF5350', '#AB47BC', '#26C6DA'\n];\n\nconst FILL_COLORS = [\n 'rgba(54,162,235,0.15)', 'rgba(255,99,132,0.15)', 'rgba(255,206,86,0.15)',\n 'rgba(75,192,192,0.15)', 'rgba(153,102,255,0.15)', 'rgba(255,159,64,0.15)',\n 'rgba(102,187,106,0.15)', 'rgba(239,83,80,0.15)', 'rgba(171,71,188,0.15)',\n 'rgba(38,198,218,0.15)'\n];\n\nexport default class MiniSeriesChart extends View {\n constructor(options = {}) {\n super({\n className: 'mini-series-chart',\n ...options\n });\n\n // Chart type: 'line', 'bar', 'area'\n this.chartType = options.chartType || 'line';\n\n // Dimensions\n this.width = options.width || '100%';\n this.height = options.height || 200;\n\n // Padding inside the SVG (left for y-axis, bottom for x-axis labels)\n this.padTop = 10;\n this.padRight = 12;\n this.padBottom = 24; // room for x-axis labels\n this.padLeft = 40; // room for y-axis values\n\n // Line options\n this.strokeWidth = options.strokeWidth || 2;\n this.smoothing = options.smoothing || 0.3;\n this.showDots = options.showDots !== false;\n this.dotRadius = options.dotRadius || 3;\n this.fill = options.fill ?? (this.chartType === 'area');\n\n // Bar options\n this.barGap = options.barGap || 2;\n this.groupGap = options.groupGap || 6;\n\n // Grid\n this.showGrid = options.showGrid !== false;\n this.gridLines = options.gridLines || 5;\n\n // Legend\n this.showLegend = options.showLegend !== false;\n this.legendPosition = options.legendPosition || 'top';\n\n // Tooltip\n this.showTooltip = options.showTooltip !== false;\n\n // Colors\n this.colors = options.colors || SERIES_COLORS;\n this.fillColors = options.fillColors || FILL_COLORS;\n\n // Value formatting\n this.valueFormatter = options.valueFormatter || null;\n this.dataFormatter = dataFormatter;\n\n // Data — Chart.js format { labels, datasets: [{ label, data }] }\n this._rawData = options.data || null;\n this._labels = [];\n this._datasets = [];\n }\n\n // ── template ──────────────────────────────────────────────────────\n\n getTemplate() {\n const widthStyle = typeof this.width === 'number' ? `${this.width}px` : this.width;\n const heightStyle = typeof this.height === 'number' ? `${this.height}px` : this.height;\n\n return `\n <div class=\"mini-series-wrapper\">\n ${this.showLegend ? '<div class=\"mini-series-legend\"></div>' : ''}\n <div class=\"mini-series-svg-area\" style=\"width:${widthStyle}; height:${heightStyle}; position:relative;\">\n <svg class=\"mini-series-svg\" width=\"100%\" height=\"100%\"\n preserveAspectRatio=\"none\" style=\"display:block;\">\n </svg>\n ${this.showTooltip ? '<div class=\"mini-series-tooltip\" style=\"display:none;\"></div>' : ''}\n </div>\n </div>\n `;\n }\n\n // ── lifecycle ─────────────────────────────────────────────────────\n\n async onAfterRender() {\n this.svg = this.element.querySelector('.mini-series-svg');\n this.tooltipEl = this.element.querySelector('.mini-series-tooltip');\n this.legendEl = this.element.querySelector('.mini-series-legend');\n\n this._updateDimensions();\n this._setupResizeObserver();\n\n if (this._rawData) {\n this._parseData(this._rawData);\n this._renderChart();\n this._renderLegend();\n }\n }\n\n // ── public API ────────────────────────────────────────────────────\n\n setData(data) {\n this._rawData = data;\n this._parseData(data);\n if (this.svg) {\n this._renderChart();\n this._renderLegend();\n }\n }\n\n // ── dimensions ────────────────────────────────────────────────────\n\n _updateDimensions() {\n if (!this.svg) return;\n const rect = this.svg.getBoundingClientRect();\n this._w = rect.width || 300;\n this._h = rect.height || (typeof this.height === 'number' ? this.height : 200);\n this.svg.setAttribute('viewBox', `0 0 ${this._w} ${this._h}`);\n }\n\n _setupResizeObserver() {\n if (typeof ResizeObserver === 'undefined') return;\n this._resizeObserver = new ResizeObserver(() => {\n this._updateDimensions();\n if (this._datasets.length > 0) this._renderChart();\n });\n if (this.svg) this._resizeObserver.observe(this.svg);\n }\n\n // ── data normalisation ────────────────────────────────────────────\n\n _parseData(data) {\n if (!data) { this._labels = []; this._datasets = []; return; }\n\n if (data.labels && data.datasets) {\n this._labels = data.labels || [];\n this._datasets = data.datasets.map((ds, i) => ({\n label: ds.label || `Series ${i + 1}`,\n data: ds.data || [],\n color: ds.borderColor || ds.color || this.colors[i % this.colors.length],\n fillColor: ds.backgroundColor || this.fillColors[i % this.fillColors.length]\n }));\n } else {\n this._labels = [];\n this._datasets = [];\n }\n }\n\n // ── chart area helpers ────────────────────────────────────────────\n\n get _plotLeft() { return this.padLeft; }\n get _plotTop() { return this.padTop; }\n get _plotRight() { return this._w - this.padRight; }\n get _plotBottom() { return this._h - this.padBottom; }\n get _plotW() { return this._plotRight - this._plotLeft; }\n get _plotH() { return this._plotBottom - this._plotTop; }\n\n _calcBounds() {\n let min = Infinity, max = -Infinity;\n for (const ds of this._datasets) {\n for (const v of ds.data) {\n if (v < min) min = v;\n if (v > max) max = v;\n }\n }\n if (!isFinite(min)) { min = 0; max = 1; }\n if (min === max) { min -= 1; max += 1; }\n // Add 5% padding on top\n const range = max - min;\n max += range * 0.05;\n if (min > 0) min = Math.max(0, min - range * 0.05);\n return { min, max };\n }\n\n _yToPixel(value, min, max) {\n return this._plotBottom - ((value - min) / (max - min)) * this._plotH;\n }\n\n _xToPixel(index, count) {\n if (count <= 1) return this._plotLeft + this._plotW / 2;\n return this._plotLeft + (index / (count - 1)) * this._plotW;\n }\n\n // ── render ────────────────────────────────────────────────────────\n\n _renderChart() {\n if (!this.svg) return;\n this._updateDimensions();\n this.svg.innerHTML = '';\n\n if (this._datasets.length === 0) return;\n\n const { min, max } = this._calcBounds();\n const count = this._labels.length || (this._datasets[0]?.data.length || 0);\n\n this._renderGrid(min, max);\n this._renderAxes(min, max, count);\n\n if (this.chartType === 'bar') {\n this._renderBars(min, max, count);\n } else {\n this._renderLines(min, max, count);\n }\n\n this._attachHoverListeners();\n }\n\n _renderGrid(min, max) {\n if (!this.showGrid) return;\n\n const steps = this.gridLines;\n for (let i = 0; i <= steps; i++) {\n const y = this._plotTop + (i / steps) * this._plotH;\n const line = this._svgEl('line', {\n x1: this._plotLeft, y1: y,\n x2: this._plotRight, y2: y,\n stroke: 'var(--bs-border-color, #dee2e6)',\n 'stroke-width': 0.5,\n 'stroke-dasharray': '3,3'\n });\n this.svg.appendChild(line);\n }\n }\n\n _renderAxes(min, max, count) {\n // Y-axis labels\n const steps = this.gridLines;\n for (let i = 0; i <= steps; i++) {\n const value = max - (i / steps) * (max - min);\n const y = this._plotTop + (i / steps) * this._plotH;\n const label = this._formatAxisValue(value);\n const text = this._svgEl('text', {\n x: this._plotLeft - 4,\n y: y + 3,\n 'text-anchor': 'end',\n 'font-size': '10',\n fill: 'var(--bs-secondary-color, #6c757d)'\n });\n text.textContent = label;\n this.svg.appendChild(text);\n }\n\n // X-axis labels — show a reasonable subset to avoid overlap\n const maxXLabels = Math.floor(this._plotW / 50);\n const step = Math.max(1, Math.ceil(count / maxXLabels));\n for (let i = 0; i < count; i += step) {\n const x = this._xToPixel(i, count);\n const text = this._svgEl('text', {\n x,\n y: this._plotBottom + 14,\n 'text-anchor': 'middle',\n 'font-size': '10',\n fill: 'var(--bs-secondary-color, #6c757d)'\n });\n const rawLabel = this._labels[i] || '';\n // Truncate long labels\n text.textContent = String(rawLabel).length > 10\n ? String(rawLabel).substring(0, 9) + '…'\n : rawLabel;\n this.svg.appendChild(text);\n }\n }\n\n _renderLines(min, max, count) {\n this._datasets.forEach((ds, dsIdx) => {\n const points = ds.data.map((v, i) => ({\n x: this._xToPixel(i, count),\n y: this._yToPixel(v, min, max)\n }));\n\n // Area fill\n if (this.fill && points.length > 1) {\n const areaPath = this._buildLinePath(points)\n + ` L ${points[points.length - 1].x},${this._plotBottom}`\n + ` L ${points[0].x},${this._plotBottom} Z`;\n const area = this._svgEl('path', {\n d: areaPath,\n fill: ds.fillColor,\n stroke: 'none'\n });\n this.svg.appendChild(area);\n }\n\n // Line\n if (points.length > 1) {\n const path = this._svgEl('path', {\n d: this._buildLinePath(points),\n fill: 'none',\n stroke: ds.color,\n 'stroke-width': this.strokeWidth,\n 'stroke-linecap': 'round',\n 'stroke-linejoin': 'round'\n });\n this.svg.appendChild(path);\n }\n\n // Dots\n if (this.showDots) {\n points.forEach((p, i) => {\n const dot = this._svgEl('circle', {\n cx: p.x, cy: p.y, r: this.dotRadius,\n fill: ds.color,\n class: 'mini-series-dot',\n 'data-col': i\n });\n this.svg.appendChild(dot);\n });\n }\n });\n }\n\n _renderBars(min, max, count) {\n const numSeries = this._datasets.length;\n const slotW = this._plotW / count;\n const groupW = slotW - this.groupGap;\n const barW = Math.max(1, (groupW - (numSeries - 1) * this.barGap) / numSeries);\n const baseline = this._yToPixel(Math.max(0, min), min, max);\n\n this._datasets.forEach((ds, dsIdx) => {\n ds.data.forEach((v, i) => {\n const slotX = this._plotLeft + i * slotW + this.groupGap / 2;\n const x = slotX + dsIdx * (barW + this.barGap);\n const y = this._yToPixel(v, min, max);\n const h = Math.abs(baseline - y);\n\n const bar = this._svgEl('rect', {\n x, y: Math.min(y, baseline),\n width: barW, height: Math.max(h, 0.5),\n fill: ds.color,\n rx: 1,\n class: 'mini-series-bar',\n 'data-col': i\n });\n this.svg.appendChild(bar);\n });\n });\n }\n\n _buildLinePath(points) {\n if (points.length === 0) return '';\n if (this.smoothing > 0 && points.length >= 2) {\n let d = `M ${points[0].x},${points[0].y}`;\n for (let i = 0; i < points.length - 1; i++) {\n const cur = points[i], nxt = points[i + 1];\n const cp1x = cur.x + (nxt.x - cur.x) * this.smoothing;\n const cp2x = nxt.x - (nxt.x - cur.x) * this.smoothing;\n d += ` C ${cp1x},${cur.y} ${cp2x},${nxt.y} ${nxt.x},${nxt.y}`;\n }\n return d;\n }\n return points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x},${p.y}`).join(' ');\n }\n\n // ── tooltip hit areas ─────────────────────────────────────────────\n\n _attachHoverListeners() {\n if (!this.showTooltip || !this.svg) return;\n\n this.svg.querySelectorAll('.mini-series-bar, .mini-series-dot').forEach(el => {\n const col = parseInt(el.getAttribute('data-col'), 10);\n if (isNaN(col)) return;\n el.addEventListener('mouseenter', (e) => this._showTooltip(col, e));\n el.addEventListener('mousemove', (e) => this._moveTooltip(e));\n el.addEventListener('mouseleave', () => this._hideTooltip());\n });\n }\n\n _showTooltip(index, event) {\n if (!this.tooltipEl) return;\n\n const label = this._labels[index] || `#${index + 1}`;\n let html = `<div class=\"mini-series-tooltip-label\">${this._esc(String(label))}</div>`;\n\n this._datasets.forEach(ds => {\n const v = ds.data[index];\n let displayValue = v;\n if (this.valueFormatter) {\n displayValue = this.dataFormatter.pipe(v, this.valueFormatter);\n } else if (typeof v === 'number') {\n displayValue = v.toLocaleString();\n }\n html += `<div class=\"mini-series-tooltip-row\">\n <span class=\"mini-series-tooltip-swatch\" style=\"background:${ds.color}\"></span>\n <span>${this._esc(ds.label)}:</span>\n <strong>${displayValue}</strong>\n </div>`;\n });\n\n this.tooltipEl.innerHTML = html;\n this.tooltipEl.style.display = 'block';\n this._moveTooltip(event);\n }\n\n _moveTooltip(event) {\n if (!this.tooltipEl || this.tooltipEl.style.display === 'none') return;\n const area = this.element.querySelector('.mini-series-svg-area');\n if (!area) return;\n const areaRect = area.getBoundingClientRect();\n const x = event.clientX - areaRect.left;\n const y = event.clientY - areaRect.top;\n\n // Render once to measure, then clamp within container\n this.tooltipEl.style.left = '0px';\n this.tooltipEl.style.top = '0px';\n this.tooltipEl.style.transform = 'none';\n const tw = this.tooltipEl.offsetWidth;\n const th = this.tooltipEl.offsetHeight;\n const aw = areaRect.width;\n const ah = areaRect.height;\n\n let left = x - tw / 2;\n let top = y - th - 8;\n // Clamp horizontally\n if (left < 0) left = 0;\n if (left + tw > aw) left = aw - tw;\n // Flip below cursor if too close to top\n if (top < 0) top = y + 12;\n // Clamp bottom\n if (top + th > ah) top = ah - th;\n\n this.tooltipEl.style.left = `${left}px`;\n this.tooltipEl.style.top = `${top}px`;\n }\n\n _hideTooltip() {\n if (this.tooltipEl) this.tooltipEl.style.display = 'none';\n }\n\n // ── legend ────────────────────────────────────────────────────────\n\n _renderLegend() {\n if (!this.showLegend || !this.legendEl) return;\n this.legendEl.innerHTML = '';\n\n this._datasets.forEach(ds => {\n const item = document.createElement('span');\n item.className = 'mini-series-legend-item';\n item.innerHTML = `\n <span class=\"mini-series-legend-swatch\" style=\"background:${ds.color};\"></span>\n <span class=\"mini-series-legend-label\">${this._esc(ds.label)}</span>\n `;\n this.legendEl.appendChild(item);\n });\n }\n\n // ── helpers ───────────────────────────────────────────────────────\n\n _formatAxisValue(value) {\n if (this.valueFormatter) {\n return this.dataFormatter.pipe(value, this.valueFormatter);\n }\n if (Math.abs(value) >= 1000000) return (value / 1000000).toFixed(1) + 'M';\n if (Math.abs(value) >= 1000) return (value / 1000).toFixed(1) + 'K';\n if (Number.isInteger(value)) return String(value);\n return value.toFixed(1);\n }\n\n _svgEl(tag, attrs = {}) {\n const el = document.createElementNS('http://www.w3.org/2000/svg', tag);\n for (const [k, v] of Object.entries(attrs)) {\n el.setAttribute(k, String(v));\n }\n return el;\n }\n\n _esc(text) {\n const d = document.createElement('div');\n d.textContent = text;\n return d.innerHTML;\n }\n\n async onBeforeDestroy() {\n if (this._resizeObserver) {\n this._resizeObserver.disconnect();\n this._resizeObserver = null;\n }\n await super.onBeforeDestroy();\n }\n}\n"],"names":["SERIES_COLORS","FILL_COLORS","MiniSeriesChart","View","constructor","options","super","className","this","chartType","width","height","padTop","padRight","padBottom","padLeft","strokeWidth","smoothing","showDots","dotRadius","fill","barGap","groupGap","showGrid","gridLines","showLegend","legendPosition","showTooltip","colors","fillColors","valueFormatter","dataFormatter","_rawData","data","_labels","_datasets","getTemplate","widthStyle","heightStyle","onAfterRender","svg","element","querySelector","tooltipEl","legendEl","_updateDimensions","_setupResizeObserver","_parseData","_renderChart","_renderLegend","setData","rect","getBoundingClientRect","_w","_h","setAttribute","ResizeObserver","_resizeObserver","length","observe","labels","datasets","map","ds","i","label","color","borderColor","fillColor","backgroundColor","_plotLeft","_plotTop","_plotRight","_plotBottom","_plotW","_plotH","_calcBounds","min","Infinity","max","v","isFinite","range","Math","_yToPixel","value","_xToPixel","index","count","innerHTML","_renderGrid","_renderAxes","_renderBars","_renderLines","_attachHoverListeners","steps","y","line","_svgEl","x1","y1","x2","y2","stroke","appendChild","_formatAxisValue","text","x","textContent","maxXLabels","floor","step","ceil","rawLabel","String","substring","forEach","dsIdx","points","areaPath","_buildLinePath","area","d","path","p","dot","cx","cy","r","class","numSeries","slotW","groupW","barW","baseline","h","abs","bar","rx","cur","nxt","cp1x","cp2x","join","querySelectorAll","el","col","parseInt","getAttribute","isNaN","addEventListener","e","_showTooltip","_moveTooltip","_hideTooltip","event","html","_esc","displayValue","pipe","toLocaleString","style","display","areaRect","clientX","left","clientY","top","transform","tw","offsetWidth","th","offsetHeight","aw","ah","item","document","createElement","toFixed","Number","isInteger","tag","attrs","createElementNS","k","Object","entries","onBeforeDestroy","disconnect"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const t=require("./Collection-CyK0u557.js"),s=["#36A2EB","#FF6384","#FFCE56","#4BC0C0","#9966FF","#FF9F40","#66BB6A","#EF5350","#AB47BC","#26C6DA"],e=["rgba(54,162,235,0.15)","rgba(255,99,132,0.15)","rgba(255,206,86,0.15)","rgba(75,192,192,0.15)","rgba(153,102,255,0.15)","rgba(255,159,64,0.15)","rgba(102,187,106,0.15)","rgba(239,83,80,0.15)","rgba(171,71,188,0.15)","rgba(38,198,218,0.15)"];class MiniSeriesChart extends t.View{constructor(i={}){super({className:"mini-series-chart",...i}),this.chartType=i.chartType||"line",this.width=i.width||"100%",this.height=i.height||200,this.padTop=10,this.padRight=12,this.padBottom=24,this.padLeft=40,this.strokeWidth=i.strokeWidth||2,this.smoothing=i.smoothing||.3,this.showDots=!1!==i.showDots,this.dotRadius=i.dotRadius||3,this.fill=i.fill??"area"===this.chartType,this.barGap=i.barGap||2,this.groupGap=i.groupGap||6,this.showGrid=!1!==i.showGrid,this.gridLines=i.gridLines||5,this.showLegend=!1!==i.showLegend,this.legendPosition=i.legendPosition||"top",this.showTooltip=!1!==i.showTooltip,this.colors=i.colors||s,this.fillColors=i.fillColors||e,this.valueFormatter=i.valueFormatter||null,this.dataFormatter=t.dataFormatter,this._rawData=i.data||null,this._labels=[],this._datasets=[]}getTemplate(){const t="number"==typeof this.width?`${this.width}px`:this.width,s="number"==typeof this.height?`${this.height}px`:this.height;return`\n <div class="mini-series-wrapper">\n ${this.showLegend?'<div class="mini-series-legend"></div>':""}\n <div class="mini-series-svg-area" style="width:${t}; height:${s}; position:relative;">\n <svg class="mini-series-svg" width="100%" height="100%"\n preserveAspectRatio="none" style="display:block;">\n </svg>\n ${this.showTooltip?'<div class="mini-series-tooltip" style="display:none;"></div>':""}\n </div>\n </div>\n `}async onAfterRender(){this.svg=this.element.querySelector(".mini-series-svg"),this.tooltipEl=this.element.querySelector(".mini-series-tooltip"),this.legendEl=this.element.querySelector(".mini-series-legend"),this._updateDimensions(),this._setupResizeObserver(),this._rawData&&(this._parseData(this._rawData),this._renderChart(),this._renderLegend())}setData(t){this._rawData=t,this._parseData(t),this.svg&&(this._renderChart(),this._renderLegend())}_updateDimensions(){if(!this.svg)return;const t=this.svg.getBoundingClientRect();this._w=t.width||300,this._h=t.height||("number"==typeof this.height?this.height:200),this.svg.setAttribute("viewBox",`0 0 ${this._w} ${this._h}`)}_setupResizeObserver(){"undefined"!=typeof ResizeObserver&&(this._resizeObserver=new ResizeObserver(()=>{this._updateDimensions(),this._datasets.length>0&&this._renderChart()}),this.svg&&this._resizeObserver.observe(this.svg))}_parseData(t){if(!t)return this._labels=[],void(this._datasets=[]);t.labels&&t.datasets?(this._labels=t.labels||[],this._datasets=t.datasets.map((t,s)=>({label:t.label||`Series ${s+1}`,data:t.data||[],color:t.borderColor||t.color||this.colors[s%this.colors.length],fillColor:t.backgroundColor||this.fillColors[s%this.fillColors.length]}))):(this._labels=[],this._datasets=[])}get _plotLeft(){return this.padLeft}get _plotTop(){return this.padTop}get _plotRight(){return this._w-this.padRight}get _plotBottom(){return this._h-this.padBottom}get _plotW(){return this._plotRight-this._plotLeft}get _plotH(){return this._plotBottom-this._plotTop}_calcBounds(){let t=1/0,s=-1/0;for(const i of this._datasets)for(const e of i.data)e<t&&(t=e),e>s&&(s=e);isFinite(t)||(t=0,s=1),t===s&&(t-=1,s+=1);const e=s-t;return s+=.05*e,t>0&&(t=Math.max(0,t-.05*e)),{min:t,max:s}}_yToPixel(t,s,e){return this._plotBottom-(t-s)/(e-s)*this._plotH}_xToPixel(t,s){return s<=1?this._plotLeft+this._plotW/2:this._plotLeft+t/(s-1)*this._plotW}_renderChart(){if(!this.svg)return;if(this._updateDimensions(),this.svg.innerHTML="",0===this._datasets.length)return;const{min:t,max:s}=this._calcBounds(),e=this._labels.length||this._datasets[0]?.data.length||0;this._renderGrid(t,s),this._renderAxes(t,s,e),"bar"===this.chartType?this._renderBars(t,s,e):this._renderLines(t,s,e),this._attachHoverListeners()}_renderGrid(t,s){if(!this.showGrid)return;const e=this.gridLines;for(let i=0;i<=e;i++){const t=this._plotTop+i/e*this._plotH,s=this._svgEl("line",{x1:this._plotLeft,y1:t,x2:this._plotRight,y2:t,stroke:"var(--bs-border-color, #dee2e6)","stroke-width":.5,"stroke-dasharray":"3,3"});this.svg.appendChild(s)}}_renderAxes(t,s,e){const i=this.gridLines;for(let h=0;h<=i;h++){const e=s-h/i*(s-t),o=this._plotTop+h/i*this._plotH,r=this._formatAxisValue(e),l=this._svgEl("text",{x:this._plotLeft-4,y:o+3,"text-anchor":"end","font-size":"10",fill:"var(--bs-secondary-color, #6c757d)"});l.textContent=r,this.svg.appendChild(l)}const o=Math.floor(this._plotW/50),r=Math.max(1,Math.ceil(e/o));for(let h=0;h<e;h+=r){const t=this._xToPixel(h,e),s=this._svgEl("text",{x:t,y:this._plotBottom+14,"text-anchor":"middle","font-size":"10",fill:"var(--bs-secondary-color, #6c757d)"}),i=this._labels[h]||"";s.textContent=String(i).length>10?String(i).substring(0,9)+"…":i,this.svg.appendChild(s)}}_renderLines(t,s,e){this._datasets.forEach((i,o)=>{const r=i.data.map((i,o)=>({x:this._xToPixel(o,e),y:this._yToPixel(i,t,s)}));if(this.fill&&r.length>1){const t=this._buildLinePath(r)+` L ${r[r.length-1].x},${this._plotBottom} L ${r[0].x},${this._plotBottom} Z`,s=this._svgEl("path",{d:t,fill:i.fillColor,stroke:"none"});this.svg.appendChild(s)}if(r.length>1){const t=this._svgEl("path",{d:this._buildLinePath(r),fill:"none",stroke:i.color,"stroke-width":this.strokeWidth,"stroke-linecap":"round","stroke-linejoin":"round"});this.svg.appendChild(t)}this.showDots&&r.forEach((t,s)=>{const e=this._svgEl("circle",{cx:t.x,cy:t.y,r:this.dotRadius,fill:i.color,class:"mini-series-dot","data-col":s});this.svg.appendChild(e)})})}_renderBars(t,s,e){const i=this._datasets.length,o=this._plotW/e,r=o-this.groupGap,h=Math.max(1,(r-(i-1)*this.barGap)/i),l=this._yToPixel(Math.max(0,t),t,s);this._datasets.forEach((e,i)=>{e.data.forEach((r,n)=>{const a=this._plotLeft+n*o+this.groupGap/2+i*(h+this.barGap),d=this._yToPixel(r,t,s),p=Math.abs(l-d),g=this._svgEl("rect",{x:a,y:Math.min(d,l),width:h,height:Math.max(p,.5),fill:e.color,rx:1,class:"mini-series-bar","data-col":n});this.svg.appendChild(g)})})}_buildLinePath(t){if(0===t.length)return"";if(this.smoothing>0&&t.length>=2){let s=`M ${t[0].x},${t[0].y}`;for(let e=0;e<t.length-1;e++){const i=t[e],o=t[e+1],r=i.x+(o.x-i.x)*this.smoothing,h=o.x-(o.x-i.x)*this.smoothing;s+=` C ${r},${i.y} ${h},${o.y} ${o.x},${o.y}`}return s}return t.map((t,s)=>`${0===s?"M":"L"} ${t.x},${t.y}`).join(" ")}_attachHoverListeners(){this.showTooltip&&this.svg&&this.svg.querySelectorAll(".mini-series-bar, .mini-series-dot").forEach(t=>{const s=parseInt(t.getAttribute("data-col"),10);isNaN(s)||(t.addEventListener("mouseenter",t=>this._showTooltip(s,t)),t.addEventListener("mousemove",t=>this._moveTooltip(t)),t.addEventListener("mouseleave",()=>this._hideTooltip()))})}_showTooltip(t,s){if(!this.tooltipEl)return;const e=this._labels[t]||`#${t+1}`;let i=`<div class="mini-series-tooltip-label">${this._esc(String(e))}</div>`;this._datasets.forEach(s=>{const e=s.data[t];let o=e;this.valueFormatter?o=this.dataFormatter.pipe(e,this.valueFormatter):"number"==typeof e&&(o=e.toLocaleString()),i+=`<div class="mini-series-tooltip-row">\n <span class="mini-series-tooltip-swatch" style="background:${s.color}"></span>\n <span>${this._esc(s.label)}:</span>\n <strong>${o}</strong>\n </div>`}),this.tooltipEl.innerHTML=i,this.tooltipEl.style.display="block",this._moveTooltip(s)}_moveTooltip(t){if(!this.tooltipEl||"none"===this.tooltipEl.style.display)return;const s=this.element.querySelector(".mini-series-svg-area");if(!s)return;const e=s.getBoundingClientRect(),i=t.clientX-e.left,o=t.clientY-e.top;this.tooltipEl.style.left="0px",this.tooltipEl.style.top="0px",this.tooltipEl.style.transform="none";const r=this.tooltipEl.offsetWidth,h=this.tooltipEl.offsetHeight,l=e.width,n=e.height;let a=i-r/2,d=o-h-8;a<0&&(a=0),a+r>l&&(a=l-r),d<0&&(d=o+12),d+h>n&&(d=n-h),this.tooltipEl.style.left=`${a}px`,this.tooltipEl.style.top=`${d}px`}_hideTooltip(){this.tooltipEl&&(this.tooltipEl.style.display="none")}_renderLegend(){this.showLegend&&this.legendEl&&(this.legendEl.innerHTML="",this._datasets.forEach(t=>{const s=document.createElement("span");s.className="mini-series-legend-item",s.innerHTML=`\n <span class="mini-series-legend-swatch" style="background:${t.color};"></span>\n <span class="mini-series-legend-label">${this._esc(t.label)}</span>\n `,this.legendEl.appendChild(s)}))}_formatAxisValue(t){return this.valueFormatter?this.dataFormatter.pipe(t,this.valueFormatter):Math.abs(t)>=1e6?(t/1e6).toFixed(1)+"M":Math.abs(t)>=1e3?(t/1e3).toFixed(1)+"K":Number.isInteger(t)?String(t):t.toFixed(1)}_svgEl(t,s={}){const e=document.createElementNS("http://www.w3.org/2000/svg",t);for(const[i,o]of Object.entries(s))e.setAttribute(i,String(o));return e}_esc(t){const s=document.createElement("div");return s.textContent=t,s.innerHTML}async onBeforeDestroy(){this._resizeObserver&&(this._resizeObserver.disconnect(),this._resizeObserver=null),await super.onBeforeDestroy()}}exports.default=MiniSeriesChart;
2
- //# sourceMappingURL=MiniSeriesChart-DdNMLwfh.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"MiniSeriesChart-DdNMLwfh.js","sources":["../../src/extensions/charts/MiniSeriesChart.js"],"sourcesContent":["/**\n * MiniSeriesChart - Lightweight SVG multi-series chart component\n * Renders line, bar, and area charts with labels, legend, and tooltips.\n * No Chart.js dependency — uses SVG for crisp, predictable sizing.\n */\n\nimport View from '@core/View.js';\nimport dataFormatter from '@core/utils/DataFormatter.js';\n\nconst SERIES_COLORS = [\n '#36A2EB', '#FF6384', '#FFCE56', '#4BC0C0', '#9966FF',\n '#FF9F40', '#66BB6A', '#EF5350', '#AB47BC', '#26C6DA'\n];\n\nconst FILL_COLORS = [\n 'rgba(54,162,235,0.15)', 'rgba(255,99,132,0.15)', 'rgba(255,206,86,0.15)',\n 'rgba(75,192,192,0.15)', 'rgba(153,102,255,0.15)', 'rgba(255,159,64,0.15)',\n 'rgba(102,187,106,0.15)', 'rgba(239,83,80,0.15)', 'rgba(171,71,188,0.15)',\n 'rgba(38,198,218,0.15)'\n];\n\nexport default class MiniSeriesChart extends View {\n constructor(options = {}) {\n super({\n className: 'mini-series-chart',\n ...options\n });\n\n // Chart type: 'line', 'bar', 'area'\n this.chartType = options.chartType || 'line';\n\n // Dimensions\n this.width = options.width || '100%';\n this.height = options.height || 200;\n\n // Padding inside the SVG (left for y-axis, bottom for x-axis labels)\n this.padTop = 10;\n this.padRight = 12;\n this.padBottom = 24; // room for x-axis labels\n this.padLeft = 40; // room for y-axis values\n\n // Line options\n this.strokeWidth = options.strokeWidth || 2;\n this.smoothing = options.smoothing || 0.3;\n this.showDots = options.showDots !== false;\n this.dotRadius = options.dotRadius || 3;\n this.fill = options.fill ?? (this.chartType === 'area');\n\n // Bar options\n this.barGap = options.barGap || 2;\n this.groupGap = options.groupGap || 6;\n\n // Grid\n this.showGrid = options.showGrid !== false;\n this.gridLines = options.gridLines || 5;\n\n // Legend\n this.showLegend = options.showLegend !== false;\n this.legendPosition = options.legendPosition || 'top';\n\n // Tooltip\n this.showTooltip = options.showTooltip !== false;\n\n // Colors\n this.colors = options.colors || SERIES_COLORS;\n this.fillColors = options.fillColors || FILL_COLORS;\n\n // Value formatting\n this.valueFormatter = options.valueFormatter || null;\n this.dataFormatter = dataFormatter;\n\n // Data — Chart.js format { labels, datasets: [{ label, data }] }\n this._rawData = options.data || null;\n this._labels = [];\n this._datasets = [];\n }\n\n // ── template ──────────────────────────────────────────────────────\n\n getTemplate() {\n const widthStyle = typeof this.width === 'number' ? `${this.width}px` : this.width;\n const heightStyle = typeof this.height === 'number' ? `${this.height}px` : this.height;\n\n return `\n <div class=\"mini-series-wrapper\">\n ${this.showLegend ? '<div class=\"mini-series-legend\"></div>' : ''}\n <div class=\"mini-series-svg-area\" style=\"width:${widthStyle}; height:${heightStyle}; position:relative;\">\n <svg class=\"mini-series-svg\" width=\"100%\" height=\"100%\"\n preserveAspectRatio=\"none\" style=\"display:block;\">\n </svg>\n ${this.showTooltip ? '<div class=\"mini-series-tooltip\" style=\"display:none;\"></div>' : ''}\n </div>\n </div>\n `;\n }\n\n // ── lifecycle ─────────────────────────────────────────────────────\n\n async onAfterRender() {\n this.svg = this.element.querySelector('.mini-series-svg');\n this.tooltipEl = this.element.querySelector('.mini-series-tooltip');\n this.legendEl = this.element.querySelector('.mini-series-legend');\n\n this._updateDimensions();\n this._setupResizeObserver();\n\n if (this._rawData) {\n this._parseData(this._rawData);\n this._renderChart();\n this._renderLegend();\n }\n }\n\n // ── public API ────────────────────────────────────────────────────\n\n setData(data) {\n this._rawData = data;\n this._parseData(data);\n if (this.svg) {\n this._renderChart();\n this._renderLegend();\n }\n }\n\n // ── dimensions ────────────────────────────────────────────────────\n\n _updateDimensions() {\n if (!this.svg) return;\n const rect = this.svg.getBoundingClientRect();\n this._w = rect.width || 300;\n this._h = rect.height || (typeof this.height === 'number' ? this.height : 200);\n this.svg.setAttribute('viewBox', `0 0 ${this._w} ${this._h}`);\n }\n\n _setupResizeObserver() {\n if (typeof ResizeObserver === 'undefined') return;\n this._resizeObserver = new ResizeObserver(() => {\n this._updateDimensions();\n if (this._datasets.length > 0) this._renderChart();\n });\n if (this.svg) this._resizeObserver.observe(this.svg);\n }\n\n // ── data normalisation ────────────────────────────────────────────\n\n _parseData(data) {\n if (!data) { this._labels = []; this._datasets = []; return; }\n\n if (data.labels && data.datasets) {\n this._labels = data.labels || [];\n this._datasets = data.datasets.map((ds, i) => ({\n label: ds.label || `Series ${i + 1}`,\n data: ds.data || [],\n color: ds.borderColor || ds.color || this.colors[i % this.colors.length],\n fillColor: ds.backgroundColor || this.fillColors[i % this.fillColors.length]\n }));\n } else {\n this._labels = [];\n this._datasets = [];\n }\n }\n\n // ── chart area helpers ────────────────────────────────────────────\n\n get _plotLeft() { return this.padLeft; }\n get _plotTop() { return this.padTop; }\n get _plotRight() { return this._w - this.padRight; }\n get _plotBottom() { return this._h - this.padBottom; }\n get _plotW() { return this._plotRight - this._plotLeft; }\n get _plotH() { return this._plotBottom - this._plotTop; }\n\n _calcBounds() {\n let min = Infinity, max = -Infinity;\n for (const ds of this._datasets) {\n for (const v of ds.data) {\n if (v < min) min = v;\n if (v > max) max = v;\n }\n }\n if (!isFinite(min)) { min = 0; max = 1; }\n if (min === max) { min -= 1; max += 1; }\n // Add 5% padding on top\n const range = max - min;\n max += range * 0.05;\n if (min > 0) min = Math.max(0, min - range * 0.05);\n return { min, max };\n }\n\n _yToPixel(value, min, max) {\n return this._plotBottom - ((value - min) / (max - min)) * this._plotH;\n }\n\n _xToPixel(index, count) {\n if (count <= 1) return this._plotLeft + this._plotW / 2;\n return this._plotLeft + (index / (count - 1)) * this._plotW;\n }\n\n // ── render ────────────────────────────────────────────────────────\n\n _renderChart() {\n if (!this.svg) return;\n this._updateDimensions();\n this.svg.innerHTML = '';\n\n if (this._datasets.length === 0) return;\n\n const { min, max } = this._calcBounds();\n const count = this._labels.length || (this._datasets[0]?.data.length || 0);\n\n this._renderGrid(min, max);\n this._renderAxes(min, max, count);\n\n if (this.chartType === 'bar') {\n this._renderBars(min, max, count);\n } else {\n this._renderLines(min, max, count);\n }\n\n this._attachHoverListeners();\n }\n\n _renderGrid(min, max) {\n if (!this.showGrid) return;\n\n const steps = this.gridLines;\n for (let i = 0; i <= steps; i++) {\n const y = this._plotTop + (i / steps) * this._plotH;\n const line = this._svgEl('line', {\n x1: this._plotLeft, y1: y,\n x2: this._plotRight, y2: y,\n stroke: 'var(--bs-border-color, #dee2e6)',\n 'stroke-width': 0.5,\n 'stroke-dasharray': '3,3'\n });\n this.svg.appendChild(line);\n }\n }\n\n _renderAxes(min, max, count) {\n // Y-axis labels\n const steps = this.gridLines;\n for (let i = 0; i <= steps; i++) {\n const value = max - (i / steps) * (max - min);\n const y = this._plotTop + (i / steps) * this._plotH;\n const label = this._formatAxisValue(value);\n const text = this._svgEl('text', {\n x: this._plotLeft - 4,\n y: y + 3,\n 'text-anchor': 'end',\n 'font-size': '10',\n fill: 'var(--bs-secondary-color, #6c757d)'\n });\n text.textContent = label;\n this.svg.appendChild(text);\n }\n\n // X-axis labels — show a reasonable subset to avoid overlap\n const maxXLabels = Math.floor(this._plotW / 50);\n const step = Math.max(1, Math.ceil(count / maxXLabels));\n for (let i = 0; i < count; i += step) {\n const x = this._xToPixel(i, count);\n const text = this._svgEl('text', {\n x,\n y: this._plotBottom + 14,\n 'text-anchor': 'middle',\n 'font-size': '10',\n fill: 'var(--bs-secondary-color, #6c757d)'\n });\n const rawLabel = this._labels[i] || '';\n // Truncate long labels\n text.textContent = String(rawLabel).length > 10\n ? String(rawLabel).substring(0, 9) + '…'\n : rawLabel;\n this.svg.appendChild(text);\n }\n }\n\n _renderLines(min, max, count) {\n this._datasets.forEach((ds, dsIdx) => {\n const points = ds.data.map((v, i) => ({\n x: this._xToPixel(i, count),\n y: this._yToPixel(v, min, max)\n }));\n\n // Area fill\n if (this.fill && points.length > 1) {\n const areaPath = this._buildLinePath(points)\n + ` L ${points[points.length - 1].x},${this._plotBottom}`\n + ` L ${points[0].x},${this._plotBottom} Z`;\n const area = this._svgEl('path', {\n d: areaPath,\n fill: ds.fillColor,\n stroke: 'none'\n });\n this.svg.appendChild(area);\n }\n\n // Line\n if (points.length > 1) {\n const path = this._svgEl('path', {\n d: this._buildLinePath(points),\n fill: 'none',\n stroke: ds.color,\n 'stroke-width': this.strokeWidth,\n 'stroke-linecap': 'round',\n 'stroke-linejoin': 'round'\n });\n this.svg.appendChild(path);\n }\n\n // Dots\n if (this.showDots) {\n points.forEach((p, i) => {\n const dot = this._svgEl('circle', {\n cx: p.x, cy: p.y, r: this.dotRadius,\n fill: ds.color,\n class: 'mini-series-dot',\n 'data-col': i\n });\n this.svg.appendChild(dot);\n });\n }\n });\n }\n\n _renderBars(min, max, count) {\n const numSeries = this._datasets.length;\n const slotW = this._plotW / count;\n const groupW = slotW - this.groupGap;\n const barW = Math.max(1, (groupW - (numSeries - 1) * this.barGap) / numSeries);\n const baseline = this._yToPixel(Math.max(0, min), min, max);\n\n this._datasets.forEach((ds, dsIdx) => {\n ds.data.forEach((v, i) => {\n const slotX = this._plotLeft + i * slotW + this.groupGap / 2;\n const x = slotX + dsIdx * (barW + this.barGap);\n const y = this._yToPixel(v, min, max);\n const h = Math.abs(baseline - y);\n\n const bar = this._svgEl('rect', {\n x, y: Math.min(y, baseline),\n width: barW, height: Math.max(h, 0.5),\n fill: ds.color,\n rx: 1,\n class: 'mini-series-bar',\n 'data-col': i\n });\n this.svg.appendChild(bar);\n });\n });\n }\n\n _buildLinePath(points) {\n if (points.length === 0) return '';\n if (this.smoothing > 0 && points.length >= 2) {\n let d = `M ${points[0].x},${points[0].y}`;\n for (let i = 0; i < points.length - 1; i++) {\n const cur = points[i], nxt = points[i + 1];\n const cp1x = cur.x + (nxt.x - cur.x) * this.smoothing;\n const cp2x = nxt.x - (nxt.x - cur.x) * this.smoothing;\n d += ` C ${cp1x},${cur.y} ${cp2x},${nxt.y} ${nxt.x},${nxt.y}`;\n }\n return d;\n }\n return points.map((p, i) => `${i === 0 ? 'M' : 'L'} ${p.x},${p.y}`).join(' ');\n }\n\n // ── tooltip hit areas ─────────────────────────────────────────────\n\n _attachHoverListeners() {\n if (!this.showTooltip || !this.svg) return;\n\n this.svg.querySelectorAll('.mini-series-bar, .mini-series-dot').forEach(el => {\n const col = parseInt(el.getAttribute('data-col'), 10);\n if (isNaN(col)) return;\n el.addEventListener('mouseenter', (e) => this._showTooltip(col, e));\n el.addEventListener('mousemove', (e) => this._moveTooltip(e));\n el.addEventListener('mouseleave', () => this._hideTooltip());\n });\n }\n\n _showTooltip(index, event) {\n if (!this.tooltipEl) return;\n\n const label = this._labels[index] || `#${index + 1}`;\n let html = `<div class=\"mini-series-tooltip-label\">${this._esc(String(label))}</div>`;\n\n this._datasets.forEach(ds => {\n const v = ds.data[index];\n let displayValue = v;\n if (this.valueFormatter) {\n displayValue = this.dataFormatter.pipe(v, this.valueFormatter);\n } else if (typeof v === 'number') {\n displayValue = v.toLocaleString();\n }\n html += `<div class=\"mini-series-tooltip-row\">\n <span class=\"mini-series-tooltip-swatch\" style=\"background:${ds.color}\"></span>\n <span>${this._esc(ds.label)}:</span>\n <strong>${displayValue}</strong>\n </div>`;\n });\n\n this.tooltipEl.innerHTML = html;\n this.tooltipEl.style.display = 'block';\n this._moveTooltip(event);\n }\n\n _moveTooltip(event) {\n if (!this.tooltipEl || this.tooltipEl.style.display === 'none') return;\n const area = this.element.querySelector('.mini-series-svg-area');\n if (!area) return;\n const areaRect = area.getBoundingClientRect();\n const x = event.clientX - areaRect.left;\n const y = event.clientY - areaRect.top;\n\n // Render once to measure, then clamp within container\n this.tooltipEl.style.left = '0px';\n this.tooltipEl.style.top = '0px';\n this.tooltipEl.style.transform = 'none';\n const tw = this.tooltipEl.offsetWidth;\n const th = this.tooltipEl.offsetHeight;\n const aw = areaRect.width;\n const ah = areaRect.height;\n\n let left = x - tw / 2;\n let top = y - th - 8;\n // Clamp horizontally\n if (left < 0) left = 0;\n if (left + tw > aw) left = aw - tw;\n // Flip below cursor if too close to top\n if (top < 0) top = y + 12;\n // Clamp bottom\n if (top + th > ah) top = ah - th;\n\n this.tooltipEl.style.left = `${left}px`;\n this.tooltipEl.style.top = `${top}px`;\n }\n\n _hideTooltip() {\n if (this.tooltipEl) this.tooltipEl.style.display = 'none';\n }\n\n // ── legend ────────────────────────────────────────────────────────\n\n _renderLegend() {\n if (!this.showLegend || !this.legendEl) return;\n this.legendEl.innerHTML = '';\n\n this._datasets.forEach(ds => {\n const item = document.createElement('span');\n item.className = 'mini-series-legend-item';\n item.innerHTML = `\n <span class=\"mini-series-legend-swatch\" style=\"background:${ds.color};\"></span>\n <span class=\"mini-series-legend-label\">${this._esc(ds.label)}</span>\n `;\n this.legendEl.appendChild(item);\n });\n }\n\n // ── helpers ───────────────────────────────────────────────────────\n\n _formatAxisValue(value) {\n if (this.valueFormatter) {\n return this.dataFormatter.pipe(value, this.valueFormatter);\n }\n if (Math.abs(value) >= 1000000) return (value / 1000000).toFixed(1) + 'M';\n if (Math.abs(value) >= 1000) return (value / 1000).toFixed(1) + 'K';\n if (Number.isInteger(value)) return String(value);\n return value.toFixed(1);\n }\n\n _svgEl(tag, attrs = {}) {\n const el = document.createElementNS('http://www.w3.org/2000/svg', tag);\n for (const [k, v] of Object.entries(attrs)) {\n el.setAttribute(k, String(v));\n }\n return el;\n }\n\n _esc(text) {\n const d = document.createElement('div');\n d.textContent = text;\n return d.innerHTML;\n }\n\n async onBeforeDestroy() {\n if (this._resizeObserver) {\n this._resizeObserver.disconnect();\n this._resizeObserver = null;\n }\n await super.onBeforeDestroy();\n }\n}\n"],"names":["SERIES_COLORS","FILL_COLORS","MiniSeriesChart","View","constructor","options","super","className","this","chartType","width","height","padTop","padRight","padBottom","padLeft","strokeWidth","smoothing","showDots","dotRadius","fill","barGap","groupGap","showGrid","gridLines","showLegend","legendPosition","showTooltip","colors","fillColors","valueFormatter","dataFormatter","_rawData","data","_labels","_datasets","getTemplate","widthStyle","heightStyle","onAfterRender","svg","element","querySelector","tooltipEl","legendEl","_updateDimensions","_setupResizeObserver","_parseData","_renderChart","_renderLegend","setData","rect","getBoundingClientRect","_w","_h","setAttribute","ResizeObserver","_resizeObserver","length","observe","labels","datasets","map","ds","i","label","color","borderColor","fillColor","backgroundColor","_plotLeft","_plotTop","_plotRight","_plotBottom","_plotW","_plotH","_calcBounds","min","Infinity","max","v","isFinite","range","Math","_yToPixel","value","_xToPixel","index","count","innerHTML","_renderGrid","_renderAxes","_renderBars","_renderLines","_attachHoverListeners","steps","y","line","_svgEl","x1","y1","x2","y2","stroke","appendChild","_formatAxisValue","text","x","textContent","maxXLabels","floor","step","ceil","rawLabel","String","substring","forEach","dsIdx","points","areaPath","_buildLinePath","area","d","path","p","dot","cx","cy","r","class","numSeries","slotW","groupW","barW","baseline","h","abs","bar","rx","cur","nxt","cp1x","cp2x","join","querySelectorAll","el","col","parseInt","getAttribute","isNaN","addEventListener","e","_showTooltip","_moveTooltip","_hideTooltip","event","html","_esc","displayValue","pipe","toLocaleString","style","display","areaRect","clientX","left","clientY","top","transform","tw","offsetWidth","th","offsetHeight","aw","ah","item","document","createElement","toFixed","Number","isInteger","tag","attrs","createElementNS","k","Object","entries","onBeforeDestroy","disconnect"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./Dialog-GzCkpMad.js");class Modal{static async show(a,e={}){return o.Dialog.showDialog({header:void 0!==e.title&&!!e.title,title:e.title||void 0,body:a,size:"lg",centered:!1,buttons:[{text:"Close",class:"btn-secondary",dismiss:!0}],...e})}static async showModel(o,a={}){const e=o.constructor,n=e?.VIEW_CLASS;if(!n)throw new Error(`Modal.showModel: No VIEW_CLASS defined on ${e?.name||"model"}. Set ${e?.name||"Model"}.VIEW_CLASS = YourView to use this method.`);const l=new n({model:o});return Modal.show(l,a)}static async showModelById(a,e,n={}){const l=new a({id:e});return await l.fetch(),l.id?Modal.showModel(l,n):(o.Dialog.alert({message:`Could not find ${a.name||"record"} with ID: ${e}`,type:"warning"}),null)}static confirm(a,e,n){return o.Dialog.confirm(a,e,n)}static alert(a,e,n){return o.Dialog.alert(a,e,n)}static prompt(a,e,n){return o.Dialog.prompt(a,e,n)}static form(a){return o.Dialog.showForm(a)}static modelForm(a){return o.Dialog.showModelForm(a)}static data(a){return o.Dialog.showData(a)}static dialog(a){return o.Dialog.showDialog(a)}static showError(a){return o.Dialog.alert(a,"Error",{type:"danger"})}static _loadingEl=null;static _loadingCounter=0;static _loadingTimeout=null;static loading(o){"string"==typeof o&&(o={message:o});const{message:a="Loading...",timeout:e=3e4}=o||{};if(Modal._loadingCounter++,1===Modal._loadingCounter){Modal._loadingTimeout&&clearTimeout(Modal._loadingTimeout),Modal._loadingEl||(Modal._loadingEl=document.createElement("div"),Modal._loadingEl.className="mojo-loading-overlay",Modal._loadingEl.innerHTML=`\n <div class="mojo-loading-card">\n <div class="mojo-loading-spinner"></div>\n <div class="mojo-loading-message">${a}</div>\n </div>\n <style>\n .mojo-loading-overlay {\n position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;\n background: rgba(255, 255, 255, 0.4);\n backdrop-filter: blur(2px);\n -webkit-backdrop-filter: blur(2px);\n z-index: 99999;\n display: flex; align-items: center; justify-content: center;\n opacity: 0; transition: opacity 0.2s ease;\n }\n .mojo-loading-overlay.show { opacity: 1; }\n .mojo-loading-card {\n display: flex; align-items: center; gap: 0.85rem;\n background: #fff;\n border: 1px solid #e9ecef;\n border-radius: 12px;\n padding: 1rem 1.5rem;\n box-shadow: 0 4px 24px rgba(0,0,0,0.08), 0 1px 4px rgba(0,0,0,0.04);\n }\n .mojo-loading-spinner {\n width: 22px; height: 22px;\n border: 2.5px solid #e9ecef;\n border-top-color: #0d6efd;\n border-radius: 50%;\n animation: mojo-spin 0.7s linear infinite;\n flex-shrink: 0;\n }\n .mojo-loading-message {\n font-size: 0.88rem;\n font-weight: 500;\n color: #495057;\n white-space: nowrap;\n }\n @keyframes mojo-spin {\n to { transform: rotate(360deg); }\n }\n </style>\n `,document.body.appendChild(Modal._loadingEl));const o=Modal._loadingEl.querySelector(".mojo-loading-message");o&&(o.textContent=a),requestAnimationFrame(()=>{Modal._loadingEl&&Modal._loadingEl.classList.add("show")}),e>0&&(Modal._loadingTimeout=setTimeout(()=>{console.error("Modal.loading timed out."),Modal.hideLoading(!0)},e))}else if(Modal._loadingEl){const o=Modal._loadingEl.querySelector(".mojo-loading-message");o&&(o.textContent=a)}}static hideLoading(o){o?Modal._loadingCounter=0:Modal._loadingCounter--,Modal._loadingCounter<=0&&(Modal._loadingCounter=0,Modal._loadingTimeout&&(clearTimeout(Modal._loadingTimeout),Modal._loadingTimeout=null),Modal._loadingEl&&(Modal._loadingEl.classList.remove("show"),setTimeout(()=>{Modal._loadingEl&&0===Modal._loadingCounter&&(Modal._loadingEl.remove(),Modal._loadingEl=null)},200)))}static showBusy(o){return Modal.loading(o)}static hideBusy(o){return Modal.hideLoading(o)}}exports.default=Modal;
2
- //# sourceMappingURL=Modal-jWZGSSOo.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Modal-jWZGSSOo.js","sources":["../../src/core/views/feedback/Modal.js"],"sourcesContent":["/**\n * Modal — AI-friendly static API for showing views in modal dialogs.\n *\n * Thin wrapper around Dialog's static helpers. All methods are static —\n * there is no instance API. Use Modal instead of `new Dialog()`.\n *\n * @example\n * import Modal from '@core/views/feedback/Modal.js';\n *\n * // Show any View in a modal\n * await Modal.show(new MyView({ model }));\n *\n * // Show a model's VIEW_CLASS automatically\n * await Modal.showModel(userModel);\n *\n * // Fetch a model by ID, then show its VIEW_CLASS\n * await Modal.showModelById(User, 42);\n *\n * // Convenience — no need to import Dialog separately\n * const yes = await Modal.confirm('Delete this?', 'Confirm');\n * await Modal.alert('Done!');\n * const data = await Modal.form({ title: 'Add', fields: [...] });\n * await Modal.modelForm({ model, formConfig: MyForms.edit });\n */\nimport Dialog from './Dialog.js';\n\nclass Modal {\n\n /**\n * Show a View instance in a modal dialog.\n *\n * @param {View} view - The view to display (rendered automatically)\n * @param {object} [options] - Dialog options (size, title, buttons, etc.)\n * @param {string} [options.size='lg'] - Dialog size: sm, md, lg, xl, xxl, fullscreen\n * @param {string|false} [options.title=false] - Dialog title (false = no header)\n * @param {Array} [options.buttons] - Footer buttons\n * @returns {Promise<*>} Resolves with button value or null if dismissed\n *\n * @example\n * await Modal.show(new DeviceView({ model: device }));\n * await Modal.show(new GroupView({ model }), { size: 'xl' });\n */\n static async show(view, options = {}) {\n return Dialog.showDialog({\n header: options.title !== undefined ? !!options.title : false,\n title: options.title || undefined,\n body: view,\n size: 'lg',\n centered: false,\n buttons: [{ text: 'Close', class: 'btn-secondary', dismiss: true }],\n ...options\n });\n }\n\n /**\n * Show a model's VIEW_CLASS in a modal dialog.\n * Looks up `model.constructor.VIEW_CLASS` and instantiates it.\n *\n * @param {Model} model - Model instance (must have VIEW_CLASS on its constructor)\n * @param {object} [options] - Dialog options passed to Modal.show()\n * @returns {Promise<*>} Resolves with button value or null if dismissed\n * @throws {Error} If no VIEW_CLASS is defined on the model's constructor\n *\n * @example\n * await Modal.showModel(userModel);\n * await Modal.showModel(groupModel, { size: 'xl' });\n */\n static async showModel(model, options = {}) {\n const ModelClass = model.constructor;\n const ViewClass = ModelClass?.VIEW_CLASS;\n\n if (!ViewClass) {\n throw new Error(\n `Modal.showModel: No VIEW_CLASS defined on ${ModelClass?.name || 'model'}. ` +\n `Set ${ModelClass?.name || 'Model'}.VIEW_CLASS = YourView to use this method.`\n );\n }\n\n const view = new ViewClass({ model });\n return Modal.show(view, options);\n }\n\n /**\n * Fetch a model by ID, then show its VIEW_CLASS in a modal.\n * Handles the common fetch-then-display pattern.\n *\n * @param {Function} ModelClass - The Model class constructor (e.g., User, Group)\n * @param {string|number} id - The model ID to fetch\n * @param {object} [options] - Dialog options passed to Modal.showModel()\n * @returns {Promise<*>} Resolves with button value, or null if model not found\n *\n * @example\n * await Modal.showModelById(User, 42);\n * await Modal.showModelById(Group, parentId, { size: 'xl' });\n */\n static async showModelById(ModelClass, id, options = {}) {\n const model = new ModelClass({ id });\n await model.fetch();\n\n if (!model.id) {\n Dialog.alert({\n message: `Could not find ${ModelClass.name || 'record'} with ID: ${id}`,\n type: 'warning'\n });\n return null;\n }\n\n return Modal.showModel(model, options);\n }\n\n // ── Convenience aliases ─────────────────────────\n // Re-exported so you never need to import Dialog separately.\n\n /** @see Dialog.confirm */\n static confirm(message, title, options) {\n return Dialog.confirm(message, title, options);\n }\n\n /** @see Dialog.alert */\n static alert(message, title, options) {\n return Dialog.alert(message, title, options);\n }\n\n /** @see Dialog.prompt */\n static prompt(message, title, options) {\n return Dialog.prompt(message, title, options);\n }\n\n /** @see Dialog.showForm */\n static form(options) {\n return Dialog.showForm(options);\n }\n\n /** @see Dialog.showModelForm */\n static modelForm(options) {\n return Dialog.showModelForm(options);\n }\n\n /** @see Dialog.showData */\n static data(options) {\n return Dialog.showData(options);\n }\n\n /** @see Dialog.showDialog — generic dialog with full options control */\n static dialog(options) {\n return Dialog.showDialog(options);\n }\n\n /** @see Dialog.showError */\n static showError(message) {\n return Dialog.alert(message, 'Error', { type: 'danger' });\n }\n\n // ── Loading indicator ───────────────────────\n // Full-screen overlay with spinner for blocking operations.\n // Supports nested calls (counter-based) — call hide for each show.\n // Modern frosted-glass card design with configurable message.\n\n static _loadingEl = null;\n static _loadingCounter = 0;\n static _loadingTimeout = null;\n\n /**\n * Show full-screen loading overlay.\n * @param {string|object} [options] - Message string or { message, timeout }\n * @param {string} [options.message='Loading...'] - Message to display\n * @param {number} [options.timeout=30000] - Auto-hide timeout in ms (0 = no timeout)\n * @example\n * Modal.loading('Saving...');\n * await someApiCall();\n * Modal.hideLoading();\n *\n * // With timeout\n * Modal.loading({ message: 'Processing...', timeout: 60000 });\n */\n static loading(options) {\n if (typeof options === 'string') options = { message: options };\n const { message = 'Loading...', timeout = 30000 } = options || {};\n\n Modal._loadingCounter++;\n\n if (Modal._loadingCounter === 1) {\n if (Modal._loadingTimeout) {\n clearTimeout(Modal._loadingTimeout);\n }\n\n if (!Modal._loadingEl) {\n Modal._loadingEl = document.createElement('div');\n Modal._loadingEl.className = 'mojo-loading-overlay';\n Modal._loadingEl.innerHTML = `\n <div class=\"mojo-loading-card\">\n <div class=\"mojo-loading-spinner\"></div>\n <div class=\"mojo-loading-message\">${message}</div>\n </div>\n <style>\n .mojo-loading-overlay {\n position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;\n background: rgba(255, 255, 255, 0.4);\n backdrop-filter: blur(2px);\n -webkit-backdrop-filter: blur(2px);\n z-index: 99999;\n display: flex; align-items: center; justify-content: center;\n opacity: 0; transition: opacity 0.2s ease;\n }\n .mojo-loading-overlay.show { opacity: 1; }\n .mojo-loading-card {\n display: flex; align-items: center; gap: 0.85rem;\n background: #fff;\n border: 1px solid #e9ecef;\n border-radius: 12px;\n padding: 1rem 1.5rem;\n box-shadow: 0 4px 24px rgba(0,0,0,0.08), 0 1px 4px rgba(0,0,0,0.04);\n }\n .mojo-loading-spinner {\n width: 22px; height: 22px;\n border: 2.5px solid #e9ecef;\n border-top-color: #0d6efd;\n border-radius: 50%;\n animation: mojo-spin 0.7s linear infinite;\n flex-shrink: 0;\n }\n .mojo-loading-message {\n font-size: 0.88rem;\n font-weight: 500;\n color: #495057;\n white-space: nowrap;\n }\n @keyframes mojo-spin {\n to { transform: rotate(360deg); }\n }\n </style>\n `;\n document.body.appendChild(Modal._loadingEl);\n }\n\n // Update message\n const msgEl = Modal._loadingEl.querySelector('.mojo-loading-message');\n if (msgEl) msgEl.textContent = message;\n\n // Trigger fade-in\n requestAnimationFrame(() => {\n if (Modal._loadingEl) Modal._loadingEl.classList.add('show');\n });\n\n // Auto-timeout\n if (timeout > 0) {\n Modal._loadingTimeout = setTimeout(() => {\n console.error('Modal.loading timed out.');\n Modal.hideLoading(true);\n }, timeout);\n }\n } else {\n // Counter > 1: just update the message\n if (Modal._loadingEl) {\n const msgEl = Modal._loadingEl.querySelector('.mojo-loading-message');\n if (msgEl) msgEl.textContent = message;\n }\n }\n }\n\n /**\n * Hide the loading overlay.\n * @param {boolean} [force=false] - Force-hide regardless of counter\n * @example\n * Modal.hideLoading(); // decrement counter\n * Modal.hideLoading(true); // force-hide immediately\n */\n static hideLoading(force) {\n if (force) {\n Modal._loadingCounter = 0;\n } else {\n Modal._loadingCounter--;\n }\n\n if (Modal._loadingCounter <= 0) {\n Modal._loadingCounter = 0;\n\n if (Modal._loadingTimeout) {\n clearTimeout(Modal._loadingTimeout);\n Modal._loadingTimeout = null;\n }\n\n if (Modal._loadingEl) {\n Modal._loadingEl.classList.remove('show');\n setTimeout(() => {\n if (Modal._loadingEl && Modal._loadingCounter === 0) {\n Modal._loadingEl.remove();\n Modal._loadingEl = null;\n }\n }, 200);\n }\n }\n }\n\n /** @alias loading — backward compat with Dialog.showBusy */\n static showBusy(options) { return Modal.loading(options); }\n /** @alias hideLoading — backward compat with Dialog.hideBusy */\n static hideBusy(force) { return Modal.hideLoading(force); }\n}\n\nexport default Modal;\n"],"names":["Modal","show","view","options","Dialog","showDialog","header","title","body","size","centered","buttons","text","class","dismiss","showModel","model","ModelClass","constructor","ViewClass","VIEW_CLASS","Error","name","showModelById","id","fetch","alert","message","type","confirm","prompt","form","showForm","modelForm","showModelForm","data","showData","dialog","showError","static","loading","timeout","_loadingCounter","_loadingTimeout","clearTimeout","_loadingEl","document","createElement","className","innerHTML","appendChild","msgEl","querySelector","textContent","requestAnimationFrame","classList","add","setTimeout","console","error","hideLoading","force","remove","showBusy","hideBusy"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{D as o}from"./Dialog-B0r9puaZ.js";class Modal{static async show(n,a={}){return o.showDialog({header:void 0!==a.title&&!!a.title,title:a.title||void 0,body:n,size:"lg",centered:!1,buttons:[{text:"Close",class:"btn-secondary",dismiss:!0}],...a})}static async showModel(o,n={}){const a=o.constructor,e=a?.VIEW_CLASS;if(!e)throw new Error(`Modal.showModel: No VIEW_CLASS defined on ${a?.name||"model"}. Set ${a?.name||"Model"}.VIEW_CLASS = YourView to use this method.`);const t=new e({model:o});return Modal.show(t,n)}static async showModelById(n,a,e={}){const t=new n({id:a});return await t.fetch(),t.id?Modal.showModel(t,e):(o.alert({message:`Could not find ${n.name||"record"} with ID: ${a}`,type:"warning"}),null)}static confirm(n,a,e){return o.confirm(n,a,e)}static alert(n,a,e){return o.alert(n,a,e)}static prompt(n,a,e){return o.prompt(n,a,e)}static form(n){return o.showForm(n)}static modelForm(n){return o.showModelForm(n)}static data(n){return o.showData(n)}static dialog(n){return o.showDialog(n)}static showError(n){return o.alert(n,"Error",{type:"danger"})}static _loadingEl=null;static _loadingCounter=0;static _loadingTimeout=null;static loading(o){"string"==typeof o&&(o={message:o});const{message:n="Loading...",timeout:a=3e4}=o||{};if(Modal._loadingCounter++,1===Modal._loadingCounter){Modal._loadingTimeout&&clearTimeout(Modal._loadingTimeout),Modal._loadingEl||(Modal._loadingEl=document.createElement("div"),Modal._loadingEl.className="mojo-loading-overlay",Modal._loadingEl.innerHTML=`\n <div class="mojo-loading-card">\n <div class="mojo-loading-spinner"></div>\n <div class="mojo-loading-message">${n}</div>\n </div>\n <style>\n .mojo-loading-overlay {\n position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;\n background: rgba(255, 255, 255, 0.4);\n backdrop-filter: blur(2px);\n -webkit-backdrop-filter: blur(2px);\n z-index: 99999;\n display: flex; align-items: center; justify-content: center;\n opacity: 0; transition: opacity 0.2s ease;\n }\n .mojo-loading-overlay.show { opacity: 1; }\n .mojo-loading-card {\n display: flex; align-items: center; gap: 0.85rem;\n background: #fff;\n border: 1px solid #e9ecef;\n border-radius: 12px;\n padding: 1rem 1.5rem;\n box-shadow: 0 4px 24px rgba(0,0,0,0.08), 0 1px 4px rgba(0,0,0,0.04);\n }\n .mojo-loading-spinner {\n width: 22px; height: 22px;\n border: 2.5px solid #e9ecef;\n border-top-color: #0d6efd;\n border-radius: 50%;\n animation: mojo-spin 0.7s linear infinite;\n flex-shrink: 0;\n }\n .mojo-loading-message {\n font-size: 0.88rem;\n font-weight: 500;\n color: #495057;\n white-space: nowrap;\n }\n @keyframes mojo-spin {\n to { transform: rotate(360deg); }\n }\n </style>\n `,document.body.appendChild(Modal._loadingEl));const o=Modal._loadingEl.querySelector(".mojo-loading-message");o&&(o.textContent=n),requestAnimationFrame(()=>{Modal._loadingEl&&Modal._loadingEl.classList.add("show")}),a>0&&(Modal._loadingTimeout=setTimeout(()=>{console.error("Modal.loading timed out."),Modal.hideLoading(!0)},a))}else if(Modal._loadingEl){const o=Modal._loadingEl.querySelector(".mojo-loading-message");o&&(o.textContent=n)}}static hideLoading(o){o?Modal._loadingCounter=0:Modal._loadingCounter--,Modal._loadingCounter<=0&&(Modal._loadingCounter=0,Modal._loadingTimeout&&(clearTimeout(Modal._loadingTimeout),Modal._loadingTimeout=null),Modal._loadingEl&&(Modal._loadingEl.classList.remove("show"),setTimeout(()=>{Modal._loadingEl&&0===Modal._loadingCounter&&(Modal._loadingEl.remove(),Modal._loadingEl=null)},200)))}static showBusy(o){return Modal.loading(o)}static hideBusy(o){return Modal.hideLoading(o)}}export{Modal as default};
2
- //# sourceMappingURL=Modal-xSaurlfZ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"Modal-xSaurlfZ.js","sources":["../../src/core/views/feedback/Modal.js"],"sourcesContent":["/**\n * Modal — AI-friendly static API for showing views in modal dialogs.\n *\n * Thin wrapper around Dialog's static helpers. All methods are static —\n * there is no instance API. Use Modal instead of `new Dialog()`.\n *\n * @example\n * import Modal from '@core/views/feedback/Modal.js';\n *\n * // Show any View in a modal\n * await Modal.show(new MyView({ model }));\n *\n * // Show a model's VIEW_CLASS automatically\n * await Modal.showModel(userModel);\n *\n * // Fetch a model by ID, then show its VIEW_CLASS\n * await Modal.showModelById(User, 42);\n *\n * // Convenience — no need to import Dialog separately\n * const yes = await Modal.confirm('Delete this?', 'Confirm');\n * await Modal.alert('Done!');\n * const data = await Modal.form({ title: 'Add', fields: [...] });\n * await Modal.modelForm({ model, formConfig: MyForms.edit });\n */\nimport Dialog from './Dialog.js';\n\nclass Modal {\n\n /**\n * Show a View instance in a modal dialog.\n *\n * @param {View} view - The view to display (rendered automatically)\n * @param {object} [options] - Dialog options (size, title, buttons, etc.)\n * @param {string} [options.size='lg'] - Dialog size: sm, md, lg, xl, xxl, fullscreen\n * @param {string|false} [options.title=false] - Dialog title (false = no header)\n * @param {Array} [options.buttons] - Footer buttons\n * @returns {Promise<*>} Resolves with button value or null if dismissed\n *\n * @example\n * await Modal.show(new DeviceView({ model: device }));\n * await Modal.show(new GroupView({ model }), { size: 'xl' });\n */\n static async show(view, options = {}) {\n return Dialog.showDialog({\n header: options.title !== undefined ? !!options.title : false,\n title: options.title || undefined,\n body: view,\n size: 'lg',\n centered: false,\n buttons: [{ text: 'Close', class: 'btn-secondary', dismiss: true }],\n ...options\n });\n }\n\n /**\n * Show a model's VIEW_CLASS in a modal dialog.\n * Looks up `model.constructor.VIEW_CLASS` and instantiates it.\n *\n * @param {Model} model - Model instance (must have VIEW_CLASS on its constructor)\n * @param {object} [options] - Dialog options passed to Modal.show()\n * @returns {Promise<*>} Resolves with button value or null if dismissed\n * @throws {Error} If no VIEW_CLASS is defined on the model's constructor\n *\n * @example\n * await Modal.showModel(userModel);\n * await Modal.showModel(groupModel, { size: 'xl' });\n */\n static async showModel(model, options = {}) {\n const ModelClass = model.constructor;\n const ViewClass = ModelClass?.VIEW_CLASS;\n\n if (!ViewClass) {\n throw new Error(\n `Modal.showModel: No VIEW_CLASS defined on ${ModelClass?.name || 'model'}. ` +\n `Set ${ModelClass?.name || 'Model'}.VIEW_CLASS = YourView to use this method.`\n );\n }\n\n const view = new ViewClass({ model });\n return Modal.show(view, options);\n }\n\n /**\n * Fetch a model by ID, then show its VIEW_CLASS in a modal.\n * Handles the common fetch-then-display pattern.\n *\n * @param {Function} ModelClass - The Model class constructor (e.g., User, Group)\n * @param {string|number} id - The model ID to fetch\n * @param {object} [options] - Dialog options passed to Modal.showModel()\n * @returns {Promise<*>} Resolves with button value, or null if model not found\n *\n * @example\n * await Modal.showModelById(User, 42);\n * await Modal.showModelById(Group, parentId, { size: 'xl' });\n */\n static async showModelById(ModelClass, id, options = {}) {\n const model = new ModelClass({ id });\n await model.fetch();\n\n if (!model.id) {\n Dialog.alert({\n message: `Could not find ${ModelClass.name || 'record'} with ID: ${id}`,\n type: 'warning'\n });\n return null;\n }\n\n return Modal.showModel(model, options);\n }\n\n // ── Convenience aliases ─────────────────────────\n // Re-exported so you never need to import Dialog separately.\n\n /** @see Dialog.confirm */\n static confirm(message, title, options) {\n return Dialog.confirm(message, title, options);\n }\n\n /** @see Dialog.alert */\n static alert(message, title, options) {\n return Dialog.alert(message, title, options);\n }\n\n /** @see Dialog.prompt */\n static prompt(message, title, options) {\n return Dialog.prompt(message, title, options);\n }\n\n /** @see Dialog.showForm */\n static form(options) {\n return Dialog.showForm(options);\n }\n\n /** @see Dialog.showModelForm */\n static modelForm(options) {\n return Dialog.showModelForm(options);\n }\n\n /** @see Dialog.showData */\n static data(options) {\n return Dialog.showData(options);\n }\n\n /** @see Dialog.showDialog — generic dialog with full options control */\n static dialog(options) {\n return Dialog.showDialog(options);\n }\n\n /** @see Dialog.showError */\n static showError(message) {\n return Dialog.alert(message, 'Error', { type: 'danger' });\n }\n\n // ── Loading indicator ───────────────────────\n // Full-screen overlay with spinner for blocking operations.\n // Supports nested calls (counter-based) — call hide for each show.\n // Modern frosted-glass card design with configurable message.\n\n static _loadingEl = null;\n static _loadingCounter = 0;\n static _loadingTimeout = null;\n\n /**\n * Show full-screen loading overlay.\n * @param {string|object} [options] - Message string or { message, timeout }\n * @param {string} [options.message='Loading...'] - Message to display\n * @param {number} [options.timeout=30000] - Auto-hide timeout in ms (0 = no timeout)\n * @example\n * Modal.loading('Saving...');\n * await someApiCall();\n * Modal.hideLoading();\n *\n * // With timeout\n * Modal.loading({ message: 'Processing...', timeout: 60000 });\n */\n static loading(options) {\n if (typeof options === 'string') options = { message: options };\n const { message = 'Loading...', timeout = 30000 } = options || {};\n\n Modal._loadingCounter++;\n\n if (Modal._loadingCounter === 1) {\n if (Modal._loadingTimeout) {\n clearTimeout(Modal._loadingTimeout);\n }\n\n if (!Modal._loadingEl) {\n Modal._loadingEl = document.createElement('div');\n Modal._loadingEl.className = 'mojo-loading-overlay';\n Modal._loadingEl.innerHTML = `\n <div class=\"mojo-loading-card\">\n <div class=\"mojo-loading-spinner\"></div>\n <div class=\"mojo-loading-message\">${message}</div>\n </div>\n <style>\n .mojo-loading-overlay {\n position: fixed; top: 0; left: 0; width: 100vw; height: 100vh;\n background: rgba(255, 255, 255, 0.4);\n backdrop-filter: blur(2px);\n -webkit-backdrop-filter: blur(2px);\n z-index: 99999;\n display: flex; align-items: center; justify-content: center;\n opacity: 0; transition: opacity 0.2s ease;\n }\n .mojo-loading-overlay.show { opacity: 1; }\n .mojo-loading-card {\n display: flex; align-items: center; gap: 0.85rem;\n background: #fff;\n border: 1px solid #e9ecef;\n border-radius: 12px;\n padding: 1rem 1.5rem;\n box-shadow: 0 4px 24px rgba(0,0,0,0.08), 0 1px 4px rgba(0,0,0,0.04);\n }\n .mojo-loading-spinner {\n width: 22px; height: 22px;\n border: 2.5px solid #e9ecef;\n border-top-color: #0d6efd;\n border-radius: 50%;\n animation: mojo-spin 0.7s linear infinite;\n flex-shrink: 0;\n }\n .mojo-loading-message {\n font-size: 0.88rem;\n font-weight: 500;\n color: #495057;\n white-space: nowrap;\n }\n @keyframes mojo-spin {\n to { transform: rotate(360deg); }\n }\n </style>\n `;\n document.body.appendChild(Modal._loadingEl);\n }\n\n // Update message\n const msgEl = Modal._loadingEl.querySelector('.mojo-loading-message');\n if (msgEl) msgEl.textContent = message;\n\n // Trigger fade-in\n requestAnimationFrame(() => {\n if (Modal._loadingEl) Modal._loadingEl.classList.add('show');\n });\n\n // Auto-timeout\n if (timeout > 0) {\n Modal._loadingTimeout = setTimeout(() => {\n console.error('Modal.loading timed out.');\n Modal.hideLoading(true);\n }, timeout);\n }\n } else {\n // Counter > 1: just update the message\n if (Modal._loadingEl) {\n const msgEl = Modal._loadingEl.querySelector('.mojo-loading-message');\n if (msgEl) msgEl.textContent = message;\n }\n }\n }\n\n /**\n * Hide the loading overlay.\n * @param {boolean} [force=false] - Force-hide regardless of counter\n * @example\n * Modal.hideLoading(); // decrement counter\n * Modal.hideLoading(true); // force-hide immediately\n */\n static hideLoading(force) {\n if (force) {\n Modal._loadingCounter = 0;\n } else {\n Modal._loadingCounter--;\n }\n\n if (Modal._loadingCounter <= 0) {\n Modal._loadingCounter = 0;\n\n if (Modal._loadingTimeout) {\n clearTimeout(Modal._loadingTimeout);\n Modal._loadingTimeout = null;\n }\n\n if (Modal._loadingEl) {\n Modal._loadingEl.classList.remove('show');\n setTimeout(() => {\n if (Modal._loadingEl && Modal._loadingCounter === 0) {\n Modal._loadingEl.remove();\n Modal._loadingEl = null;\n }\n }, 200);\n }\n }\n }\n\n /** @alias loading — backward compat with Dialog.showBusy */\n static showBusy(options) { return Modal.loading(options); }\n /** @alias hideLoading — backward compat with Dialog.hideBusy */\n static hideBusy(force) { return Modal.hideLoading(force); }\n}\n\nexport default Modal;\n"],"names":["Modal","show","view","options","Dialog","showDialog","header","title","body","size","centered","buttons","text","class","dismiss","showModel","model","ModelClass","constructor","ViewClass","VIEW_CLASS","Error","name","showModelById","id","fetch","alert","message","type","confirm","prompt","form","showForm","modelForm","showModelForm","data","showData","dialog","showError","static","loading","timeout","_loadingCounter","_loadingTimeout","clearTimeout","_loadingEl","document","createElement","className","innerHTML","appendChild","msgEl","querySelector","textContent","requestAnimationFrame","classList","add","setTimeout","console","error","hideLoading","force","remove","showBusy","hideBusy"],"mappings":"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"}