web-mojo 2.2.97 → 2.2.99

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 (127) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/dist/admin.cjs.js +1 -1
  3. package/dist/admin.es.js +1 -1
  4. package/dist/auth.cjs.js +1 -1
  5. package/dist/auth.es.js +1 -1
  6. package/dist/charts.cjs.js +1 -1
  7. package/dist/charts.es.js +1 -1
  8. package/dist/chunks/{AssistantPanelView-BR17_qm2.js → AssistantPanelView-7LrbfDui.js} +2 -2
  9. package/dist/chunks/{AssistantPanelView-BR17_qm2.js.map → AssistantPanelView-7LrbfDui.js.map} +1 -1
  10. package/dist/chunks/{AssistantPanelView-DFcOLZn2.js → AssistantPanelView-BVy5oJ22.js} +2 -2
  11. package/dist/chunks/{AssistantPanelView-DFcOLZn2.js.map → AssistantPanelView-BVy5oJ22.js.map} +1 -1
  12. package/dist/chunks/ChatView-BB87MPeq.js +2 -0
  13. package/dist/chunks/ChatView-BB87MPeq.js.map +1 -0
  14. package/dist/chunks/ChatView-DiniUXTJ.js +2 -0
  15. package/dist/chunks/ChatView-DiniUXTJ.js.map +1 -0
  16. package/dist/chunks/{Collection-DXcf6bOu.js → Collection-C39Oy2q0.js} +2 -2
  17. package/dist/chunks/{Collection-DXcf6bOu.js.map → Collection-C39Oy2q0.js.map} +1 -1
  18. package/dist/chunks/{Collection-DwIvN0yq.js → Collection-CyK0u557.js} +2 -2
  19. package/dist/chunks/{Collection-DwIvN0yq.js.map → Collection-CyK0u557.js.map} +1 -1
  20. package/dist/chunks/{ContextMenu-BWDMrvKJ.js → ContextMenu-D-C7V6J6.js} +2 -2
  21. package/dist/chunks/{ContextMenu-BWDMrvKJ.js.map → ContextMenu-D-C7V6J6.js.map} +1 -1
  22. package/dist/chunks/{ContextMenu-oonPaMfx.js → ContextMenu-hjqR1pGW.js} +2 -2
  23. package/dist/chunks/{ContextMenu-oonPaMfx.js.map → ContextMenu-hjqR1pGW.js.map} +1 -1
  24. package/dist/chunks/{DataView-DdrFwbjE.js → DataView-6lhf855r.js} +2 -2
  25. package/dist/chunks/{DataView-DdrFwbjE.js.map → DataView-6lhf855r.js.map} +1 -1
  26. package/dist/chunks/{DataView-BqQhHIhZ.js → DataView-Bb83ww5U.js} +2 -2
  27. package/dist/chunks/{DataView-BqQhHIhZ.js.map → DataView-Bb83ww5U.js.map} +1 -1
  28. package/dist/chunks/{Dialog-BO06wfM8.js → Dialog-B0r9puaZ.js} +3 -3
  29. package/dist/chunks/Dialog-B0r9puaZ.js.map +1 -0
  30. package/dist/chunks/{Dialog-DVabZtKC.js → Dialog-GzCkpMad.js} +3 -3
  31. package/dist/chunks/Dialog-GzCkpMad.js.map +1 -0
  32. package/dist/chunks/{FormView-CW7sg6-U.js → FormView-DEROOklJ.js} +3 -3
  33. package/dist/chunks/{FormView-CW7sg6-U.js.map → FormView-DEROOklJ.js.map} +1 -1
  34. package/dist/chunks/{FormView-DbxACn7-.js → FormView-UmvPskWT.js} +3 -3
  35. package/dist/chunks/{FormView-DbxACn7-.js.map → FormView-UmvPskWT.js.map} +1 -1
  36. package/dist/chunks/{ListView-ZsMVvvUQ.js → ListView-D_hOtfWZ.js} +2 -2
  37. package/dist/chunks/{ListView-ZsMVvvUQ.js.map → ListView-D_hOtfWZ.js.map} +1 -1
  38. package/dist/chunks/{ListView-DLyS4Nfd.js → ListView-Jkke6pU1.js} +2 -2
  39. package/dist/chunks/{ListView-DLyS4Nfd.js.map → ListView-Jkke6pU1.js.map} +1 -1
  40. package/dist/chunks/{MetricsCountryMapView-197-WHEu.js → MetricsCountryMapView-UdvJWArx.js} +2 -2
  41. package/dist/chunks/{MetricsCountryMapView-197-WHEu.js.map → MetricsCountryMapView-UdvJWArx.js.map} +1 -1
  42. package/dist/chunks/{MetricsCountryMapView-BgLr-rjI.js → MetricsCountryMapView-jLWCL6Hm.js} +2 -2
  43. package/dist/chunks/{MetricsCountryMapView-BgLr-rjI.js.map → MetricsCountryMapView-jLWCL6Hm.js.map} +1 -1
  44. package/dist/chunks/{MetricsMiniChartWidget-BMF6wIF9.js → MetricsMiniChartWidget-CV-McxOl.js} +2 -2
  45. package/dist/chunks/{MetricsMiniChartWidget-BMF6wIF9.js.map → MetricsMiniChartWidget-CV-McxOl.js.map} +1 -1
  46. package/dist/chunks/{MetricsMiniChartWidget-DrIFgvOj.js → MetricsMiniChartWidget-DG0DeDuR.js} +2 -2
  47. package/dist/chunks/{MetricsMiniChartWidget-DrIFgvOj.js.map → MetricsMiniChartWidget-DG0DeDuR.js.map} +1 -1
  48. package/dist/chunks/{MiniPieChart-eTjaZQGx.js → MiniPieChart-B3sM4Bjv.js} +2 -2
  49. package/dist/chunks/{MiniPieChart-eTjaZQGx.js.map → MiniPieChart-B3sM4Bjv.js.map} +1 -1
  50. package/dist/chunks/{MiniPieChart-DOFUDyEj.js → MiniPieChart-DL5Rynvm.js} +2 -2
  51. package/dist/chunks/{MiniPieChart-DOFUDyEj.js.map → MiniPieChart-DL5Rynvm.js.map} +1 -1
  52. package/dist/chunks/{MiniSeriesChart-DPwiySbr.js → MiniSeriesChart-C4DPVbU_.js} +2 -2
  53. package/dist/chunks/{MiniSeriesChart-DPwiySbr.js.map → MiniSeriesChart-C4DPVbU_.js.map} +1 -1
  54. package/dist/chunks/{MiniSeriesChart-Cs8F8j0y.js → MiniSeriesChart-DdNMLwfh.js} +2 -2
  55. package/dist/chunks/{MiniSeriesChart-Cs8F8j0y.js.map → MiniSeriesChart-DdNMLwfh.js.map} +1 -1
  56. package/dist/chunks/{Modal-MSmE_82x.js → Modal-jWZGSSOo.js} +2 -2
  57. package/dist/chunks/{Modal-MSmE_82x.js.map → Modal-jWZGSSOo.js.map} +1 -1
  58. package/dist/chunks/{Modal-D_bVwX-V.js → Modal-xSaurlfZ.js} +2 -2
  59. package/dist/chunks/{Modal-D_bVwX-V.js.map → Modal-xSaurlfZ.js.map} +1 -1
  60. package/dist/chunks/{Passkeys-CZ_oTngY.js → Passkeys-BPV1gNkR.js} +2 -2
  61. package/dist/chunks/{Passkeys-CZ_oTngY.js.map → Passkeys-BPV1gNkR.js.map} +1 -1
  62. package/dist/chunks/{Passkeys-C6VT-snT.js → Passkeys-CIRjqi7n.js} +2 -2
  63. package/dist/chunks/{Passkeys-C6VT-snT.js.map → Passkeys-CIRjqi7n.js.map} +1 -1
  64. package/dist/chunks/{TokenManager-BUzSwY3u.js → TokenManager-CKgK0MIz.js} +2 -2
  65. package/dist/chunks/{TokenManager-BUzSwY3u.js.map → TokenManager-CKgK0MIz.js.map} +1 -1
  66. package/dist/chunks/{TokenManager-BzMDp2Ym.js → TokenManager-Cu0YmxAx.js} +2 -2
  67. package/dist/chunks/{TokenManager-BzMDp2Ym.js.map → TokenManager-Cu0YmxAx.js.map} +1 -1
  68. package/dist/chunks/{UserProfileView-NpL2wU6h.js → UserProfileView-BXT8COCF.js} +2 -2
  69. package/dist/chunks/{UserProfileView-NpL2wU6h.js.map → UserProfileView-BXT8COCF.js.map} +1 -1
  70. package/dist/chunks/{UserProfileView-CxrYFgMl.js → UserProfileView-Slj-9C__.js} +2 -2
  71. package/dist/chunks/{UserProfileView-CxrYFgMl.js.map → UserProfileView-Slj-9C__.js.map} +1 -1
  72. package/dist/chunks/{WebApp-DpuN7rZ3.js → WebApp-CXkNqtZX.js} +2 -2
  73. package/dist/chunks/{WebApp-DpuN7rZ3.js.map → WebApp-CXkNqtZX.js.map} +1 -1
  74. package/dist/chunks/{WebApp-CyeQb4cM.js → WebApp-m6YeJFWY.js} +2 -2
  75. package/dist/chunks/{WebApp-CyeQb4cM.js.map → WebApp-m6YeJFWY.js.map} +1 -1
  76. package/dist/chunks/{WebSocketClient-CPJGeiPN.js → WebSocketClient-BQAZr8C4.js} +2 -2
  77. package/dist/chunks/{WebSocketClient-CPJGeiPN.js.map → WebSocketClient-BQAZr8C4.js.map} +1 -1
  78. package/dist/chunks/{WebSocketClient-Cjmr5C_u.js → WebSocketClient-YR5d82h8.js} +2 -2
  79. package/dist/chunks/{WebSocketClient-Cjmr5C_u.js.map → WebSocketClient-YR5d82h8.js.map} +1 -1
  80. package/dist/chunks/admin-BsmX-4pc.js +2 -0
  81. package/dist/chunks/admin-BsmX-4pc.js.map +1 -0
  82. package/dist/chunks/admin-CzhyMUYh.js +2 -0
  83. package/dist/chunks/admin-CzhyMUYh.js.map +1 -0
  84. package/dist/chunks/{index-D3v4btI8.js → index-CSmG_P2r.js} +2 -2
  85. package/dist/chunks/{index-D3v4btI8.js.map → index-CSmG_P2r.js.map} +1 -1
  86. package/dist/chunks/{index-BPn9cZzq.js → index-uo77m1wt.js} +2 -2
  87. package/dist/chunks/{index-BPn9cZzq.js.map → index-uo77m1wt.js.map} +1 -1
  88. package/dist/chunks/{version-hgKnkQjn.js → version-C1YeA5NE.js} +2 -2
  89. package/dist/chunks/{version-hgKnkQjn.js.map → version-C1YeA5NE.js.map} +1 -1
  90. package/dist/chunks/{version-CT8Bg3nZ.js → version-CZlqPaoP.js} +2 -2
  91. package/dist/chunks/{version-CT8Bg3nZ.js.map → version-CZlqPaoP.js.map} +1 -1
  92. package/dist/css/web-mojo.css +1 -1
  93. package/dist/docit.cjs.js +1 -1
  94. package/dist/docit.es.js +1 -1
  95. package/dist/index.cjs.js +1 -1
  96. package/dist/index.cjs.js.map +1 -1
  97. package/dist/index.es.js +1 -1
  98. package/dist/index.es.js.map +1 -1
  99. package/dist/lightbox.cjs.js +1 -1
  100. package/dist/lightbox.cjs.js.map +1 -1
  101. package/dist/lightbox.es.js +1 -1
  102. package/dist/lightbox.es.js.map +1 -1
  103. package/dist/map.cjs.js +1 -1
  104. package/dist/map.es.js +1 -1
  105. package/dist/timeline.cjs.js +1 -1
  106. package/dist/timeline.es.js +1 -1
  107. package/dist/user-profile.cjs.js +1 -1
  108. package/dist/user-profile.es.js +1 -1
  109. package/dist/web-mojo.lite.iife.js +109 -2
  110. package/dist/web-mojo.lite.iife.js.map +1 -1
  111. package/dist/web-mojo.lite.iife.min.js +98 -98
  112. package/dist/web-mojo.lite.iife.min.js.map +1 -1
  113. package/package.json +1 -1
  114. package/dist/chunks/ChatView-DzdJkSRe.js +0 -2
  115. package/dist/chunks/ChatView-DzdJkSRe.js.map +0 -1
  116. package/dist/chunks/ChatView-E-Y3ZAn2.js +0 -2
  117. package/dist/chunks/ChatView-E-Y3ZAn2.js.map +0 -1
  118. package/dist/chunks/Dialog-BO06wfM8.js.map +0 -1
  119. package/dist/chunks/Dialog-DVabZtKC.js.map +0 -1
  120. package/dist/chunks/PDFViewer-Dv2OEqy0.js +0 -2
  121. package/dist/chunks/PDFViewer-Dv2OEqy0.js.map +0 -1
  122. package/dist/chunks/PDFViewer-b0l9yCQw.js +0 -2
  123. package/dist/chunks/PDFViewer-b0l9yCQw.js.map +0 -1
  124. package/dist/chunks/admin-B4J2Qfvt.js +0 -2
  125. package/dist/chunks/admin-B4J2Qfvt.js.map +0 -1
  126. package/dist/chunks/admin-CYy-fnPz.js +0 -2
  127. package/dist/chunks/admin-CYy-fnPz.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"MiniSeriesChart-Cs8F8j0y.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
+ {"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 +1,2 @@
1
- "use strict";Object.defineProperty(exports,Symbol.toStringTag,{value:"Module"});const o=require("./Dialog-DVabZtKC.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-MSmE_82x.js.map
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 +1 @@
1
- {"version":3,"file":"Modal-MSmE_82x.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
+ {"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 +1,2 @@
1
- import{D as o}from"./Dialog-BO06wfM8.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-D_bVwX-V.js.map
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 +1 @@
1
- {"version":3,"file":"Modal-D_bVwX-V.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
+ {"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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"}