drizzle-cube 0.6.4 → 0.6.5
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.
- package/dist/adapters/ActivityGridChart.config-Bvi50jl_.cjs +1 -0
- package/dist/adapters/ActivityGridChart.config-BwswifOD.js +2 -0
- package/dist/adapters/AreaChart.config-Cehf1Kjo.cjs +1 -0
- package/dist/adapters/AreaChart.config-DC-gnmli.js +2 -0
- package/dist/adapters/BarChart.config-BY53r96T.cjs +1 -0
- package/dist/adapters/BarChart.config-DJN5Oqmw.js +2 -0
- package/dist/adapters/BoxPlotChart.config-9hLT3yMs.js +2 -0
- package/dist/adapters/BoxPlotChart.config-D9P4PMTf.cjs +1 -0
- package/dist/adapters/BubbleChart.config-CEVSsy7u.js +2 -0
- package/dist/adapters/BubbleChart.config-Cji0z0Tb.cjs +1 -0
- package/dist/adapters/CandlestickChart.config-DPv76FmM.cjs +1 -0
- package/dist/adapters/CandlestickChart.config-tcHTorLu.js +2 -0
- package/dist/adapters/DataTable.config-D4txBrlQ.cjs +1 -0
- package/dist/adapters/DataTable.config-DrObkanI.js +2 -0
- package/dist/adapters/FunnelChart.config-BFYSkibE.js +2 -0
- package/dist/adapters/FunnelChart.config-BTSFeha-.cjs +1 -0
- package/dist/adapters/GaugeChart.config-BFz6NZfT.js +2 -0
- package/dist/adapters/GaugeChart.config-DJKD6oh8.cjs +1 -0
- package/dist/adapters/HeatMapChart.config-C3EZl9Sy.cjs +1 -0
- package/dist/adapters/HeatMapChart.config-jUCb5NAE.js +2 -0
- package/dist/adapters/KpiDelta.config-DhuealNk.js +2 -0
- package/dist/adapters/KpiDelta.config-m6FEIeWo.cjs +1 -0
- package/dist/adapters/KpiNumber.config-Cmd7eHmg.cjs +1 -0
- package/dist/adapters/KpiNumber.config-KQdKrkK-.js +2 -0
- package/dist/adapters/KpiText.config-D_pU4jH3.cjs +1 -0
- package/dist/adapters/KpiText.config-V8SvhllA.js +2 -0
- package/dist/adapters/LineChart.config-BuWM0TJx.js +2 -0
- package/dist/adapters/LineChart.config-CsxJ3f5A.cjs +1 -0
- package/dist/adapters/MarkdownChart.config-CJdjenj7.cjs +1 -0
- package/dist/adapters/MarkdownChart.config-oCWrAuom.js +2 -0
- package/dist/adapters/MeasureProfileChart.config-DBLnhtOk.cjs +1 -0
- package/dist/adapters/MeasureProfileChart.config-DWg0jzxA.js +2 -0
- package/dist/adapters/PieChart.config-D3qI6nbM.cjs +1 -0
- package/dist/adapters/PieChart.config-R2rcul2D.js +2 -0
- package/dist/adapters/RadarChart.config-BlK8QuDi.js +2 -0
- package/dist/adapters/RadarChart.config-fH3ce10I.cjs +1 -0
- package/dist/adapters/RadialBarChart.config-CqCnb27I.js +2 -0
- package/dist/adapters/RadialBarChart.config-DQQHJOCs.cjs +1 -0
- package/dist/adapters/RetentionCombinedChart.config-BFJ8i-kp.js +2 -0
- package/dist/adapters/RetentionCombinedChart.config-B_Wd_YjX.cjs +1 -0
- package/dist/adapters/RetentionHeatmap.config-BLqu9-Ft.js +2 -0
- package/dist/adapters/RetentionHeatmap.config-MvOPw_Dd.cjs +1 -0
- package/dist/adapters/SankeyChart.config-C_4u9Xiq.js +2 -0
- package/dist/adapters/SankeyChart.config-EH6wsjPr.cjs +1 -0
- package/dist/adapters/ScatterChart.config-D-MlQ7mP.js +2 -0
- package/dist/adapters/ScatterChart.config-DmwiEBN-.cjs +1 -0
- package/dist/adapters/SunburstChart.config-BRr_as_L.js +2 -0
- package/dist/adapters/SunburstChart.config-CptDj8e4.cjs +1 -0
- package/dist/adapters/TreeMapChart.config-D5wX2xaT.cjs +1 -0
- package/dist/adapters/TreeMapChart.config-Dyhwpwq3.js +2 -0
- package/dist/adapters/WaterfallChart.config-B_LGJIov.js +2 -0
- package/dist/adapters/WaterfallChart.config-Q4Fv196W.cjs +1 -0
- package/dist/adapters/{compiler-DyyBaLry.cjs → compiler-D0v5KJhv.cjs} +2 -2
- package/dist/adapters/{compiler-lG6eNsoI.js → compiler-ZruQ85ff.js} +35 -30
- package/dist/adapters/core/index.cjs +1 -1
- package/dist/adapters/core/index.js +1 -1
- package/dist/adapters/{core-F1pCQPde.cjs → core-CVqTwOR3.cjs} +1 -1
- package/dist/adapters/{core-Bbchr0ui.js → core-DoSUiMmv.js} +60 -60
- package/dist/adapters/express/index.cjs +2 -2
- package/dist/adapters/express/index.js +80 -75
- package/dist/adapters/fastify/index.cjs +2 -2
- package/dist/adapters/fastify/index.js +63 -58
- package/dist/adapters/{handler-DRZb2ip6.cjs → handler-DyIyrFFp.cjs} +3 -3
- package/dist/adapters/{handler-u8FyzPBT.js → handler-j74EJDdo.js} +28 -28
- package/dist/adapters/hono/index.cjs +2 -2
- package/dist/adapters/hono/index.js +57 -52
- package/dist/adapters/mcp-tools.cjs +1 -1
- package/dist/adapters/mcp-tools.js +2 -2
- package/dist/adapters/mcp-transport-BuU5CrKL.cjs +40 -0
- package/dist/adapters/mcp-transport-l8DhKzR5.js +601 -0
- package/dist/adapters/mcp-transport.d.ts +21 -3
- package/dist/adapters/nextjs/index.cjs +1 -1
- package/dist/adapters/nextjs/index.js +110 -105
- package/dist/adapters/{openai-CmMzrs1Y.js → openai-BCSKRcbD.js} +10 -10
- package/dist/{server/openai-DhzGY9R4.js → adapters/openai-BjR3ohaS.js} +1 -1
- package/dist/{server/openai-B4kAJTSD.cjs → adapters/openai-ClVVLjNl.cjs} +2 -2
- package/dist/adapters/{openai-Cdf2wWZA.cjs → openai-CsVXOcJZ.cjs} +1 -1
- package/dist/adapters/utils-CBR-9AMD.cjs +128 -0
- package/dist/adapters/{utils-BPWZsX7k.js → utils-U7gV5wQL.js} +789 -788
- package/dist/adapters/utils.cjs +1 -1
- package/dist/adapters/utils.d.ts +16 -4
- package/dist/adapters/utils.js +1 -1
- package/dist/cjs/adapters/mcp-transport.d.ts +21 -3
- package/dist/cjs/adapters/utils.d.ts +16 -4
- package/dist/cjs/server/executors/sqlite-executor.d.ts +8 -2
- package/dist/client/charts.js +13 -13
- package/dist/client/chunks/ConfirmModal-D6eLc9NO.js +3283 -0
- package/dist/client/chunks/ConfirmModal-D6eLc9NO.js.map +1 -0
- package/dist/client/chunks/{DashboardEditModal-Cs1ig1_V.js → DashboardEditModal-DFQSxR_C.js} +1134 -4389
- package/dist/client/chunks/DashboardEditModal-DFQSxR_C.js.map +1 -0
- package/dist/client/chunks/{RetentionCombinedChart-BgbDhsPz.js → RetentionCombinedChart-DY7wKLs5.js} +3 -3
- package/dist/client/chunks/{RetentionCombinedChart-BgbDhsPz.js.map → RetentionCombinedChart-DY7wKLs5.js.map} +1 -1
- package/dist/client/chunks/{RetentionHeatmap-DjXZaTPq.js → RetentionHeatmap-iNCG-dLd.js} +2 -2
- package/dist/client/chunks/{RetentionHeatmap-DjXZaTPq.js.map → RetentionHeatmap-iNCG-dLd.js.map} +1 -1
- package/dist/client/chunks/{analysis-builder-B64yaeDe.js → analysis-builder-CBZ7lOC-.js} +311 -311
- package/dist/client/chunks/{analysis-builder-B64yaeDe.js.map → analysis-builder-CBZ7lOC-.js.map} +1 -1
- package/dist/client/chunks/{analysis-builder-shared-CD0n2Nb8.js → analysis-builder-shared-8alCn-zw.js} +411 -411
- package/dist/client/chunks/{analysis-builder-shared-CD0n2Nb8.js.map → analysis-builder-shared-8alCn-zw.js.map} +1 -1
- package/dist/client/chunks/{chart-activity-grid-DX0SJbxs.js → chart-activity-grid-DDqFVWoa.js} +5 -2
- package/dist/client/chunks/{chart-activity-grid-DX0SJbxs.js.map → chart-activity-grid-DDqFVWoa.js.map} +1 -1
- package/dist/client/chunks/{chart-area-of01_62R.js → chart-area-BHxPNsmc.js} +2 -2
- package/dist/client/chunks/{chart-area-of01_62R.js.map → chart-area-BHxPNsmc.js.map} +1 -1
- package/dist/client/chunks/{chart-bar-BqelQE_I.js → chart-bar-DAO3PPcE.js} +3 -3
- package/dist/client/chunks/{chart-bar-BqelQE_I.js.map → chart-bar-DAO3PPcE.js.map} +1 -1
- package/dist/client/chunks/{chart-box-plot-kkBixZ27.js → chart-box-plot-CUpFyQQk.js} +2 -2
- package/dist/client/chunks/{chart-box-plot-kkBixZ27.js.map → chart-box-plot-CUpFyQQk.js.map} +1 -1
- package/dist/client/chunks/{chart-bubble-B2he1--4.js → chart-bubble-DvP_6_n9.js} +2 -2
- package/dist/client/chunks/{chart-bubble-B2he1--4.js.map → chart-bubble-DvP_6_n9.js.map} +1 -1
- package/dist/client/chunks/{chart-candlestick-DZp19Tzh.js → chart-candlestick-Dx8ZCMzl.js} +2 -2
- package/dist/client/chunks/{chart-candlestick-DZp19Tzh.js.map → chart-candlestick-Dx8ZCMzl.js.map} +1 -1
- package/dist/client/chunks/{chart-data-table-D4g5_jfF.js → chart-data-table-BP6DMdom.js} +32 -16
- package/dist/client/chunks/chart-data-table-BP6DMdom.js.map +1 -0
- package/dist/client/chunks/{chart-funnel-CToKSBaL.js → chart-funnel-xeVGBy-p.js} +2 -2
- package/dist/client/chunks/{chart-funnel-CToKSBaL.js.map → chart-funnel-xeVGBy-p.js.map} +1 -1
- package/dist/client/chunks/{chart-gauge-DTVezSk7.js → chart-gauge-DXQ4r3cb.js} +3 -3
- package/dist/client/chunks/{chart-gauge-DTVezSk7.js.map → chart-gauge-DXQ4r3cb.js.map} +1 -1
- package/dist/client/chunks/{chart-heat-map-DTuUl0BR.js → chart-heat-map-Pnk6rhqQ.js} +3 -3
- package/dist/client/chunks/{chart-heat-map-DTuUl0BR.js.map → chart-heat-map-Pnk6rhqQ.js.map} +1 -1
- package/dist/client/chunks/{chart-kpi-delta-BvWOt8-D.js → chart-kpi-delta-nXQnRRBr.js} +3 -3
- package/dist/client/chunks/{chart-kpi-delta-BvWOt8-D.js.map → chart-kpi-delta-nXQnRRBr.js.map} +1 -1
- package/dist/client/chunks/{chart-kpi-number-xgZmMiQY.js → chart-kpi-number-m8UGJfBr.js} +5 -5
- package/dist/client/chunks/{chart-kpi-number-xgZmMiQY.js.map → chart-kpi-number-m8UGJfBr.js.map} +1 -1
- package/dist/client/chunks/{chart-kpi-text-ZO3eFi7t.js → chart-kpi-text-CurpqmaD.js} +7 -4
- package/dist/client/chunks/{chart-kpi-text-ZO3eFi7t.js.map → chart-kpi-text-CurpqmaD.js.map} +1 -1
- package/dist/client/chunks/{chart-line-DKgrQA6c.js → chart-line-sJK-cJc0.js} +3 -3
- package/dist/client/chunks/{chart-line-DKgrQA6c.js.map → chart-line-sJK-cJc0.js.map} +1 -1
- package/dist/client/chunks/{chart-markdown-CV75S_zL.js → chart-markdown-BVrqqygz.js} +1263 -1192
- package/dist/client/chunks/chart-markdown-BVrqqygz.js.map +1 -0
- package/dist/client/chunks/{chart-measure-profile-Ket8fJyf.js → chart-measure-profile-k9_QDQbB.js} +3 -3
- package/dist/client/chunks/{chart-measure-profile-Ket8fJyf.js.map → chart-measure-profile-k9_QDQbB.js.map} +1 -1
- package/dist/client/chunks/{chart-pie-ByieAX5H.js → chart-pie-BDaaYt7a.js} +3 -3
- package/dist/client/chunks/{chart-pie-ByieAX5H.js.map → chart-pie-BDaaYt7a.js.map} +1 -1
- package/dist/client/chunks/{chart-radar-CiSwHWp4.js → chart-radar-Bz07PIVe.js} +3 -3
- package/dist/client/chunks/{chart-radar-CiSwHWp4.js.map → chart-radar-Bz07PIVe.js.map} +1 -1
- package/dist/client/chunks/{chart-radial-bar-BF6Mhl6f.js → chart-radial-bar-DpyxKQMj.js} +3 -3
- package/dist/client/chunks/{chart-radial-bar-BF6Mhl6f.js.map → chart-radial-bar-DpyxKQMj.js.map} +1 -1
- package/dist/client/chunks/{chart-sankey-DjrvKw6K.js → chart-sankey-BAeNbI-p.js} +2 -2
- package/dist/client/chunks/{chart-sankey-DjrvKw6K.js.map → chart-sankey-BAeNbI-p.js.map} +1 -1
- package/dist/client/chunks/{chart-scatter-Dd9WFqnS.js → chart-scatter-CRhGLCcy.js} +3 -3
- package/dist/client/chunks/{chart-scatter-Dd9WFqnS.js.map → chart-scatter-CRhGLCcy.js.map} +1 -1
- package/dist/client/chunks/{chart-sunburst-leGpuDj7.js → chart-sunburst-D3wV5OrK.js} +3 -3
- package/dist/client/chunks/{chart-sunburst-leGpuDj7.js.map → chart-sunburst-D3wV5OrK.js.map} +1 -1
- package/dist/client/chunks/{chart-tree-map-Ceq5sLZA.js → chart-tree-map-iI3ewOKY.js} +3 -3
- package/dist/client/chunks/{chart-tree-map-Ceq5sLZA.js.map → chart-tree-map-iI3ewOKY.js.map} +1 -1
- package/dist/client/chunks/{chart-waterfall-DyvQReN5.js → chart-waterfall-BrrYTZfs.js} +3 -3
- package/dist/client/chunks/{chart-waterfall-DyvQReN5.js.map → chart-waterfall-BrrYTZfs.js.map} +1 -1
- package/dist/client/chunks/{charts-core-DaXSt1Dd.js → charts-core-Cs-UIsQa.js} +2 -2
- package/dist/client/chunks/{charts-core-DaXSt1Dd.js.map → charts-core-Cs-UIsQa.js.map} +1 -1
- package/dist/client/chunks/charts-loader-DAJbAD7a.js +84 -0
- package/dist/client/chunks/{charts-loader-B0DOQMFH.js.map → charts-loader-DAJbAD7a.js.map} +1 -1
- package/dist/client/chunks/core-D7vPfUIe.js.map +1 -1
- package/dist/client/chunks/{dist-zPWyTBdU.js → dist-BwQr11Fz.js} +251 -252
- package/dist/client/chunks/{dist-zPWyTBdU.js.map → dist-BwQr11Fz.js.map} +1 -1
- package/dist/client/chunks/{exceljs.min-CIqBqwTW.js → exceljs.min-Dey-qIFL.js} +16 -16
- package/dist/client/chunks/{exceljs.min-CIqBqwTW.js.map → exceljs.min-Dey-qIFL.js.map} +1 -1
- package/dist/client/chunks/javascript-DFnKaHmQ.js.map +1 -1
- package/dist/client/chunks/retention-ChW9jYdy.js.map +1 -1
- package/dist/client/chunks/{schema-visualization-DJPTktM6.js → schema-visualization-BGT_cNon.js} +12 -12
- package/dist/client/chunks/{schema-visualization-DJPTktM6.js.map → schema-visualization-BGT_cNon.js.map} +1 -1
- package/dist/client/chunks/sql-CmVzGP4w.js.map +1 -1
- package/dist/client/chunks/syntaxHighlighting-Bq2Bj9Xt.js +30 -0
- package/dist/client/chunks/syntaxHighlighting-Bq2Bj9Xt.js.map +1 -0
- package/dist/client/chunks/{useDirtyStateTracking-BT6zqCFl.js → useDebounce-7suCFq9v.js} +47 -109
- package/dist/client/chunks/useDebounce-7suCFq9v.js.map +1 -0
- package/dist/client/chunks/useDirtyStateTracking-D2OiqKoQ.js +66 -0
- package/dist/client/chunks/useDirtyStateTracking-D2OiqKoQ.js.map +1 -0
- package/dist/client/chunks/{useExplainAI-Dq_meKNN.js → useExplainAI-CEf04DPE.js} +14 -14
- package/dist/client/chunks/{useExplainAI-Dq_meKNN.js.map → useExplainAI-CEf04DPE.js.map} +1 -1
- package/dist/client/chunks/useNotebookLayout-Ck3Z3uzg.js.map +1 -1
- package/dist/client/chunks/utils-DjLiJKS_.js +104 -0
- package/dist/client/chunks/utils-DjLiJKS_.js.map +1 -0
- package/dist/client/chunks/{vendor-D4jADu8t.js → vendor-DFAQ4Ucl.js} +5 -3
- package/dist/client/chunks/{vendor-D4jADu8t.js.map → vendor-DFAQ4Ucl.js.map} +1 -1
- package/dist/client/components.js +4 -3
- package/dist/client/hooks.js +5 -4
- package/dist/client/icons.js +1 -1
- package/dist/client/index.js +33 -29
- package/dist/client/index.js.map +1 -1
- package/dist/client/providers.js +1 -1
- package/dist/client/schema.js +1 -1
- package/dist/client/styles.css +1 -1
- package/dist/client/utils.js +32 -6
- package/dist/client/utils.js.map +1 -0
- package/dist/client-bundle-stats.html +1 -1
- package/dist/mcp-app/mcp-app.html +145 -50
- package/dist/server/executors/sqlite-executor.d.ts +8 -2
- package/dist/server/index.cjs +33 -33
- package/dist/server/index.js +1268 -1262
- package/dist/server/{openai-CmMzrs1Y.js → openai-BCSKRcbD.js} +10 -10
- package/dist/{adapters/openai-DhzGY9R4.js → server/openai-BjR3ohaS.js} +1 -1
- package/dist/{adapters/openai-B4kAJTSD.cjs → server/openai-ClVVLjNl.cjs} +2 -2
- package/dist/server/{openai-Cdf2wWZA.cjs → openai-CsVXOcJZ.cjs} +1 -1
- package/package.json +11 -7
- package/dist/adapters/ActivityGridChart.config-BtECymia.cjs +0 -1
- package/dist/adapters/ActivityGridChart.config-CTd5HYjI.js +0 -2
- package/dist/adapters/AreaChart.config-1B8iQnfn.js +0 -2
- package/dist/adapters/AreaChart.config-hnncyQL4.cjs +0 -1
- package/dist/adapters/BarChart.config-C-QCf1rL.cjs +0 -1
- package/dist/adapters/BarChart.config-CFelK1qP.js +0 -2
- package/dist/adapters/BoxPlotChart.config-CD9WEPyF.js +0 -2
- package/dist/adapters/BoxPlotChart.config-DEbLA0BX.cjs +0 -1
- package/dist/adapters/BubbleChart.config-B_M4hzzV.js +0 -2
- package/dist/adapters/BubbleChart.config-dRZZlAke.cjs +0 -1
- package/dist/adapters/CandlestickChart.config-Dsil2Fop.cjs +0 -1
- package/dist/adapters/CandlestickChart.config-fuhyFvob.js +0 -2
- package/dist/adapters/DataTable.config-q2gqBi6t.cjs +0 -1
- package/dist/adapters/DataTable.config-wIQnHX5R.js +0 -2
- package/dist/adapters/FunnelChart.config-Dz710ssx.js +0 -2
- package/dist/adapters/FunnelChart.config-YNP9CeS-.cjs +0 -1
- package/dist/adapters/GaugeChart.config-BG9FcMCn.cjs +0 -1
- package/dist/adapters/GaugeChart.config-CgwniXkd.js +0 -2
- package/dist/adapters/HeatMapChart.config-1zSMXXoN.cjs +0 -1
- package/dist/adapters/HeatMapChart.config-YVEWx6s5.js +0 -2
- package/dist/adapters/KpiDelta.config-BWvYXuFp.cjs +0 -1
- package/dist/adapters/KpiDelta.config-C_dYM64q.js +0 -2
- package/dist/adapters/KpiNumber.config-CXg6toZG.js +0 -2
- package/dist/adapters/KpiNumber.config-CZmV-yU1.cjs +0 -1
- package/dist/adapters/KpiText.config-BY-SJvAF.js +0 -2
- package/dist/adapters/KpiText.config-GSIxy0CE.cjs +0 -1
- package/dist/adapters/LineChart.config-CJtF8SOu.js +0 -2
- package/dist/adapters/LineChart.config-d0y60gw9.cjs +0 -1
- package/dist/adapters/MarkdownChart.config-B6w0spya.cjs +0 -1
- package/dist/adapters/MarkdownChart.config-BuIQcWOn.js +0 -2
- package/dist/adapters/MeasureProfileChart.config-Bo2n5Ae5.cjs +0 -1
- package/dist/adapters/MeasureProfileChart.config-C5d34lsc.js +0 -2
- package/dist/adapters/PieChart.config-CDxfXCIt.cjs +0 -1
- package/dist/adapters/PieChart.config-CuZxQc5m.js +0 -2
- package/dist/adapters/RadarChart.config-DpdVWyh5.cjs +0 -1
- package/dist/adapters/RadarChart.config-KrxwaaGu.js +0 -2
- package/dist/adapters/RadialBarChart.config-DpRZd0FW.js +0 -2
- package/dist/adapters/RadialBarChart.config-faIY4jpE.cjs +0 -1
- package/dist/adapters/RetentionCombinedChart.config-CUnScqnS.cjs +0 -1
- package/dist/adapters/RetentionCombinedChart.config-Dd8FuawP.js +0 -2
- package/dist/adapters/RetentionHeatmap.config-CPd6GeoQ.js +0 -2
- package/dist/adapters/RetentionHeatmap.config-CPlHbLom.cjs +0 -1
- package/dist/adapters/SankeyChart.config-DbIUqi-H.cjs +0 -1
- package/dist/adapters/SankeyChart.config-kzAnW0C7.js +0 -2
- package/dist/adapters/ScatterChart.config-4Okvn27v.js +0 -2
- package/dist/adapters/ScatterChart.config-4f9nNw3e.cjs +0 -1
- package/dist/adapters/SunburstChart.config-BsUQkIM_.js +0 -2
- package/dist/adapters/SunburstChart.config-lvnYkWs7.cjs +0 -1
- package/dist/adapters/TreeMapChart.config-S0qsgAFW.js +0 -2
- package/dist/adapters/TreeMapChart.config-jbwKsTYt.cjs +0 -1
- package/dist/adapters/WaterfallChart.config-CDQ74-pS.cjs +0 -1
- package/dist/adapters/WaterfallChart.config-XdtH-O5g.js +0 -2
- package/dist/adapters/mcp-transport-Bw_zqky2.js +0 -591
- package/dist/adapters/mcp-transport-CNIPoe1i.cjs +0 -40
- package/dist/adapters/utils-_whV4fXL.cjs +0 -128
- package/dist/client/chunks/DashboardEditModal-Cs1ig1_V.js.map +0 -1
- package/dist/client/chunks/chart-data-table-D4g5_jfF.js.map +0 -1
- package/dist/client/chunks/chart-markdown-CV75S_zL.js.map +0 -1
- package/dist/client/chunks/charts-loader-B0DOQMFH.js +0 -84
- package/dist/client/chunks/useDirtyStateTracking-BT6zqCFl.js.map +0 -1
- package/dist/client/chunks/utils-Cq-j5E5I.js +0 -155
- package/dist/client/chunks/utils-Cq-j5E5I.js.map +0 -1
package/dist/client/chunks/{chart-box-plot-kkBixZ27.js.map → chart-box-plot-CUpFyQQk.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-box-plot-kkBixZ27.js","names":[],"sources":["../../../src/client/components/charts/BoxPlotChart.tsx"],"sourcesContent":["import React, { useLayoutEffect, useMemo, useRef, useState } from 'react'\nimport { useTranslation } from '../../hooks/useTranslation.js'\nimport { CHART_COLORS } from '../../utils/chartConstants.js'\nimport { formatAxisValue } from '../../utils/chartUtils.js'\nimport type { ChartProps } from '../../types.js'\n\nconst MAX_BOXES = 50\n\ninterface BoxStats {\n label: string\n min: number\n q1: number\n median: number\n q3: number\n max: number\n color: string\n}\n\nfunction parseNumeric(v: unknown): number | null {\n if (v === undefined || v === null) return null\n const n = typeof v === 'number' ? v : parseFloat(String(v))\n return isNaN(n) ? null : n\n}\n\nfunction buildFrom5Measures(\n row: Record<string, unknown>,\n minField: string,\n q1Field: string,\n medianField: string,\n q3Field: string,\n maxField: string,\n label: string,\n color: string\n): BoxStats | null {\n const min = parseNumeric(row[minField])\n const q1 = parseNumeric(row[q1Field])\n const median = parseNumeric(row[medianField])\n const q3 = parseNumeric(row[q3Field])\n const max = parseNumeric(row[maxField])\n if (min === null || q1 === null || median === null || q3 === null || max === null) return null\n return { label, min, q1, median, q3, max, color }\n}\n\n/** Build approximate box stats assuming normality: Q1/Q3 at ±1σ, whiskers at ±2σ */\nfunction buildFrom3Measures(\n row: Record<string, unknown>,\n avgField: string,\n stddevField: string,\n medianField: string,\n label: string,\n color: string\n): BoxStats | null {\n const avg = parseNumeric(row[avgField])\n const sd = parseNumeric(row[stddevField])\n const median = parseNumeric(row[medianField])\n if (avg === null || sd === null || median === null) return null\n const absSd = Math.abs(sd)\n return {\n label,\n min: avg - 2 * absSd,\n q1: avg - absSd,\n median,\n q3: avg + absSd,\n max: avg + 2 * absSd,\n color,\n }\n}\n\nfunction BoxElement({\n x,\n boxWidth,\n minY,\n q1Y,\n medianY,\n q3Y,\n maxY,\n color,\n label,\n}: {\n x: number\n boxWidth: number\n minY: number\n q1Y: number\n medianY: number\n q3Y: number\n maxY: number\n color: string\n label: string\n}) {\n const halfWidth = boxWidth / 2\n const whiskerX = x\n const capWidth = boxWidth * 0.4\n\n return (\n <g data-testid={`box-${label}`}>\n {/* Whisker line (min to max) */}\n <line x1={whiskerX} y1={minY} x2={whiskerX} y2={maxY} stroke={color} strokeWidth={1.5} />\n {/* Min cap */}\n <line\n x1={whiskerX - capWidth / 2}\n y1={minY}\n x2={whiskerX + capWidth / 2}\n y2={minY}\n stroke={color}\n strokeWidth={1.5}\n />\n {/* Max cap */}\n <line\n x1={whiskerX - capWidth / 2}\n y1={maxY}\n x2={whiskerX + capWidth / 2}\n y2={maxY}\n stroke={color}\n strokeWidth={1.5}\n />\n {/* IQR Box (Q1 to Q3) */}\n <rect\n x={whiskerX - halfWidth}\n y={Math.min(q1Y, q3Y)}\n width={boxWidth}\n height={Math.abs(q3Y - q1Y) || 2}\n fill={color}\n fillOpacity={0.3}\n stroke={color}\n strokeWidth={1.5}\n />\n {/* Median line */}\n <line\n x1={whiskerX - halfWidth}\n y1={medianY}\n x2={whiskerX + halfWidth}\n y2={medianY}\n stroke={color}\n strokeWidth={2.5}\n data-testid={`median-${label}`}\n />\n </g>\n )\n}\n\nfunction YAxis({\n scale,\n domainMin,\n domainMax,\n width,\n tickCount = 5,\n format,\n}: {\n scale: (v: number) => number\n domainMin: number\n domainMax: number\n width: number\n tickCount?: number\n format?: (v: number) => string\n}) {\n const ticks = useMemo(() => {\n const range = domainMax - domainMin\n if (range === 0) return [domainMin]\n const step = range / (tickCount - 1)\n return Array.from({ length: tickCount }, (_, i) => domainMin + i * step)\n }, [domainMin, domainMax, tickCount])\n\n return (\n <g data-testid=\"y-axis\">\n {ticks.map((tick, i) => (\n <g key={i} transform={`translate(0, ${scale(tick)})`}>\n <line x1={0} x2={-6} stroke=\"currentColor\" strokeWidth={1} />\n <text\n x={-10}\n textAnchor=\"end\"\n dominantBaseline=\"middle\"\n fontSize={11}\n fill=\"currentColor\"\n className=\"text-dc-text-secondary\"\n >\n {format ? format(tick) : tick.toLocaleString()}\n </text>\n <line x1={0} x2={width} stroke=\"currentColor\" strokeOpacity={0.1} strokeWidth={1} />\n </g>\n ))}\n <line y1={scale(ticks[0])} y2={scale(ticks[ticks.length - 1])} stroke=\"currentColor\" strokeWidth={1} />\n </g>\n )\n}\n\nconst BoxPlotChart = React.memo(function BoxPlotChart({\n data,\n chartConfig,\n displayConfig = {},\n height = '100%',\n colorPalette,\n onDataPointClick,\n drillEnabled,\n}: ChartProps) {\n const { t } = useTranslation()\n const containerRef = useRef<HTMLDivElement>(null)\n const [dimensions, setDimensions] = useState({ width: 0, height: 0 })\n\n useLayoutEffect(() => {\n const el = containerRef.current\n if (!el) return\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width, height: h } = entry.contentRect\n if (width > 0 && h > 0) setDimensions({ width, height: h })\n }\n })\n observer.observe(el)\n const rect = el.getBoundingClientRect()\n if (rect.width > 0 && rect.height > 0) setDimensions({ width: rect.width, height: rect.height })\n return () => observer.disconnect()\n }, [])\n\n const yAxisFormat = displayConfig?.leftYAxisFormat\n\n const { xField, mode, fields, configError } = useMemo(() => {\n const xField = Array.isArray(chartConfig?.xAxis)\n ? chartConfig.xAxis[0]\n : chartConfig?.xAxis ?? chartConfig?.x\n\n const yAxisFields: string[] = Array.isArray(chartConfig?.yAxis)\n ? chartConfig.yAxis\n : []\n\n if (!xField || yAxisFields.length === 0) {\n return {\n xField,\n mode: 'none' as const,\n fields: {},\n configError: 'BoxPlot requires an X-Axis dimension and at least one measure in Y-Axis',\n }\n }\n\n // 5-measure mode: yAxis = [min, q1, median, q3, max]\n if (yAxisFields.length >= 5) {\n return {\n xField,\n mode: '5measure' as const,\n fields: {\n minField: yAxisFields[0],\n q1Field: yAxisFields[1],\n medianField: yAxisFields[2],\n q3Field: yAxisFields[3],\n maxField: yAxisFields[4],\n },\n configError: null,\n }\n }\n\n // 3-measure mode: yAxis = [avg, stddev, median]\n if (yAxisFields.length >= 3) {\n return {\n xField,\n mode: '3measure' as const,\n fields: {\n avgField: yAxisFields[0],\n stddevField: yAxisFields[1],\n medianField: yAxisFields[2],\n },\n configError: null,\n }\n }\n\n if (yAxisFields.length === 2) {\n return {\n xField,\n mode: 'none' as const,\n fields: {},\n configError: 'BoxPlot requires 1 measure (auto), 3 (avg/stddev/median), or 5 (min/q1/median/q3/max)',\n }\n }\n\n // Auto mode: use yAxis[0] as the value field (treated as median/value)\n return {\n xField,\n mode: 'auto' as const,\n fields: { valueField: yAxisFields[0] },\n configError: null,\n }\n }, [chartConfig])\n\n const boxes: BoxStats[] = useMemo(() => {\n if (configError || !data || data.length === 0 || mode === 'none') return []\n const rows = (data as Record<string, unknown>[]).slice(0, MAX_BOXES)\n const palette = colorPalette?.colors ?? CHART_COLORS\n\n const results: BoxStats[] = []\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i]\n const label = xField ? String(row[xField] ?? `Row ${i + 1}`) : `Row ${i + 1}`\n const color = palette[i % palette.length]\n\n let box: BoxStats | null = null\n if (mode === '5measure') {\n box = buildFrom5Measures(\n row,\n fields.minField!,\n fields.q1Field!,\n fields.medianField!,\n fields.q3Field!,\n fields.maxField!,\n label,\n color\n )\n } else if (mode === '3measure') {\n box = buildFrom3Measures(row, fields.avgField!, fields.stddevField!, fields.medianField!, label, color)\n } else {\n // Auto: use value as median, build minimal box (value ± 0)\n const v = parseNumeric(row[fields.valueField!])\n if (v !== null) {\n box = { label, min: v, q1: v, median: v, q3: v, max: v, color }\n }\n }\n if (box) results.push(box)\n }\n return results\n }, [data, xField, mode, fields, colorPalette, configError])\n\n if (!data || data.length === 0) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-text-muted\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.noData')}</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">{t('chart.runtime.noDataHint.boxPlot')}</div>\n </div>\n </div>\n )\n }\n\n if (configError) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-warning\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.configError')}</div>\n <div className=\"dc:text-xs\">{configError}</div>\n </div>\n </div>\n )\n }\n\n if (boxes.length === 0) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-text-muted\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.noValidData')}</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">\n {t('chart.runtime.noValidDataHint.boxPlot')}\n </div>\n </div>\n </div>\n )\n }\n\n try {\n const margin = { top: 20, right: 20, bottom: 60, left: 60 }\n const containerWidth = dimensions.width || 600\n const containerHeight = typeof height === 'number' ? height : (dimensions.height || 400)\n const innerWidth = Math.max(containerWidth - margin.left - margin.right, 50)\n const innerHeight = Math.max(containerHeight - margin.top - margin.bottom, 50)\n\n const allValues = boxes.flatMap((b) => [b.min, b.max])\n const rawMin = Math.min(...allValues)\n const rawMax = Math.max(...allValues)\n const padding = (rawMax - rawMin) * 0.1 || 1\n const domainMin = rawMin - padding\n const domainMax = rawMax + padding\n\n const domainRange = domainMax - domainMin\n const yScale = (v: number) =>\n domainRange === 0 ? innerHeight / 2 : innerHeight - ((v - domainMin) / domainRange) * innerHeight\n\n const boxSpacing = innerWidth / boxes.length\n const boxWidth = Math.min(boxSpacing * 0.6, 40)\n\n const isTruncated = (data as unknown[]).length > MAX_BOXES\n\n return (\n <div ref={containerRef} className=\"dc:relative dc:w-full\" style={{ height }}>\n <svg\n width=\"100%\"\n height={isTruncated ? `calc(100% - 20px)` : '100%'}\n viewBox={`0 0 ${containerWidth} ${typeof containerHeight === 'number' ? containerHeight : 400}`}\n preserveAspectRatio=\"none\"\n data-testid=\"boxplot-svg\"\n >\n <g transform={`translate(${margin.left}, ${margin.top})`}>\n <YAxis\n scale={yScale}\n domainMin={domainMin}\n domainMax={domainMax}\n width={innerWidth}\n tickCount={5}\n format={yAxisFormat ? (v) => formatAxisValue(v, yAxisFormat) : undefined}\n />\n\n {boxes.map((box, i) => {\n const cx = boxSpacing * i + boxSpacing / 2\n return (\n <g\n key={`${box.label}-${i}`}\n onClick={(event: React.MouseEvent) => {\n if (onDataPointClick && drillEnabled) {\n onDataPointClick({\n dataPoint: { ...box },\n clickedField: xField ?? '',\n xValue: box.label,\n position: { x: event.clientX, y: event.clientY },\n nativeEvent: event,\n })\n }\n }}\n cursor={drillEnabled ? 'pointer' : undefined}\n >\n <title>{`${box.label}: min=${box.min}, Q1=${box.q1}, median=${box.median}, Q3=${box.q3}, max=${box.max}`}</title>\n <BoxElement\n x={cx}\n boxWidth={boxWidth}\n minY={yScale(box.min)}\n q1Y={yScale(box.q1)}\n medianY={yScale(box.median)}\n q3Y={yScale(box.q3)}\n maxY={yScale(box.max)}\n color={box.color}\n label={box.label}\n />\n <text\n x={cx}\n y={innerHeight + 20}\n textAnchor=\"middle\"\n fontSize={11}\n fill=\"currentColor\"\n className=\"text-dc-text-secondary\"\n data-testid={`x-label-${box.label}`}\n >\n {box.label}\n </text>\n </g>\n )\n })}\n </g>\n </svg>\n {isTruncated && (\n <div className=\"dc:text-xs text-dc-warning dc:text-center dc:mt-1\">\n {t('chart.runtime.boxPlot.truncated', {\n max: MAX_BOXES,\n total: (data as unknown[]).length\n })}\n </div>\n )}\n </div>\n )\n } catch (error) {\n return (\n <div className=\"dc:flex dc:flex-col dc:items-center dc:justify-center dc:w-full text-dc-error dc:p-4\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.chartError', { chartType: 'Box Plot Chart' })}</div>\n <div className=\"dc:text-xs dc:mb-2\">{error instanceof Error ? error.message : t('chart.runtime.unknownError')}</div>\n <div className=\"dc:text-xs text-dc-text-muted\">{t('chart.runtime.checkConfig')}</div>\n </div>\n </div>\n )\n }\n})\n\nexport default BoxPlotChart\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chart-box-plot-CUpFyQQk.js","names":[],"sources":["../../../src/client/components/charts/BoxPlotChart.tsx"],"sourcesContent":["import React, { useLayoutEffect, useMemo, useRef, useState } from 'react'\nimport { useTranslation } from '../../hooks/useTranslation.js'\nimport { CHART_COLORS } from '../../utils/chartConstants.js'\nimport { formatAxisValue } from '../../utils/chartUtils.js'\nimport type { ChartProps } from '../../types.js'\n\nconst MAX_BOXES = 50\n\ninterface BoxStats {\n label: string\n min: number\n q1: number\n median: number\n q3: number\n max: number\n color: string\n}\n\nfunction parseNumeric(v: unknown): number | null {\n if (v === undefined || v === null) return null\n const n = typeof v === 'number' ? v : parseFloat(String(v))\n return isNaN(n) ? null : n\n}\n\nfunction buildFrom5Measures(\n row: Record<string, unknown>,\n minField: string,\n q1Field: string,\n medianField: string,\n q3Field: string,\n maxField: string,\n label: string,\n color: string\n): BoxStats | null {\n const min = parseNumeric(row[minField])\n const q1 = parseNumeric(row[q1Field])\n const median = parseNumeric(row[medianField])\n const q3 = parseNumeric(row[q3Field])\n const max = parseNumeric(row[maxField])\n if (min === null || q1 === null || median === null || q3 === null || max === null) return null\n return { label, min, q1, median, q3, max, color }\n}\n\n/** Build approximate box stats assuming normality: Q1/Q3 at ±1σ, whiskers at ±2σ */\nfunction buildFrom3Measures(\n row: Record<string, unknown>,\n avgField: string,\n stddevField: string,\n medianField: string,\n label: string,\n color: string\n): BoxStats | null {\n const avg = parseNumeric(row[avgField])\n const sd = parseNumeric(row[stddevField])\n const median = parseNumeric(row[medianField])\n if (avg === null || sd === null || median === null) return null\n const absSd = Math.abs(sd)\n return {\n label,\n min: avg - 2 * absSd,\n q1: avg - absSd,\n median,\n q3: avg + absSd,\n max: avg + 2 * absSd,\n color,\n }\n}\n\nfunction BoxElement({\n x,\n boxWidth,\n minY,\n q1Y,\n medianY,\n q3Y,\n maxY,\n color,\n label,\n}: {\n x: number\n boxWidth: number\n minY: number\n q1Y: number\n medianY: number\n q3Y: number\n maxY: number\n color: string\n label: string\n}) {\n const halfWidth = boxWidth / 2\n const whiskerX = x\n const capWidth = boxWidth * 0.4\n\n return (\n <g data-testid={`box-${label}`}>\n {/* Whisker line (min to max) */}\n <line x1={whiskerX} y1={minY} x2={whiskerX} y2={maxY} stroke={color} strokeWidth={1.5} />\n {/* Min cap */}\n <line\n x1={whiskerX - capWidth / 2}\n y1={minY}\n x2={whiskerX + capWidth / 2}\n y2={minY}\n stroke={color}\n strokeWidth={1.5}\n />\n {/* Max cap */}\n <line\n x1={whiskerX - capWidth / 2}\n y1={maxY}\n x2={whiskerX + capWidth / 2}\n y2={maxY}\n stroke={color}\n strokeWidth={1.5}\n />\n {/* IQR Box (Q1 to Q3) */}\n <rect\n x={whiskerX - halfWidth}\n y={Math.min(q1Y, q3Y)}\n width={boxWidth}\n height={Math.abs(q3Y - q1Y) || 2}\n fill={color}\n fillOpacity={0.3}\n stroke={color}\n strokeWidth={1.5}\n />\n {/* Median line */}\n <line\n x1={whiskerX - halfWidth}\n y1={medianY}\n x2={whiskerX + halfWidth}\n y2={medianY}\n stroke={color}\n strokeWidth={2.5}\n data-testid={`median-${label}`}\n />\n </g>\n )\n}\n\nfunction YAxis({\n scale,\n domainMin,\n domainMax,\n width,\n tickCount = 5,\n format,\n}: {\n scale: (v: number) => number\n domainMin: number\n domainMax: number\n width: number\n tickCount?: number\n format?: (v: number) => string\n}) {\n const ticks = useMemo(() => {\n const range = domainMax - domainMin\n if (range === 0) return [domainMin]\n const step = range / (tickCount - 1)\n return Array.from({ length: tickCount }, (_, i) => domainMin + i * step)\n }, [domainMin, domainMax, tickCount])\n\n return (\n <g data-testid=\"y-axis\">\n {ticks.map((tick, i) => (\n <g key={i} transform={`translate(0, ${scale(tick)})`}>\n <line x1={0} x2={-6} stroke=\"currentColor\" strokeWidth={1} />\n <text\n x={-10}\n textAnchor=\"end\"\n dominantBaseline=\"middle\"\n fontSize={11}\n fill=\"currentColor\"\n className=\"text-dc-text-secondary\"\n >\n {format ? format(tick) : tick.toLocaleString()}\n </text>\n <line x1={0} x2={width} stroke=\"currentColor\" strokeOpacity={0.1} strokeWidth={1} />\n </g>\n ))}\n <line y1={scale(ticks[0])} y2={scale(ticks[ticks.length - 1])} stroke=\"currentColor\" strokeWidth={1} />\n </g>\n )\n}\n\nconst BoxPlotChart = React.memo(function BoxPlotChart({\n data,\n chartConfig,\n displayConfig = {},\n height = '100%',\n colorPalette,\n onDataPointClick,\n drillEnabled,\n}: ChartProps) {\n const { t } = useTranslation()\n const containerRef = useRef<HTMLDivElement>(null)\n const [dimensions, setDimensions] = useState({ width: 0, height: 0 })\n\n useLayoutEffect(() => {\n const el = containerRef.current\n if (!el) return\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width, height: h } = entry.contentRect\n if (width > 0 && h > 0) setDimensions({ width, height: h })\n }\n })\n observer.observe(el)\n const rect = el.getBoundingClientRect()\n if (rect.width > 0 && rect.height > 0) setDimensions({ width: rect.width, height: rect.height })\n return () => observer.disconnect()\n }, [])\n\n const yAxisFormat = displayConfig?.leftYAxisFormat\n\n const { xField, mode, fields, configError } = useMemo(() => {\n const xField = Array.isArray(chartConfig?.xAxis)\n ? chartConfig.xAxis[0]\n : chartConfig?.xAxis ?? chartConfig?.x\n\n const yAxisFields: string[] = Array.isArray(chartConfig?.yAxis)\n ? chartConfig.yAxis\n : []\n\n if (!xField || yAxisFields.length === 0) {\n return {\n xField,\n mode: 'none' as const,\n fields: {},\n configError: 'BoxPlot requires an X-Axis dimension and at least one measure in Y-Axis',\n }\n }\n\n // 5-measure mode: yAxis = [min, q1, median, q3, max]\n if (yAxisFields.length >= 5) {\n return {\n xField,\n mode: '5measure' as const,\n fields: {\n minField: yAxisFields[0],\n q1Field: yAxisFields[1],\n medianField: yAxisFields[2],\n q3Field: yAxisFields[3],\n maxField: yAxisFields[4],\n },\n configError: null,\n }\n }\n\n // 3-measure mode: yAxis = [avg, stddev, median]\n if (yAxisFields.length >= 3) {\n return {\n xField,\n mode: '3measure' as const,\n fields: {\n avgField: yAxisFields[0],\n stddevField: yAxisFields[1],\n medianField: yAxisFields[2],\n },\n configError: null,\n }\n }\n\n if (yAxisFields.length === 2) {\n return {\n xField,\n mode: 'none' as const,\n fields: {},\n configError: 'BoxPlot requires 1 measure (auto), 3 (avg/stddev/median), or 5 (min/q1/median/q3/max)',\n }\n }\n\n // Auto mode: use yAxis[0] as the value field (treated as median/value)\n return {\n xField,\n mode: 'auto' as const,\n fields: { valueField: yAxisFields[0] },\n configError: null,\n }\n }, [chartConfig])\n\n const boxes: BoxStats[] = useMemo(() => {\n if (configError || !data || data.length === 0 || mode === 'none') return []\n const rows = (data as Record<string, unknown>[]).slice(0, MAX_BOXES)\n const palette = colorPalette?.colors ?? CHART_COLORS\n\n const results: BoxStats[] = []\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i]\n const label = xField ? String(row[xField] ?? `Row ${i + 1}`) : `Row ${i + 1}`\n const color = palette[i % palette.length]\n\n let box: BoxStats | null = null\n if (mode === '5measure') {\n box = buildFrom5Measures(\n row,\n fields.minField!,\n fields.q1Field!,\n fields.medianField!,\n fields.q3Field!,\n fields.maxField!,\n label,\n color\n )\n } else if (mode === '3measure') {\n box = buildFrom3Measures(row, fields.avgField!, fields.stddevField!, fields.medianField!, label, color)\n } else {\n // Auto: use value as median, build minimal box (value ± 0)\n const v = parseNumeric(row[fields.valueField!])\n if (v !== null) {\n box = { label, min: v, q1: v, median: v, q3: v, max: v, color }\n }\n }\n if (box) results.push(box)\n }\n return results\n }, [data, xField, mode, fields, colorPalette, configError])\n\n if (!data || data.length === 0) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-text-muted\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.noData')}</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">{t('chart.runtime.noDataHint.boxPlot')}</div>\n </div>\n </div>\n )\n }\n\n if (configError) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-warning\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.configError')}</div>\n <div className=\"dc:text-xs\">{configError}</div>\n </div>\n </div>\n )\n }\n\n if (boxes.length === 0) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-text-muted\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.noValidData')}</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">\n {t('chart.runtime.noValidDataHint.boxPlot')}\n </div>\n </div>\n </div>\n )\n }\n\n try {\n const margin = { top: 20, right: 20, bottom: 60, left: 60 }\n const containerWidth = dimensions.width || 600\n const containerHeight = typeof height === 'number' ? height : (dimensions.height || 400)\n const innerWidth = Math.max(containerWidth - margin.left - margin.right, 50)\n const innerHeight = Math.max(containerHeight - margin.top - margin.bottom, 50)\n\n const allValues = boxes.flatMap((b) => [b.min, b.max])\n const rawMin = Math.min(...allValues)\n const rawMax = Math.max(...allValues)\n const padding = (rawMax - rawMin) * 0.1 || 1\n const domainMin = rawMin - padding\n const domainMax = rawMax + padding\n\n const domainRange = domainMax - domainMin\n const yScale = (v: number) =>\n domainRange === 0 ? innerHeight / 2 : innerHeight - ((v - domainMin) / domainRange) * innerHeight\n\n const boxSpacing = innerWidth / boxes.length\n const boxWidth = Math.min(boxSpacing * 0.6, 40)\n\n const isTruncated = (data as unknown[]).length > MAX_BOXES\n\n return (\n <div ref={containerRef} className=\"dc:relative dc:w-full\" style={{ height }}>\n <svg\n width=\"100%\"\n height={isTruncated ? `calc(100% - 20px)` : '100%'}\n viewBox={`0 0 ${containerWidth} ${typeof containerHeight === 'number' ? containerHeight : 400}`}\n preserveAspectRatio=\"none\"\n data-testid=\"boxplot-svg\"\n >\n <g transform={`translate(${margin.left}, ${margin.top})`}>\n <YAxis\n scale={yScale}\n domainMin={domainMin}\n domainMax={domainMax}\n width={innerWidth}\n tickCount={5}\n format={yAxisFormat ? (v) => formatAxisValue(v, yAxisFormat) : undefined}\n />\n\n {boxes.map((box, i) => {\n const cx = boxSpacing * i + boxSpacing / 2\n return (\n <g\n key={`${box.label}-${i}`}\n onClick={(event: React.MouseEvent) => {\n if (onDataPointClick && drillEnabled) {\n onDataPointClick({\n dataPoint: { ...box },\n clickedField: xField ?? '',\n xValue: box.label,\n position: { x: event.clientX, y: event.clientY },\n nativeEvent: event,\n })\n }\n }}\n cursor={drillEnabled ? 'pointer' : undefined}\n >\n <title>{`${box.label}: min=${box.min}, Q1=${box.q1}, median=${box.median}, Q3=${box.q3}, max=${box.max}`}</title>\n <BoxElement\n x={cx}\n boxWidth={boxWidth}\n minY={yScale(box.min)}\n q1Y={yScale(box.q1)}\n medianY={yScale(box.median)}\n q3Y={yScale(box.q3)}\n maxY={yScale(box.max)}\n color={box.color}\n label={box.label}\n />\n <text\n x={cx}\n y={innerHeight + 20}\n textAnchor=\"middle\"\n fontSize={11}\n fill=\"currentColor\"\n className=\"text-dc-text-secondary\"\n data-testid={`x-label-${box.label}`}\n >\n {box.label}\n </text>\n </g>\n )\n })}\n </g>\n </svg>\n {isTruncated && (\n <div className=\"dc:text-xs text-dc-warning dc:text-center dc:mt-1\">\n {t('chart.runtime.boxPlot.truncated', {\n max: MAX_BOXES,\n total: (data as unknown[]).length\n })}\n </div>\n )}\n </div>\n )\n } catch (error) {\n return (\n <div className=\"dc:flex dc:flex-col dc:items-center dc:justify-center dc:w-full text-dc-error dc:p-4\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.chartError', { chartType: 'Box Plot Chart' })}</div>\n <div className=\"dc:text-xs dc:mb-2\">{error instanceof Error ? error.message : t('chart.runtime.unknownError')}</div>\n <div className=\"dc:text-xs text-dc-text-muted\">{t('chart.runtime.checkConfig')}</div>\n </div>\n </div>\n )\n }\n})\n\nexport default BoxPlotChart\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as e } from "./rolldown-runtime-CWhphoD1.js";
|
|
2
|
-
import { P as t, S as n, a as r, c as i, h as a, i as o, l as s, n as c, o as l, r as u, s as d, w as f, x as p, y as m } from "./chart-activity-grid-
|
|
2
|
+
import { P as t, S as n, a as r, c as i, h as a, i as o, l as s, n as c, o as l, r as u, s as d, w as f, x as p, y as m } from "./chart-activity-grid-DDqFVWoa.js";
|
|
3
3
|
import h, { useCallback as g, useEffect as _, useMemo as v, useSyncExternalStore as y } from "react";
|
|
4
4
|
import { jsx as b, jsxs as x } from "react/jsx-runtime";
|
|
5
5
|
import { axisBottom as S, axisLeft as C, extent as w, max as T, scaleLinear as E, scaleOrdinal as D, scaleQuantize as O, scaleSqrt as k, select as A } from "d3";
|
|
@@ -218,4 +218,4 @@ var U = /* @__PURE__ */ e({ default: () => W }), W = h.memo(function({ data: e,
|
|
|
218
218
|
//#endregion
|
|
219
219
|
export { M as n, U as t };
|
|
220
220
|
|
|
221
|
-
//# sourceMappingURL=chart-bubble-
|
|
221
|
+
//# sourceMappingURL=chart-bubble-DvP_6_n9.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-bubble-B2he1--4.js","names":[],"sources":["../../../src/client/hooks/useTheme.ts","../../../src/client/components/charts/BubbleChart.render.ts","../../../src/client/components/charts/BubbleChart.tsx"],"sourcesContent":["/**\n * useTheme - External Theme State Hook\n *\n * Uses React 18's useSyncExternalStore to prevent parent component re-renders.\n * The theme state is stored externally and changes are propagated through\n * a subscribe/notify pattern.\n *\n * This prevents the ThemeToggle component from causing Layout re-renders.\n */\n\nimport { useSyncExternalStore, useCallback } from 'react'\nimport { getTheme, setTheme as setThemeUtil, watchThemeChanges, type Theme } from '../theme/index.js'\n\n// External store for theme state\nconst themeStore = {\n listeners: new Set<() => void>(),\n\n subscribe(listener: () => void) {\n this.listeners.add(listener)\n return () => this.listeners.delete(listener)\n },\n\n notify() {\n this.listeners.forEach(listener => listener())\n }\n}\n\n// Watch theme changes from DOM/system and notify subscribers\nwatchThemeChanges(() => {\n themeStore.notify()\n})\n\n/**\n * Hook to access and update theme\n *\n * Returns current theme and a setter function.\n * Only components using this hook will re-render on theme changes.\n */\nexport function useTheme() {\n // Subscribe to external theme store\n const theme = useSyncExternalStore(\n themeStore.subscribe.bind(themeStore),\n getTheme, // Client-side snapshot\n getTheme // Server-side snapshot (SSR)\n )\n\n // Stable setter function\n const setTheme = useCallback((newTheme: Theme) => {\n setThemeUtil(newTheme)\n themeStore.notify()\n }, [])\n\n return { theme, setTheme }\n}\n","/**\n * D3 rendering for BubbleChart, extracted from the component's render effect.\n *\n * The effect orchestrates these pure-ish drawing helpers. Behaviour matches the\n * original inline D3 exactly; only the structure changed (one function per\n * concern) to keep each helper's complexity low.\n */\nimport {\n select,\n scaleLinear,\n scaleSqrt,\n scaleOrdinal,\n scaleQuantize,\n extent,\n max,\n axisBottom,\n axisLeft,\n type Selection,\n type ScaleLinear,\n type ScalePower,\n type ScaleOrdinal,\n type ScaleQuantize\n} from 'd3'\nimport { CHART_COLORS, CHART_COLORS_GRADIENT, CHART_MARGINS } from '../../utils/chartConstants.js'\nimport { formatAxisValue } from '../../utils/chartUtils.js'\nimport { resolveThemeColors } from './BubbleChart.helpers.js'\nimport type { BubbleData, BubbleDisplayOptions, BubbleFields } from './BubbleChart.helpers.js'\nimport type { ColorPalette, CubeQuery } from '../../types.js'\n\ntype ColorScale = ScaleOrdinal<string, string> | ScaleQuantize<string>\ntype G = Selection<SVGGElement, unknown, null, undefined>\n\nexport interface BubbleRenderContext {\n svgEl: SVGSVGElement\n bubbleData: BubbleData[]\n fields: BubbleFields\n options: BubbleDisplayOptions\n dimensions: { width: number; height: number }\n queryObject: CubeQuery | undefined\n colorPalette?: ColorPalette\n isDark: boolean\n getFieldLabel: (field: string) => string\n}\n\ninterface ColorScaleResult {\n colorScale: ColorScale\n isNumericColorField: boolean\n uniqueColors: string[]\n}\n\n/** Build the bubble fill colour scale (numeric → quantize, categorical → ordinal). */\nfunction buildColorScale(\n bubbleData: BubbleData[],\n colorFieldName: string | undefined,\n colorPalette: ColorPalette | undefined\n): ColorScaleResult {\n if (colorFieldName && bubbleData.length > 0) {\n const colorValues = bubbleData\n .map((item) => (typeof item.color === 'string' ? parseFloat(item.color) : item.color))\n .filter((val): val is number => !isNaN(val as number))\n const isNumericColorField =\n colorValues.length === bubbleData.length && colorValues.every((val) => typeof val === 'number')\n\n if (isNumericColorField) {\n const colorScale = scaleQuantize<string>()\n .domain([Math.min(...colorValues), Math.max(...colorValues)])\n .range(colorPalette?.gradient || CHART_COLORS_GRADIENT)\n return { colorScale, isNumericColorField, uniqueColors: [] }\n }\n\n const uniqueColors = [...new Set(bubbleData.map((d) => String(d.color)))]\n const colorScale = scaleOrdinal<string>().domain(uniqueColors).range(colorPalette?.colors || CHART_COLORS)\n return { colorScale, isNumericColorField, uniqueColors }\n }\n\n const colorScale = scaleOrdinal<string>().domain(['default']).range([CHART_COLORS[0]])\n return { colorScale, isNumericColorField: false, uniqueColors: [] }\n}\n\n/** Format an x-axis tick for a time dimension based on its granularity. */\nfunction formatTimeTick(value: number | { valueOf(): number }, granularity: string | undefined): string {\n const date = new Date(value as number)\n if (isNaN(date.getTime())) return String(value)\n const yr = date.getUTCFullYear()\n const mo = String(date.getUTCMonth() + 1).padStart(2, '0')\n const dy = String(date.getUTCDate()).padStart(2, '0')\n switch (granularity?.toLowerCase()) {\n case 'year':\n return String(yr)\n case 'quarter':\n return `${yr}-Q${Math.floor(date.getUTCMonth() / 3) + 1}`\n case 'month':\n return `${yr}-${mo}`\n case 'week':\n case 'day':\n return `${yr}-${mo}-${dy}`\n case 'hour':\n return `${mo}-${dy} ${String(date.getUTCHours()).padStart(2, '0')}:00`\n default:\n return `${yr}-${mo}`\n }\n}\n\n/** Draw the dashed background grid. */\nfunction drawGrid(\n g: G,\n xScale: ScaleLinear<number, number>,\n yScale: ScaleLinear<number, number>,\n width: number,\n chartHeight: number,\n gridColor: string\n) {\n const styleGrid = (grid: G) => {\n grid.selectAll('line').style('stroke', gridColor).style('stroke-dasharray', '3,3').style('opacity', 0.3)\n grid.select('.domain').style('stroke', 'none')\n }\n const xGrid = g\n .append('g')\n .attr('transform', `translate(0,${chartHeight})`)\n .call(axisBottom(xScale).tickSize(-chartHeight).tickFormat(() => '')) as unknown as G\n styleGrid(xGrid)\n const yGrid = g.append('g').call(axisLeft(yScale).tickSize(-width).tickFormat(() => '')) as unknown as G\n styleGrid(yGrid)\n}\n\n/** Draw X and Y axes with labels and theme-aware styling. */\nfunction drawAxes(\n ctx: BubbleRenderContext,\n g: G,\n xScale: ScaleLinear<number, number>,\n yScale: ScaleLinear<number, number>,\n width: number,\n chartHeight: number,\n textColor: string,\n gridColor: string\n) {\n const { fields, options, queryObject, getFieldLabel } = ctx\n const isTimeDimension =\n queryObject?.timeDimensions?.some((td: { dimension: string }) => td.dimension === fields.xAxisField) || false\n const xGranularity = queryObject?.timeDimensions?.find(\n (td: { dimension: string; granularity?: string }) => td.dimension === fields.xAxisField\n )?.granularity\n\n const xAxisGenerator = axisBottom(xScale)\n if (isTimeDimension) {\n xAxisGenerator.tickFormat((d) => formatTimeTick(d as number, xGranularity))\n } else if (options.xAxisFormat) {\n xAxisGenerator.tickFormat((d) => formatAxisValue(d as number, options.xAxisFormat))\n }\n\n const xAxis = g.append('g').attr('transform', `translate(0,${chartHeight})`).call(xAxisGenerator)\n xAxis.selectAll('text').style('fill', textColor)\n xAxis.selectAll('line, path').style('stroke', gridColor)\n xAxis\n .append('text')\n .attr('x', width / 2)\n .attr('y', 35)\n .attr('fill', textColor)\n .style('text-anchor', 'middle')\n .style('font-size', '12px')\n .text(options.xAxisFormat?.label || getFieldLabel(fields.xAxisField))\n\n const yAxisGenerator = axisLeft(yScale)\n if (options.leftYAxisFormat) {\n yAxisGenerator.tickFormat((d) => formatAxisValue(d as number, options.leftYAxisFormat))\n }\n const yAxis = g.append('g').call(yAxisGenerator)\n yAxis.selectAll('text').style('fill', textColor)\n yAxis.selectAll('line, path').style('stroke', gridColor)\n yAxis\n .append('text')\n .attr('transform', 'rotate(-90)')\n .attr('y', -35)\n .attr('x', -chartHeight / 2)\n .attr('fill', textColor)\n .style('text-anchor', 'middle')\n .style('font-size', '12px')\n .text(options.leftYAxisFormat?.label || getFieldLabel(fields.yAxisField))\n}\n\n/** Create the floating HTML tooltip element. */\nfunction createTooltip() {\n return select('body')\n .append('div')\n .attr('class', 'bubble-chart-tooltip')\n .style('position', 'absolute')\n .style('padding', '8px')\n .style('background', 'rgba(0, 0, 0, 0.8)')\n .style('color', 'white')\n .style('border-radius', '4px')\n .style('font-size', '12px')\n .style('pointer-events', 'none')\n .style('opacity', 0)\n .style('z-index', 1000)\n}\n\ntype Tooltip = ReturnType<typeof createTooltip>\ntype Bubbles = Selection<SVGCircleElement, BubbleData, SVGGElement, unknown>\n\n/** Compose the multi-line tooltip HTML for a bubble. */\nfunction bubbleTooltipHtml(ctx: BubbleRenderContext, d: BubbleData): string {\n const { fields, options, getFieldLabel } = ctx\n const fmt = (v: number) => (options.leftYAxisFormat ? formatAxisValue(v, options.leftYAxisFormat) : v)\n return [\n `<strong>${d.series || 'Unknown'}</strong>`,\n `${getFieldLabel(fields.xAxisField)}: ${d.xLabel || (options.xAxisFormat ? formatAxisValue(d.x, options.xAxisFormat) : d.x)}`,\n `${getFieldLabel(fields.yAxisField)}: ${fmt(d.y)}`,\n `${getFieldLabel(fields.sizeFieldName)}: ${fmt(d.size)}`,\n fields.colorFieldName && d.color ? `${getFieldLabel(fields.colorFieldName)}: ${d.color}` : ''\n ]\n .filter(Boolean)\n .join('<br>')\n}\n\n/** Attach hover handlers showing/hiding the tooltip and growing the bubble. */\nfunction attachBubbleHover(\n ctx: BubbleRenderContext,\n bubbles: Bubbles,\n tooltip: Tooltip,\n sizeScale: ScalePower<number, number>\n) {\n bubbles\n .on('mouseover', function (event, d) {\n select(this).transition().duration(200).style('opacity', 1).attr('r', sizeScale(d.size) * 1.1)\n tooltip\n .html(bubbleTooltipHtml(ctx, d))\n .style('left', event.pageX + 10 + 'px')\n .style('top', event.pageY - 10 + 'px')\n .transition()\n .duration(200)\n .style('opacity', 1)\n })\n .on('mousemove', function (event) {\n tooltip.style('left', event.pageX + 10 + 'px').style('top', event.pageY - 10 + 'px')\n })\n .on('mouseout', function (_event, d) {\n select(this).transition().duration(200).style('opacity', ctx.options.bubbleOpacity).attr('r', sizeScale(d.size))\n tooltip.transition().duration(200).style('opacity', 0)\n })\n}\n\n/** Draw the gradient legend for a numeric colour field. */\nfunction drawNumericLegend(\n ctx: BubbleRenderContext,\n svg: Selection<SVGSVGElement, unknown, null, undefined>,\n g: G,\n width: number,\n chartHeight: number,\n textColor: string\n) {\n const { bubbleData, fields, options, colorPalette, getFieldLabel } = ctx\n const legendWidth = 200\n const legendHeight = 20\n const minValue = Math.min(...bubbleData.map((d) => d.color as number))\n const maxValue = Math.max(...bubbleData.map((d) => d.color as number))\n const fmt = (v: number) => (options.leftYAxisFormat ? formatAxisValue(v, options.leftYAxisFormat) : v.toFixed(2))\n\n const legend = g\n .append('g')\n .attr('class', 'color-legend')\n .attr('transform', `translate(${width / 2 - legendWidth / 2}, ${chartHeight + 60})`)\n\n const gradient = svg\n .append('defs')\n .append('linearGradient')\n .attr('id', 'color-scale-gradient')\n .attr('x1', '0%').attr('y1', '0%').attr('x2', '100%').attr('y2', '0%')\n const gradientColors = colorPalette?.gradient || CHART_COLORS_GRADIENT\n gradientColors.forEach((color, i) => {\n gradient.append('stop').attr('offset', `${(i / (gradientColors.length - 1)) * 100}%`).attr('stop-color', color)\n })\n\n legend.append('rect')\n .attr('width', legendWidth).attr('height', legendHeight)\n .style('fill', 'url(#color-scale-gradient)').style('stroke', '#ccc').style('stroke-width', 1)\n legend.append('text')\n .attr('x', 0).attr('y', legendHeight + 15).attr('text-anchor', 'start')\n .style('font-size', '11px').style('fill', textColor).text(fmt(minValue))\n legend.append('text')\n .attr('x', legendWidth).attr('y', legendHeight + 15).attr('text-anchor', 'end')\n .style('font-size', '11px').style('fill', textColor).text(fmt(maxValue))\n legend.append('text')\n .attr('x', legendWidth / 2).attr('y', -5).attr('text-anchor', 'middle')\n .style('font-size', '12px').style('font-weight', 'bold').style('fill', textColor)\n .text(getFieldLabel(fields.colorFieldName!))\n}\n\n/** Draw the categorical legend (one swatch per series) with hover highlighting. */\nfunction drawCategoricalLegend(\n ctx: BubbleRenderContext,\n g: G,\n width: number,\n chartHeight: number,\n textColor: string,\n uniqueColors: string[],\n colorScale: ScaleOrdinal<string, string>,\n bubbles: Bubbles\n) {\n const { fields, options } = ctx\n if (uniqueColors.length === 0) return\n\n const legend = g\n .append('g')\n .attr('class', 'legend')\n .attr('transform', `translate(${width / 2 - (uniqueColors.length * 80) / 2}, ${chartHeight + 60})`)\n\n const legendItem = legend\n .selectAll('.legend-item')\n .data(uniqueColors)\n .enter()\n .append('g')\n .attr('class', 'legend-item')\n .attr('transform', (_d, i) => `translate(${i * 80}, 0)`)\n .style('cursor', 'pointer')\n\n legendItem.append('circle')\n .attr('cx', 5).attr('cy', 5).attr('r', 5)\n .style('fill', (d) => colorScale(d as string)).style('opacity', options.bubbleOpacity)\n legendItem.append('text')\n .attr('x', 15).attr('y', 5).attr('dy', '.35em')\n .style('font-size', '11px').style('fill', textColor).text((d) => String(d))\n\n legendItem\n .on('mouseover', function (_event, legendKey) {\n bubbles.transition().duration(200).style('opacity', (d) =>\n fields.colorFieldName && String(d.color) === legendKey ? 1 : 0.2\n )\n })\n .on('mouseout', function () {\n bubbles.transition().duration(200).style('opacity', options.bubbleOpacity)\n })\n}\n\n/**\n * Render the bubble chart into the given SVG element. Returns a cleanup function\n * that removes the floating tooltip. Returns undefined when there is nothing to draw.\n */\nexport function renderBubbleChart(ctx: BubbleRenderContext): (() => void) | undefined {\n const { svgEl, bubbleData, fields, options, dimensions, colorPalette, isDark } = ctx\n\n select(svgEl).selectAll('*').remove()\n if (bubbleData.length === 0) return undefined\n\n const margin = {\n ...CHART_MARGINS,\n left: CHART_MARGINS.left + 30,\n bottom: options.showLegend && fields.colorFieldName ? 100 : 40\n }\n const width = dimensions.width - margin.left - margin.right\n const chartHeight = dimensions.height - margin.top - margin.bottom\n\n const svg = select(svgEl).attr('width', dimensions.width).attr('height', dimensions.height)\n const g = svg.append('g').attr('transform', `translate(${margin.left},${margin.top})`)\n\n const xScale = scaleLinear().domain(extent(bubbleData, (d) => d.x) as [number, number]).range([0, width]).nice()\n const yScale = scaleLinear().domain(extent(bubbleData, (d) => d.y) as [number, number]).range([chartHeight, 0]).nice()\n const sizeScale = scaleSqrt()\n .domain([0, max(bubbleData, (d) => d.size) as number])\n .range([options.minBubbleSize, options.maxBubbleSize])\n\n const { colorScale, isNumericColorField, uniqueColors } = buildColorScale(\n bubbleData,\n fields.colorFieldName,\n colorPalette\n )\n const { textColor, gridColor } = resolveThemeColors(isDark)\n\n if (options.showGrid) {\n drawGrid(g, xScale, yScale, width, chartHeight, gridColor)\n }\n drawAxes(ctx, g, xScale, yScale, width, chartHeight, textColor, gridColor)\n\n const tooltip = createTooltip()\n\n const bubbles = g\n .selectAll('.bubble')\n .data(bubbleData)\n .enter()\n .append('circle')\n .attr('class', 'bubble')\n .attr('cx', (d) => xScale(d.x))\n .attr('cy', (d) => yScale(d.y))\n .attr('r', (d) => sizeScale(d.size))\n .style('fill', (d) => {\n if (fields.colorFieldName && d.color !== undefined) {\n return isNumericColorField\n ? (colorScale as ScaleQuantize<string>)(d.color as number)\n : (colorScale as ScaleOrdinal<string, string>)(String(d.color))\n }\n return CHART_COLORS[0]\n })\n .style('opacity', options.bubbleOpacity)\n .style('stroke', '#fff')\n .style('stroke-width', 1)\n .style('cursor', 'pointer') as Bubbles\n\n if (options.showTooltip) {\n attachBubbleHover(ctx, bubbles, tooltip, sizeScale)\n }\n\n if (options.showLegend && fields.colorFieldName) {\n if (isNumericColorField) {\n drawNumericLegend(ctx, svg, g, width, chartHeight, textColor)\n } else {\n drawCategoricalLegend(ctx, g, width, chartHeight, textColor, uniqueColors, colorScale as ScaleOrdinal<string, string>, bubbles)\n }\n }\n\n return () => {\n tooltip.remove()\n }\n}\n","import React, { useEffect, useMemo } from 'react'\nimport { useTranslation } from '../../hooks/useTranslation.js'\nimport { transition as _transition } from 'd3'\n// _transition import is for side effects only - it extends Selection.prototype with .transition()\nvoid _transition\nimport { useCubeFieldLabel } from '../../hooks/useCubeFieldLabel.js'\nimport { useTheme } from '../../hooks/useTheme.js'\nimport { useChartDimensions } from './useChartDimensions.js'\nimport {\n resolveBubbleDisplayOptions,\n resolveBubbleFields,\n transformBubbleData\n} from './BubbleChart.helpers.js'\nimport { renderBubbleChart } from './BubbleChart.render.js'\nimport type { ChartProps } from '../../types.js'\n\nconst BubbleChart = React.memo(function BubbleChart({\n data,\n chartConfig,\n displayConfig = {},\n queryObject,\n height = \"100%\",\n colorPalette\n}: ChartProps) {\n const { t } = useTranslation()\n const svgRef = React.useRef<SVGSVGElement | null>(null)\n const { containerRef, dimensions, dimensionsReady } = useChartDimensions()\n const { theme } = useTheme()\n const getFieldLabel = useCubeFieldLabel()\n\n // Memoize display options to keep the render effect dependencies stable\n const options = useMemo(() => resolveBubbleDisplayOptions(displayConfig), [displayConfig])\n\n useEffect(() => {\n if (!data || data.length === 0 || !svgRef.current || !dimensionsReady || dimensions.width === 0) {\n return\n }\n\n const fields = resolveBubbleFields(chartConfig)\n if (!fields) return\n\n const bubbleData = transformBubbleData(data as Record<string, any>[], fields, queryObject)\n\n return renderBubbleChart({\n svgEl: svgRef.current,\n bubbleData,\n fields,\n options,\n dimensions,\n queryObject,\n colorPalette,\n isDark: theme !== 'light',\n getFieldLabel\n })\n }, [data, chartConfig, options, queryObject, dimensions, dimensionsReady, colorPalette, theme, getFieldLabel])\n\n if (!data || data.length === 0) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-text-muted\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.noData')}</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">{t('chart.runtime.noDataHint.bubble')}</div>\n </div>\n </div>\n )\n }\n\n // Validate that we have required fields\n const hasValidConfig = chartConfig?.xAxis && chartConfig?.yAxis && chartConfig?.series\n if (!hasValidConfig) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-warning\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.activityGridConfigRequired')}</div>\n <div className=\"dc:text-xs\">{t('chart.runtime.configErrorHint.bubbleRequired')}</div>\n <div className=\"dc:text-xs dc:mt-1\">{t('chart.runtime.configErrorHint.bubbleOptional')}</div>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"dc:w-full dc:flex-1 dc:flex dc:flex-col dc:relative\" style={{ height, minHeight: '250px', overflow: 'hidden' }}>\n <div ref={containerRef} className=\"dc:w-full dc:h-full dc:relative\">\n <svg ref={svgRef} className=\"dc:w-full dc:h-full\" />\n {!dimensionsReady && (\n <div className=\"dc:absolute dc:inset-0 dc:flex dc:items-center dc:justify-center\">\n <div className=\"text-dc-text-muted dc:text-sm\">{t('chart.runtime.measuringDimensions')}</div>\n </div>\n )}\n </div>\n </div>\n )\n})\n\nexport default BubbleChart\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"chart-bubble-DvP_6_n9.js","names":[],"sources":["../../../src/client/hooks/useTheme.ts","../../../src/client/components/charts/BubbleChart.render.ts","../../../src/client/components/charts/BubbleChart.tsx"],"sourcesContent":["/**\n * useTheme - External Theme State Hook\n *\n * Uses React 18's useSyncExternalStore to prevent parent component re-renders.\n * The theme state is stored externally and changes are propagated through\n * a subscribe/notify pattern.\n *\n * This prevents the ThemeToggle component from causing Layout re-renders.\n */\n\nimport { useSyncExternalStore, useCallback } from 'react'\nimport { getTheme, setTheme as setThemeUtil, watchThemeChanges, type Theme } from '../theme/index.js'\n\n// External store for theme state\nconst themeStore = {\n listeners: new Set<() => void>(),\n\n subscribe(listener: () => void) {\n this.listeners.add(listener)\n return () => this.listeners.delete(listener)\n },\n\n notify() {\n this.listeners.forEach(listener => listener())\n }\n}\n\n// Watch theme changes from DOM/system and notify subscribers\nwatchThemeChanges(() => {\n themeStore.notify()\n})\n\n/**\n * Hook to access and update theme\n *\n * Returns current theme and a setter function.\n * Only components using this hook will re-render on theme changes.\n */\nexport function useTheme() {\n // Subscribe to external theme store\n const theme = useSyncExternalStore(\n themeStore.subscribe.bind(themeStore),\n getTheme, // Client-side snapshot\n getTheme // Server-side snapshot (SSR)\n )\n\n // Stable setter function\n const setTheme = useCallback((newTheme: Theme) => {\n setThemeUtil(newTheme)\n themeStore.notify()\n }, [])\n\n return { theme, setTheme }\n}\n","/**\n * D3 rendering for BubbleChart, extracted from the component's render effect.\n *\n * The effect orchestrates these pure-ish drawing helpers. Behaviour matches the\n * original inline D3 exactly; only the structure changed (one function per\n * concern) to keep each helper's complexity low.\n */\nimport {\n select,\n scaleLinear,\n scaleSqrt,\n scaleOrdinal,\n scaleQuantize,\n extent,\n max,\n axisBottom,\n axisLeft,\n type Selection,\n type ScaleLinear,\n type ScalePower,\n type ScaleOrdinal,\n type ScaleQuantize\n} from 'd3'\nimport { CHART_COLORS, CHART_COLORS_GRADIENT, CHART_MARGINS } from '../../utils/chartConstants.js'\nimport { formatAxisValue } from '../../utils/chartUtils.js'\nimport { resolveThemeColors } from './BubbleChart.helpers.js'\nimport type { BubbleData, BubbleDisplayOptions, BubbleFields } from './BubbleChart.helpers.js'\nimport type { ColorPalette, CubeQuery } from '../../types.js'\n\ntype ColorScale = ScaleOrdinal<string, string> | ScaleQuantize<string>\ntype G = Selection<SVGGElement, unknown, null, undefined>\n\nexport interface BubbleRenderContext {\n svgEl: SVGSVGElement\n bubbleData: BubbleData[]\n fields: BubbleFields\n options: BubbleDisplayOptions\n dimensions: { width: number; height: number }\n queryObject: CubeQuery | undefined\n colorPalette?: ColorPalette\n isDark: boolean\n getFieldLabel: (field: string) => string\n}\n\ninterface ColorScaleResult {\n colorScale: ColorScale\n isNumericColorField: boolean\n uniqueColors: string[]\n}\n\n/** Build the bubble fill colour scale (numeric → quantize, categorical → ordinal). */\nfunction buildColorScale(\n bubbleData: BubbleData[],\n colorFieldName: string | undefined,\n colorPalette: ColorPalette | undefined\n): ColorScaleResult {\n if (colorFieldName && bubbleData.length > 0) {\n const colorValues = bubbleData\n .map((item) => (typeof item.color === 'string' ? parseFloat(item.color) : item.color))\n .filter((val): val is number => !isNaN(val as number))\n const isNumericColorField =\n colorValues.length === bubbleData.length && colorValues.every((val) => typeof val === 'number')\n\n if (isNumericColorField) {\n const colorScale = scaleQuantize<string>()\n .domain([Math.min(...colorValues), Math.max(...colorValues)])\n .range(colorPalette?.gradient || CHART_COLORS_GRADIENT)\n return { colorScale, isNumericColorField, uniqueColors: [] }\n }\n\n const uniqueColors = [...new Set(bubbleData.map((d) => String(d.color)))]\n const colorScale = scaleOrdinal<string>().domain(uniqueColors).range(colorPalette?.colors || CHART_COLORS)\n return { colorScale, isNumericColorField, uniqueColors }\n }\n\n const colorScale = scaleOrdinal<string>().domain(['default']).range([CHART_COLORS[0]])\n return { colorScale, isNumericColorField: false, uniqueColors: [] }\n}\n\n/** Format an x-axis tick for a time dimension based on its granularity. */\nfunction formatTimeTick(value: number | { valueOf(): number }, granularity: string | undefined): string {\n const date = new Date(value as number)\n if (isNaN(date.getTime())) return String(value)\n const yr = date.getUTCFullYear()\n const mo = String(date.getUTCMonth() + 1).padStart(2, '0')\n const dy = String(date.getUTCDate()).padStart(2, '0')\n switch (granularity?.toLowerCase()) {\n case 'year':\n return String(yr)\n case 'quarter':\n return `${yr}-Q${Math.floor(date.getUTCMonth() / 3) + 1}`\n case 'month':\n return `${yr}-${mo}`\n case 'week':\n case 'day':\n return `${yr}-${mo}-${dy}`\n case 'hour':\n return `${mo}-${dy} ${String(date.getUTCHours()).padStart(2, '0')}:00`\n default:\n return `${yr}-${mo}`\n }\n}\n\n/** Draw the dashed background grid. */\nfunction drawGrid(\n g: G,\n xScale: ScaleLinear<number, number>,\n yScale: ScaleLinear<number, number>,\n width: number,\n chartHeight: number,\n gridColor: string\n) {\n const styleGrid = (grid: G) => {\n grid.selectAll('line').style('stroke', gridColor).style('stroke-dasharray', '3,3').style('opacity', 0.3)\n grid.select('.domain').style('stroke', 'none')\n }\n const xGrid = g\n .append('g')\n .attr('transform', `translate(0,${chartHeight})`)\n .call(axisBottom(xScale).tickSize(-chartHeight).tickFormat(() => '')) as unknown as G\n styleGrid(xGrid)\n const yGrid = g.append('g').call(axisLeft(yScale).tickSize(-width).tickFormat(() => '')) as unknown as G\n styleGrid(yGrid)\n}\n\n/** Draw X and Y axes with labels and theme-aware styling. */\nfunction drawAxes(\n ctx: BubbleRenderContext,\n g: G,\n xScale: ScaleLinear<number, number>,\n yScale: ScaleLinear<number, number>,\n width: number,\n chartHeight: number,\n textColor: string,\n gridColor: string\n) {\n const { fields, options, queryObject, getFieldLabel } = ctx\n const isTimeDimension =\n queryObject?.timeDimensions?.some((td: { dimension: string }) => td.dimension === fields.xAxisField) || false\n const xGranularity = queryObject?.timeDimensions?.find(\n (td: { dimension: string; granularity?: string }) => td.dimension === fields.xAxisField\n )?.granularity\n\n const xAxisGenerator = axisBottom(xScale)\n if (isTimeDimension) {\n xAxisGenerator.tickFormat((d) => formatTimeTick(d as number, xGranularity))\n } else if (options.xAxisFormat) {\n xAxisGenerator.tickFormat((d) => formatAxisValue(d as number, options.xAxisFormat))\n }\n\n const xAxis = g.append('g').attr('transform', `translate(0,${chartHeight})`).call(xAxisGenerator)\n xAxis.selectAll('text').style('fill', textColor)\n xAxis.selectAll('line, path').style('stroke', gridColor)\n xAxis\n .append('text')\n .attr('x', width / 2)\n .attr('y', 35)\n .attr('fill', textColor)\n .style('text-anchor', 'middle')\n .style('font-size', '12px')\n .text(options.xAxisFormat?.label || getFieldLabel(fields.xAxisField))\n\n const yAxisGenerator = axisLeft(yScale)\n if (options.leftYAxisFormat) {\n yAxisGenerator.tickFormat((d) => formatAxisValue(d as number, options.leftYAxisFormat))\n }\n const yAxis = g.append('g').call(yAxisGenerator)\n yAxis.selectAll('text').style('fill', textColor)\n yAxis.selectAll('line, path').style('stroke', gridColor)\n yAxis\n .append('text')\n .attr('transform', 'rotate(-90)')\n .attr('y', -35)\n .attr('x', -chartHeight / 2)\n .attr('fill', textColor)\n .style('text-anchor', 'middle')\n .style('font-size', '12px')\n .text(options.leftYAxisFormat?.label || getFieldLabel(fields.yAxisField))\n}\n\n/** Create the floating HTML tooltip element. */\nfunction createTooltip() {\n return select('body')\n .append('div')\n .attr('class', 'bubble-chart-tooltip')\n .style('position', 'absolute')\n .style('padding', '8px')\n .style('background', 'rgba(0, 0, 0, 0.8)')\n .style('color', 'white')\n .style('border-radius', '4px')\n .style('font-size', '12px')\n .style('pointer-events', 'none')\n .style('opacity', 0)\n .style('z-index', 1000)\n}\n\ntype Tooltip = ReturnType<typeof createTooltip>\ntype Bubbles = Selection<SVGCircleElement, BubbleData, SVGGElement, unknown>\n\n/** Compose the multi-line tooltip HTML for a bubble. */\nfunction bubbleTooltipHtml(ctx: BubbleRenderContext, d: BubbleData): string {\n const { fields, options, getFieldLabel } = ctx\n const fmt = (v: number) => (options.leftYAxisFormat ? formatAxisValue(v, options.leftYAxisFormat) : v)\n return [\n `<strong>${d.series || 'Unknown'}</strong>`,\n `${getFieldLabel(fields.xAxisField)}: ${d.xLabel || (options.xAxisFormat ? formatAxisValue(d.x, options.xAxisFormat) : d.x)}`,\n `${getFieldLabel(fields.yAxisField)}: ${fmt(d.y)}`,\n `${getFieldLabel(fields.sizeFieldName)}: ${fmt(d.size)}`,\n fields.colorFieldName && d.color ? `${getFieldLabel(fields.colorFieldName)}: ${d.color}` : ''\n ]\n .filter(Boolean)\n .join('<br>')\n}\n\n/** Attach hover handlers showing/hiding the tooltip and growing the bubble. */\nfunction attachBubbleHover(\n ctx: BubbleRenderContext,\n bubbles: Bubbles,\n tooltip: Tooltip,\n sizeScale: ScalePower<number, number>\n) {\n bubbles\n .on('mouseover', function (event, d) {\n select(this).transition().duration(200).style('opacity', 1).attr('r', sizeScale(d.size) * 1.1)\n tooltip\n .html(bubbleTooltipHtml(ctx, d))\n .style('left', event.pageX + 10 + 'px')\n .style('top', event.pageY - 10 + 'px')\n .transition()\n .duration(200)\n .style('opacity', 1)\n })\n .on('mousemove', function (event) {\n tooltip.style('left', event.pageX + 10 + 'px').style('top', event.pageY - 10 + 'px')\n })\n .on('mouseout', function (_event, d) {\n select(this).transition().duration(200).style('opacity', ctx.options.bubbleOpacity).attr('r', sizeScale(d.size))\n tooltip.transition().duration(200).style('opacity', 0)\n })\n}\n\n/** Draw the gradient legend for a numeric colour field. */\nfunction drawNumericLegend(\n ctx: BubbleRenderContext,\n svg: Selection<SVGSVGElement, unknown, null, undefined>,\n g: G,\n width: number,\n chartHeight: number,\n textColor: string\n) {\n const { bubbleData, fields, options, colorPalette, getFieldLabel } = ctx\n const legendWidth = 200\n const legendHeight = 20\n const minValue = Math.min(...bubbleData.map((d) => d.color as number))\n const maxValue = Math.max(...bubbleData.map((d) => d.color as number))\n const fmt = (v: number) => (options.leftYAxisFormat ? formatAxisValue(v, options.leftYAxisFormat) : v.toFixed(2))\n\n const legend = g\n .append('g')\n .attr('class', 'color-legend')\n .attr('transform', `translate(${width / 2 - legendWidth / 2}, ${chartHeight + 60})`)\n\n const gradient = svg\n .append('defs')\n .append('linearGradient')\n .attr('id', 'color-scale-gradient')\n .attr('x1', '0%').attr('y1', '0%').attr('x2', '100%').attr('y2', '0%')\n const gradientColors = colorPalette?.gradient || CHART_COLORS_GRADIENT\n gradientColors.forEach((color, i) => {\n gradient.append('stop').attr('offset', `${(i / (gradientColors.length - 1)) * 100}%`).attr('stop-color', color)\n })\n\n legend.append('rect')\n .attr('width', legendWidth).attr('height', legendHeight)\n .style('fill', 'url(#color-scale-gradient)').style('stroke', '#ccc').style('stroke-width', 1)\n legend.append('text')\n .attr('x', 0).attr('y', legendHeight + 15).attr('text-anchor', 'start')\n .style('font-size', '11px').style('fill', textColor).text(fmt(minValue))\n legend.append('text')\n .attr('x', legendWidth).attr('y', legendHeight + 15).attr('text-anchor', 'end')\n .style('font-size', '11px').style('fill', textColor).text(fmt(maxValue))\n legend.append('text')\n .attr('x', legendWidth / 2).attr('y', -5).attr('text-anchor', 'middle')\n .style('font-size', '12px').style('font-weight', 'bold').style('fill', textColor)\n .text(getFieldLabel(fields.colorFieldName!))\n}\n\n/** Draw the categorical legend (one swatch per series) with hover highlighting. */\nfunction drawCategoricalLegend(\n ctx: BubbleRenderContext,\n g: G,\n width: number,\n chartHeight: number,\n textColor: string,\n uniqueColors: string[],\n colorScale: ScaleOrdinal<string, string>,\n bubbles: Bubbles\n) {\n const { fields, options } = ctx\n if (uniqueColors.length === 0) return\n\n const legend = g\n .append('g')\n .attr('class', 'legend')\n .attr('transform', `translate(${width / 2 - (uniqueColors.length * 80) / 2}, ${chartHeight + 60})`)\n\n const legendItem = legend\n .selectAll('.legend-item')\n .data(uniqueColors)\n .enter()\n .append('g')\n .attr('class', 'legend-item')\n .attr('transform', (_d, i) => `translate(${i * 80}, 0)`)\n .style('cursor', 'pointer')\n\n legendItem.append('circle')\n .attr('cx', 5).attr('cy', 5).attr('r', 5)\n .style('fill', (d) => colorScale(d as string)).style('opacity', options.bubbleOpacity)\n legendItem.append('text')\n .attr('x', 15).attr('y', 5).attr('dy', '.35em')\n .style('font-size', '11px').style('fill', textColor).text((d) => String(d))\n\n legendItem\n .on('mouseover', function (_event, legendKey) {\n bubbles.transition().duration(200).style('opacity', (d) =>\n fields.colorFieldName && String(d.color) === legendKey ? 1 : 0.2\n )\n })\n .on('mouseout', function () {\n bubbles.transition().duration(200).style('opacity', options.bubbleOpacity)\n })\n}\n\n/**\n * Render the bubble chart into the given SVG element. Returns a cleanup function\n * that removes the floating tooltip. Returns undefined when there is nothing to draw.\n */\nexport function renderBubbleChart(ctx: BubbleRenderContext): (() => void) | undefined {\n const { svgEl, bubbleData, fields, options, dimensions, colorPalette, isDark } = ctx\n\n select(svgEl).selectAll('*').remove()\n if (bubbleData.length === 0) return undefined\n\n const margin = {\n ...CHART_MARGINS,\n left: CHART_MARGINS.left + 30,\n bottom: options.showLegend && fields.colorFieldName ? 100 : 40\n }\n const width = dimensions.width - margin.left - margin.right\n const chartHeight = dimensions.height - margin.top - margin.bottom\n\n const svg = select(svgEl).attr('width', dimensions.width).attr('height', dimensions.height)\n const g = svg.append('g').attr('transform', `translate(${margin.left},${margin.top})`)\n\n const xScale = scaleLinear().domain(extent(bubbleData, (d) => d.x) as [number, number]).range([0, width]).nice()\n const yScale = scaleLinear().domain(extent(bubbleData, (d) => d.y) as [number, number]).range([chartHeight, 0]).nice()\n const sizeScale = scaleSqrt()\n .domain([0, max(bubbleData, (d) => d.size) as number])\n .range([options.minBubbleSize, options.maxBubbleSize])\n\n const { colorScale, isNumericColorField, uniqueColors } = buildColorScale(\n bubbleData,\n fields.colorFieldName,\n colorPalette\n )\n const { textColor, gridColor } = resolveThemeColors(isDark)\n\n if (options.showGrid) {\n drawGrid(g, xScale, yScale, width, chartHeight, gridColor)\n }\n drawAxes(ctx, g, xScale, yScale, width, chartHeight, textColor, gridColor)\n\n const tooltip = createTooltip()\n\n const bubbles = g\n .selectAll('.bubble')\n .data(bubbleData)\n .enter()\n .append('circle')\n .attr('class', 'bubble')\n .attr('cx', (d) => xScale(d.x))\n .attr('cy', (d) => yScale(d.y))\n .attr('r', (d) => sizeScale(d.size))\n .style('fill', (d) => {\n if (fields.colorFieldName && d.color !== undefined) {\n return isNumericColorField\n ? (colorScale as ScaleQuantize<string>)(d.color as number)\n : (colorScale as ScaleOrdinal<string, string>)(String(d.color))\n }\n return CHART_COLORS[0]\n })\n .style('opacity', options.bubbleOpacity)\n .style('stroke', '#fff')\n .style('stroke-width', 1)\n .style('cursor', 'pointer') as Bubbles\n\n if (options.showTooltip) {\n attachBubbleHover(ctx, bubbles, tooltip, sizeScale)\n }\n\n if (options.showLegend && fields.colorFieldName) {\n if (isNumericColorField) {\n drawNumericLegend(ctx, svg, g, width, chartHeight, textColor)\n } else {\n drawCategoricalLegend(ctx, g, width, chartHeight, textColor, uniqueColors, colorScale as ScaleOrdinal<string, string>, bubbles)\n }\n }\n\n return () => {\n tooltip.remove()\n }\n}\n","import React, { useEffect, useMemo } from 'react'\nimport { useTranslation } from '../../hooks/useTranslation.js'\nimport { transition as _transition } from 'd3'\n// _transition import is for side effects only - it extends Selection.prototype with .transition()\nvoid _transition\nimport { useCubeFieldLabel } from '../../hooks/useCubeFieldLabel.js'\nimport { useTheme } from '../../hooks/useTheme.js'\nimport { useChartDimensions } from './useChartDimensions.js'\nimport {\n resolveBubbleDisplayOptions,\n resolveBubbleFields,\n transformBubbleData\n} from './BubbleChart.helpers.js'\nimport { renderBubbleChart } from './BubbleChart.render.js'\nimport type { ChartProps } from '../../types.js'\n\nconst BubbleChart = React.memo(function BubbleChart({\n data,\n chartConfig,\n displayConfig = {},\n queryObject,\n height = \"100%\",\n colorPalette\n}: ChartProps) {\n const { t } = useTranslation()\n const svgRef = React.useRef<SVGSVGElement | null>(null)\n const { containerRef, dimensions, dimensionsReady } = useChartDimensions()\n const { theme } = useTheme()\n const getFieldLabel = useCubeFieldLabel()\n\n // Memoize display options to keep the render effect dependencies stable\n const options = useMemo(() => resolveBubbleDisplayOptions(displayConfig), [displayConfig])\n\n useEffect(() => {\n if (!data || data.length === 0 || !svgRef.current || !dimensionsReady || dimensions.width === 0) {\n return\n }\n\n const fields = resolveBubbleFields(chartConfig)\n if (!fields) return\n\n const bubbleData = transformBubbleData(data as Record<string, any>[], fields, queryObject)\n\n return renderBubbleChart({\n svgEl: svgRef.current,\n bubbleData,\n fields,\n options,\n dimensions,\n queryObject,\n colorPalette,\n isDark: theme !== 'light',\n getFieldLabel\n })\n }, [data, chartConfig, options, queryObject, dimensions, dimensionsReady, colorPalette, theme, getFieldLabel])\n\n if (!data || data.length === 0) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-text-muted\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.noData')}</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">{t('chart.runtime.noDataHint.bubble')}</div>\n </div>\n </div>\n )\n }\n\n // Validate that we have required fields\n const hasValidConfig = chartConfig?.xAxis && chartConfig?.yAxis && chartConfig?.series\n if (!hasValidConfig) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-warning\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.activityGridConfigRequired')}</div>\n <div className=\"dc:text-xs\">{t('chart.runtime.configErrorHint.bubbleRequired')}</div>\n <div className=\"dc:text-xs dc:mt-1\">{t('chart.runtime.configErrorHint.bubbleOptional')}</div>\n </div>\n </div>\n )\n }\n\n return (\n <div className=\"dc:w-full dc:flex-1 dc:flex dc:flex-col dc:relative\" style={{ height, minHeight: '250px', overflow: 'hidden' }}>\n <div ref={containerRef} className=\"dc:w-full dc:h-full dc:relative\">\n <svg ref={svgRef} className=\"dc:w-full dc:h-full\" />\n {!dimensionsReady && (\n <div className=\"dc:absolute dc:inset-0 dc:flex dc:items-center dc:justify-center\">\n <div className=\"text-dc-text-muted dc:text-sm\">{t('chart.runtime.measuringDimensions')}</div>\n </div>\n )}\n </div>\n </div>\n )\n})\n\nexport default BubbleChart\n"],"mappings":"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"}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { n as e } from "./rolldown-runtime-CWhphoD1.js";
|
|
2
|
-
import { P as t, w as n } from "./chart-activity-grid-
|
|
2
|
+
import { P as t, w as n } from "./chart-activity-grid-DDqFVWoa.js";
|
|
3
3
|
import r, { useLayoutEffect as i, useMemo as a, useRef as o, useState as s } from "react";
|
|
4
4
|
import { Fragment as c, jsx as l, jsxs as u } from "react/jsx-runtime";
|
|
5
5
|
//#region src/client/components/charts/CandlestickChart.tsx
|
|
@@ -300,4 +300,4 @@ var y = r.memo(function({ data: e, chartConfig: r, displayConfig: c = {}, height
|
|
|
300
300
|
//#endregion
|
|
301
301
|
export { d as t };
|
|
302
302
|
|
|
303
|
-
//# sourceMappingURL=chart-candlestick-
|
|
303
|
+
//# sourceMappingURL=chart-candlestick-Dx8ZCMzl.js.map
|
package/dist/client/chunks/{chart-candlestick-DZp19Tzh.js.map → chart-candlestick-Dx8ZCMzl.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chart-candlestick-DZp19Tzh.js","names":[],"sources":["../../../src/client/components/charts/CandlestickChart.tsx"],"sourcesContent":["import React, { useLayoutEffect, useMemo, useRef, useState } from 'react'\nimport { useTranslation } from '../../hooks/useTranslation.js'\nimport { formatAxisValue } from '../../utils/chartUtils.js'\nimport type { ChartProps } from '../../types.js'\n\nconst BULL_COLOR_DEFAULT = '#22c55e'\nconst BEAR_COLOR_DEFAULT = '#ef4444'\nconst WICK_COLOR = '#94a3b8'\nconst MAX_CANDLES = 200\n\ninterface CandleData {\n label: string\n open: number\n close: number\n high: number\n low: number\n isBullish: boolean\n originalIndex: number\n}\n\nfunction parseNum(v: unknown): number | null {\n if (v === undefined || v === null) return null\n const n = typeof v === 'number' ? v : parseFloat(String(v))\n return isNaN(n) ? null : n\n}\n\nfunction Candle({\n x,\n candleWidth,\n openY,\n closeY,\n highY,\n lowY,\n isBullish,\n bullColor,\n bearColor,\n showWicks,\n label,\n}: {\n x: number\n candleWidth: number\n openY: number\n closeY: number\n highY: number\n lowY: number\n isBullish: boolean\n bullColor: string\n bearColor: string\n showWicks: boolean\n label: string\n}) {\n const fill = isBullish ? bullColor : bearColor\n const bodyTop = Math.min(openY, closeY)\n const bodyBottom = Math.max(openY, closeY)\n const bodyHeight = Math.max(bodyBottom - bodyTop, 1)\n const halfWidth = candleWidth / 2\n\n return (\n <g data-testid={`candle-${label}`}>\n <rect\n x={x - halfWidth}\n y={bodyTop}\n width={candleWidth}\n height={bodyHeight}\n fill={fill}\n data-testid={`candle-body-${label}`}\n data-bullish={isBullish}\n />\n {showWicks && (\n <>\n <line\n x1={x}\n y1={highY}\n x2={x}\n y2={bodyTop}\n stroke={WICK_COLOR}\n strokeWidth={1}\n data-testid={`wick-high-${label}`}\n />\n <line\n x1={x}\n y1={bodyBottom}\n x2={x}\n y2={lowY}\n stroke={WICK_COLOR}\n strokeWidth={1}\n data-testid={`wick-low-${label}`}\n />\n </>\n )}\n </g>\n )\n}\n\nfunction YAxisTicks({\n domainMin,\n domainMax,\n innerHeight,\n tickCount,\n format,\n}: {\n domainMin: number\n domainMax: number\n innerHeight: number\n tickCount: number\n format?: (v: number) => string\n}) {\n const ticks = useMemo(() => {\n const step = (domainMax - domainMin) / (tickCount - 1)\n return Array.from({ length: tickCount }, (_, i) => domainMin + i * step)\n }, [domainMin, domainMax, tickCount])\n\n const yScale = (v: number) => innerHeight - ((v - domainMin) / (domainMax - domainMin)) * innerHeight\n\n return (\n <g data-testid=\"y-axis\">\n <line y1={0} y2={innerHeight} stroke=\"currentColor\" strokeWidth={1} />\n {ticks.map((tick, i) => (\n <g key={i} transform={`translate(0, ${yScale(tick)})`}>\n <line x1={0} x2={-6} stroke=\"currentColor\" strokeWidth={1} />\n <text\n x={-10}\n textAnchor=\"end\"\n dominantBaseline=\"middle\"\n fontSize={11}\n fill=\"currentColor\"\n className=\"text-dc-text-secondary\"\n >\n {format ? format(tick) : tick.toLocaleString()}\n </text>\n <line x1={0} x2=\"100%\" stroke=\"currentColor\" strokeOpacity={0.1} strokeWidth={1} />\n </g>\n ))}\n </g>\n )\n}\n\nconst CandlestickChart = React.memo(function CandlestickChart({\n data,\n chartConfig,\n displayConfig = {},\n height = '100%',\n onDataPointClick,\n drillEnabled,\n}: ChartProps) {\n const { t } = useTranslation()\n const containerRef = useRef<HTMLDivElement>(null)\n const [dimensions, setDimensions] = useState({ width: 0, height: 0 })\n\n useLayoutEffect(() => {\n const el = containerRef.current\n if (!el) return\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width, height: h } = entry.contentRect\n if (width > 0 && h > 0) setDimensions({ width, height: h })\n }\n })\n observer.observe(el)\n const rect = el.getBoundingClientRect()\n if (rect.width > 0 && rect.height > 0) setDimensions({ width: rect.width, height: rect.height })\n return () => observer.disconnect()\n }, [])\n\n const bullColor = displayConfig?.bullColor ?? BULL_COLOR_DEFAULT\n const bearColor = displayConfig?.bearColor ?? BEAR_COLOR_DEFAULT\n const showWicks = displayConfig?.showWicks ?? true\n const rangeMode = displayConfig?.rangeMode ?? 'ohlc'\n const yAxisFormat = displayConfig?.leftYAxisFormat\n\n const { xField, openField, closeField, highField, lowField, configError } = useMemo(() => {\n const xField = Array.isArray(chartConfig?.xAxis)\n ? chartConfig.xAxis[0]\n : chartConfig?.xAxis ?? chartConfig?.x\n\n const yAxisFields: string[] = Array.isArray(chartConfig?.yAxis)\n ? chartConfig.yAxis\n : []\n\n const openField = yAxisFields[0] ?? ''\n const closeField = (rangeMode === 'range' ? yAxisFields[0] : yAxisFields[1]) ?? ''\n const highField = (rangeMode === 'range' ? yAxisFields[0] : yAxisFields[2]) ?? ''\n const lowField = (rangeMode === 'range' ? yAxisFields[1] : yAxisFields[3]) ?? ''\n\n if (!xField) {\n return {\n xField,\n openField,\n closeField,\n highField,\n lowField,\n configError: 'Candlestick chart requires an X-Axis (time or category dimension)',\n }\n }\n\n if (rangeMode === 'range' && (!highField || !lowField)) {\n return {\n xField,\n openField,\n closeField,\n highField,\n lowField,\n configError: 'Range mode requires at least 2 measures (high, low) in Y-Axis',\n }\n }\n\n if (rangeMode === 'ohlc' && (!openField || !closeField)) {\n return {\n xField,\n openField,\n closeField,\n highField,\n lowField,\n configError: 'OHLC mode requires at least 2 measures (open, close) in Y-Axis',\n }\n }\n\n return { xField, openField, closeField, highField, lowField, configError: null }\n }, [chartConfig, rangeMode])\n\n const candles: CandleData[] = useMemo(() => {\n if (configError || !data || data.length === 0) return []\n const rows = (data as Record<string, unknown>[]).slice(0, MAX_CANDLES)\n const result: CandleData[] = []\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i]\n const label = String(row[xField!] ?? `Bar ${i + 1}`)\n const rawOpen = parseNum(row[openField])\n const rawClose = parseNum(row[closeField])\n if (rawOpen === null || rawClose === null) continue\n\n let open = rawOpen\n let close = rawClose\n const high = highField ? (parseNum(row[highField]) ?? Math.max(open, close)) : Math.max(open, close)\n const low = lowField ? (parseNum(row[lowField]) ?? Math.min(open, close)) : Math.min(open, close)\n\n if (rangeMode === 'range') {\n open = low\n close = high\n }\n\n result.push({\n label,\n open,\n close,\n high: Math.max(open, close, high),\n low: Math.min(open, close, low),\n isBullish: close >= open,\n originalIndex: i,\n })\n }\n return result\n }, [data, xField, openField, closeField, highField, lowField, rangeMode, configError])\n\n try {\n if (!data || data.length === 0) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-text-muted\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.noData')}</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">{t('chart.runtime.noDataHint.candlestick')}</div>\n </div>\n </div>\n )\n }\n\n if (configError) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-warning\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.configError')}</div>\n <div className=\"dc:text-xs\">{configError}</div>\n </div>\n </div>\n )\n }\n const margin = { top: 20, right: 20, bottom: 60, left: 70 }\n const containerWidth = dimensions.width || 600\n const containerHeight =\n typeof height === 'number' ? height : dimensions.height || 400\n const innerWidth = Math.max(containerWidth - margin.left - margin.right, 50)\n const innerHeight = Math.max(\n (typeof containerHeight === 'number' ? containerHeight : parseInt(String(containerHeight)) || 400) -\n margin.top -\n margin.bottom,\n 50\n )\n\n const allValues = candles.flatMap((c) => [c.low, c.high])\n const rawMin = Math.min(...allValues)\n const rawMax = Math.max(...allValues)\n const pad = (rawMax - rawMin) * 0.05 || 1\n const domainMin = rawMin - pad\n const domainMax = rawMax + pad\n\n const yScale = (v: number) =>\n innerHeight - ((v - domainMin) / (domainMax - domainMin)) * innerHeight\n\n const candleSpacing = innerWidth / candles.length\n const candleWidth = Math.min(candleSpacing * 0.7, 20)\n\n const isTruncated = (data as unknown[]).length > MAX_CANDLES\n\n return (\n <div ref={containerRef} className=\"dc:relative dc:w-full\" style={{ height }}>\n <svg\n width=\"100%\"\n height={isTruncated ? 'calc(100% - 20px)' : '100%'}\n viewBox={`0 0 ${containerWidth} ${typeof containerHeight === 'number' ? containerHeight : 400}`}\n data-testid=\"candlestick-svg\"\n >\n <g transform={`translate(${margin.left}, ${margin.top})`}>\n <YAxisTicks\n domainMin={domainMin}\n domainMax={domainMax}\n innerHeight={innerHeight}\n tickCount={5}\n format={yAxisFormat ? (v) => formatAxisValue(v, yAxisFormat) : undefined}\n />\n\n {candles.map((candle, i) => {\n const cx = candleSpacing * i + candleSpacing / 2\n return (\n <g\n key={candle.label + i}\n onClick={(event: React.MouseEvent) => {\n if (onDataPointClick && drillEnabled) {\n onDataPointClick({\n dataPoint: { ...candle },\n clickedField: xField ?? '',\n xValue: candle.label,\n position: { x: event.clientX, y: event.clientY },\n nativeEvent: event,\n })\n }\n }}\n cursor={drillEnabled ? 'pointer' : undefined}\n >\n <title>{`${candle.label}: O=${candle.open} H=${candle.high} L=${candle.low} C=${candle.close}`}</title>\n <Candle\n x={cx}\n candleWidth={candleWidth}\n openY={yScale(candle.open)}\n closeY={yScale(candle.close)}\n highY={yScale(candle.high)}\n lowY={yScale(candle.low)}\n isBullish={candle.isBullish}\n bullColor={bullColor}\n bearColor={bearColor}\n showWicks={showWicks}\n label={candle.label}\n />\n <text\n x={cx}\n y={innerHeight + 20}\n textAnchor=\"middle\"\n fontSize={10}\n fill=\"currentColor\"\n className=\"text-dc-text-secondary\"\n data-testid={`x-label-${candle.label}`}\n >\n {candle.label}\n </text>\n </g>\n )\n })}\n </g>\n </svg>\n {isTruncated && (\n <div className=\"dc:text-xs text-dc-warning dc:text-center dc:mt-1\">\n {t('chart.runtime.candlestick.truncated', {\n max: MAX_CANDLES,\n total: (data as unknown[]).length\n })}\n </div>\n )}\n </div>\n )\n } catch (error) {\n return (\n <div className=\"dc:flex dc:flex-col dc:items-center dc:justify-center dc:w-full text-dc-error dc:p-4\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.chartError', { chartType: 'Candlestick Chart' })}</div>\n <div className=\"dc:text-xs dc:mb-2\">{error instanceof Error ? error.message : t('chart.runtime.unknownError')}</div>\n <div className=\"dc:text-xs text-dc-text-muted\">{t('chart.runtime.checkConfig')}</div>\n </div>\n </div>\n )\n }\n})\n\nexport default CandlestickChart\n"],"mappings":";;;;;iDAKM,IAAqB,WACrB,IAAqB,WACrB,IAAa,WACb,IAAc;AAYpB,SAAS,EAAS,GAA2B;CAC3C,IAAI,KAAyB,MAAM,OAAO;CAC1C,IAAM,IAAI,OAAO,KAAM,WAAW,IAAI,WAAW,OAAO,CAAC,CAAC;CAC1D,OAAO,MAAM,CAAC,IAAI,OAAO;AAC3B;AAEA,SAAS,EAAO,EACd,MACA,gBACA,UACA,WACA,UACA,SACA,cACA,cACA,cACA,cACA,YAaC;CACD,IAAM,IAAO,IAAY,IAAY,GAC/B,IAAU,KAAK,IAAI,GAAO,CAAM,GAChC,IAAa,KAAK,IAAI,GAAO,CAAM,GACnC,IAAa,KAAK,IAAI,IAAa,GAAS,CAAC,GAC7C,IAAY,IAAc;CAEhC,OACE,kBAAC,KAAD;EAAG,eAAa,UAAU;YAA1B,CACE,kBAAC,QAAD;GACE,GAAG,IAAI;GACP,GAAG;GACH,OAAO;GACP,QAAQ;GACF;GACN,eAAa,eAAe;GAC5B,gBAAc;EACf,CAAA,GACA,KACC,kBAAA,GAAA,EAAA,UAAA,CACE,kBAAC,QAAD;GACE,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,QAAQ;GACR,aAAa;GACb,eAAa,aAAa;EAC3B,CAAA,GACD,kBAAC,QAAD;GACE,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,IAAI;GACJ,QAAQ;GACR,aAAa;GACb,eAAa,YAAY;EAC1B,CAAA,CACD,EAAA,CAAA,CAEH;;AAEP;AAEA,SAAS,EAAW,EAClB,cACA,cACA,gBACA,cACA,aAOC;CACD,IAAM,IAAQ,QAAc;EAC1B,IAAM,KAAQ,IAAY,MAAc,IAAY;EACpD,OAAO,MAAM,KAAK,EAAE,QAAQ,EAAU,IAAI,GAAG,MAAM,IAAY,IAAI,CAAI;CACzE,GAAG;EAAC;EAAW;EAAW;CAAS,CAAC,GAE9B,KAAU,MAAc,KAAgB,IAAI,MAAc,IAAY,KAAc;CAE1F,OACE,kBAAC,KAAD;EAAG,eAAY;YAAf,CACE,kBAAC,QAAD;GAAM,IAAI;GAAG,IAAI;GAAa,QAAO;GAAe,aAAa;EAAI,CAAA,GACpE,EAAM,KAAK,GAAM,MAChB,kBAAC,KAAD;GAAW,WAAW,gBAAgB,EAAO,CAAI,EAAE;aAAnD;IACE,kBAAC,QAAD;KAAM,IAAI;KAAG,IAAI;KAAI,QAAO;KAAe,aAAa;IAAI,CAAA;IAC5D,kBAAC,QAAD;KACE,GAAG;KACH,YAAW;KACX,kBAAiB;KACjB,UAAU;KACV,MAAK;KACL,WAAU;eAET,IAAS,EAAO,CAAI,IAAI,EAAK,eAAe;IACzC,CAAA;IACN,kBAAC,QAAD;KAAM,IAAI;KAAG,IAAG;KAAO,QAAO;KAAe,eAAe;KAAK,aAAa;IAAI,CAAA;GACjF;KAbK,CAaL,CACJ,CACA;;AAEP;AAEA,IAAM,IAAmB,EAAM,KAAK,SAA0B,EAC5D,SACA,gBACA,mBAAgB,CAAC,GACjB,YAAS,QACT,qBACA,mBACa;CACb,IAAM,EAAE,SAAM,EAAe,GACvB,IAAe,EAAuB,IAAI,GAC1C,CAAC,GAAY,KAAiB,EAAS;EAAE,OAAO;EAAG,QAAQ;CAAE,CAAC;CAEpE,QAAsB;EACpB,IAAM,IAAK,EAAa;EACxB,IAAI,CAAC,GAAI;EACT,IAAM,IAAW,IAAI,gBAAgB,MAAY;GAC/C,KAAK,IAAM,KAAS,GAAS;IAC3B,IAAM,EAAE,UAAO,QAAQ,MAAM,EAAM;IACnC,AAAI,IAAQ,KAAK,IAAI,KAAG,EAAc;KAAE;KAAO,QAAQ;IAAE,CAAC;GAC5D;EACF,CAAC;EACD,EAAS,QAAQ,CAAE;EACnB,IAAM,IAAO,EAAG,sBAAsB;EAEtC,OADI,EAAK,QAAQ,KAAK,EAAK,SAAS,KAAG,EAAc;GAAE,OAAO,EAAK;GAAO,QAAQ,EAAK;EAAO,CAAC,SAClF,EAAS,WAAW;CACnC,GAAG,CAAC,CAAC;CAEL,IAAM,IAAY,GAAe,aAAa,GACxC,IAAY,GAAe,aAAa,GACxC,IAAY,GAAe,aAAa,IACxC,IAAY,GAAe,aAAa,QACxC,IAAc,GAAe,iBAE7B,EAAE,WAAQ,cAAW,eAAY,cAAW,aAAU,mBAAgB,QAAc;EACxF,IAAM,IAAS,MAAM,QAAQ,GAAa,KAAK,IAC3C,EAAY,MAAM,KAClB,GAAa,SAAS,GAAa,GAEjC,IAAwB,MAAM,QAAQ,GAAa,KAAK,IAC1D,EAAY,QACZ,CAAC,GAEC,IAAY,EAAY,MAAM,IAC9B,KAAc,MAAc,UAAU,EAAY,KAAK,EAAY,OAAO,IAC1E,KAAa,MAAc,UAAU,EAAY,KAAK,EAAY,OAAO,IACzE,KAAY,MAAc,UAAU,EAAY,KAAK,EAAY,OAAO;EAmC9E,OAjCK,IAWD,MAAc,YAAY,CAAC,KAAa,CAAC,KACpC;GACL;GACA;GACA;GACA;GACA;GACA,aAAa;EACf,IAGE,MAAc,WAAW,CAAC,KAAa,CAAC,KACnC;GACL;GACA;GACA;GACA;GACA;GACA,aAAa;EACf,IAGK;GAAE;GAAQ;GAAW;GAAY;GAAW;GAAU,aAAa;EAAK,IAhCtE;GACL;GACA;GACA;GACA;GACA;GACA,aAAa;EACf;CA0BJ,GAAG,CAAC,GAAa,CAAS,CAAC,GAErB,IAAwB,QAAc;EAC1C,IAAI,KAAe,CAAC,KAAQ,EAAK,WAAW,GAAG,OAAO,CAAC;EACvD,IAAM,IAAQ,EAAmC,MAAM,GAAG,CAAW,GAC/D,IAAuB,CAAC;EAC9B,KAAK,IAAI,IAAI,GAAG,IAAI,EAAK,QAAQ,KAAK;GACpC,IAAM,IAAM,EAAK,IACX,IAAQ,OAAO,EAAI,MAAY,OAAO,IAAI,GAAG,GAC7C,IAAU,EAAS,EAAI,EAAU,GACjC,IAAW,EAAS,EAAI,EAAW;GACzC,IAAI,MAAY,QAAQ,MAAa,MAAM;GAE3C,IAAI,IAAO,GACP,IAAQ,GACN,IAAO,IAAa,EAAS,EAAI,EAAU,KAAK,KAAK,IAAI,GAAM,CAAK,IAAK,KAAK,IAAI,GAAM,CAAK,GAC7F,IAAM,IAAY,EAAS,EAAI,EAAS,KAAK,KAAK,IAAI,GAAM,CAAK,IAAK,KAAK,IAAI,GAAM,CAAK;GAOhG,AALI,MAAc,YAChB,IAAO,GACP,IAAQ,IAGV,EAAO,KAAK;IACV;IACA;IACA;IACA,MAAM,KAAK,IAAI,GAAM,GAAO,CAAI;IAChC,KAAK,KAAK,IAAI,GAAM,GAAO,CAAG;IAC9B,WAAW,KAAS;IACpB,eAAe;GACjB,CAAC;EACH;EACA,OAAO;CACT,GAAG;EAAC;EAAM;EAAQ;EAAW;EAAY;EAAW;EAAU;EAAW;CAAW,CAAC;CAErF,IAAI;EACF,IAAI,CAAC,KAAQ,EAAK,WAAW,GAC3B,OACE,kBAAC,OAAD;GAAK,WAAU;GAAyE,OAAO,EAAE,UAAO;aACtG,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAuC,EAAE,sBAAsB;IAAO,CAAA,GACrF,kBAAC,OAAD;KAAK,WAAU;eAAqC,EAAE,sCAAsC;IAAO,CAAA,CAChG;;EACF,CAAA;EAIT,IAAI,GACF,OACE,kBAAC,OAAD;GAAK,WAAU;GAAsE,OAAO,EAAE,UAAO;aACnG,kBAAC,OAAD;IAAK,WAAU;cAAf,CACE,kBAAC,OAAD;KAAK,WAAU;eAAuC,EAAE,2BAA2B;IAAO,CAAA,GAC1F,kBAAC,OAAD;KAAK,WAAU;eAAc;IAAiB,CAAA,CAC3C;;EACF,CAAA;EAGT,IAAM,IAAS;GAAE,KAAK;GAAI,OAAO;GAAI,QAAQ;GAAI,MAAM;EAAG,GACpD,IAAiB,EAAW,SAAS,KACrC,IACJ,OAAO,KAAW,WAAW,IAAS,EAAW,UAAU,KACvD,IAAa,KAAK,IAAI,IAAiB,EAAO,OAAO,EAAO,OAAO,EAAE,GACrE,IAAc,KAAK,KACtB,OAAO,KAAoB,WAAW,IAAkB,SAAS,OAAO,CAAe,CAAC,KAAK,OAC5F,EAAO,MACP,EAAO,QACT,EACF,GAEM,IAAY,EAAQ,SAAS,MAAM,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,GAClD,IAAS,KAAK,IAAI,GAAG,CAAS,GAC9B,IAAS,KAAK,IAAI,GAAG,CAAS,GAC9B,KAAO,IAAS,KAAU,OAAQ,GAClC,IAAY,IAAS,GACrB,IAAY,IAAS,GAErB,KAAU,MACd,KAAgB,IAAI,MAAc,IAAY,KAAc,GAExD,IAAgB,IAAa,EAAQ,QACrC,IAAc,KAAK,IAAI,IAAgB,IAAK,EAAE,GAE9C,IAAe,EAAmB,SAAS;EAEjD,OACE,kBAAC,OAAD;GAAK,KAAK;GAAc,WAAU;GAAwB,OAAO,EAAE,UAAO;aAA1E,CACE,kBAAC,OAAD;IACE,OAAM;IACN,QAAQ,IAAc,sBAAsB;IAC5C,SAAS,OAAO,EAAe,GAAG,OAAO,KAAoB,WAAW,IAAkB;IAC1F,eAAY;cAEZ,kBAAC,KAAD;KAAG,WAAW,aAAa,EAAO,KAAK,IAAI,EAAO,IAAI;eAAtD,CACE,kBAAC,GAAD;MACa;MACA;MACE;MACb,WAAW;MACX,QAAQ,KAAe,MAAM,EAAgB,GAAG,CAAW,IAAI,KAAA;KAChE,CAAA,GAEA,EAAQ,KAAK,GAAQ,MAAM;MAC1B,IAAM,IAAK,IAAgB,IAAI,IAAgB;MAC/C,OACE,kBAAC,KAAD;OAEE,UAAU,MAA4B;QACpC,AAAI,KAAoB,KACtB,EAAiB;SACf,WAAW,EAAE,GAAG,EAAO;SACvB,cAAc,KAAU;SACxB,QAAQ,EAAO;SACf,UAAU;UAAE,GAAG,EAAM;UAAS,GAAG,EAAM;SAAQ;SAC/C,aAAa;QACf,CAAC;OAEL;OACA,QAAQ,IAAe,YAAY,KAAA;iBAbrC;QAeE,kBAAC,SAAD,EAAA,UAAQ,GAAG,EAAO,MAAM,MAAM,EAAO,KAAK,KAAK,EAAO,KAAK,KAAK,EAAO,IAAI,KAAK,EAAO,QAAe,CAAA;QACtG,kBAAC,GAAD;SACE,GAAG;SACU;SACb,OAAO,EAAO,EAAO,IAAI;SACzB,QAAQ,EAAO,EAAO,KAAK;SAC3B,OAAO,EAAO,EAAO,IAAI;SACzB,MAAM,EAAO,EAAO,GAAG;SACvB,WAAW,EAAO;SACP;SACA;SACA;SACX,OAAO,EAAO;QACf,CAAA;QACD,kBAAC,QAAD;SACE,GAAG;SACH,GAAG,IAAc;SACjB,YAAW;SACX,UAAU;SACV,MAAK;SACL,WAAU;SACV,eAAa,WAAW,EAAO;mBAE9B,EAAO;QACJ,CAAA;OACL;SAvCI,EAAO,QAAQ,CAuCnB;KAEP,CAAC,CACA;;GACA,CAAA,GACJ,KACC,kBAAC,OAAD;IAAK,WAAU;cACZ,EAAE,uCAAuC;KACxC,KAAK;KACL,OAAQ,EAAmB;IAC7B,CAAC;GACE,CAAA,CAEJ;;CAET,SAAS,GAAO;EACd,OACE,kBAAC,OAAD;GAAK,WAAU;GAAuF,OAAO,EAAE,UAAO;aACpH,kBAAC,OAAD;IAAK,WAAU;cAAf;KACE,kBAAC,OAAD;MAAK,WAAU;gBAAuC,EAAE,4BAA4B,EAAE,WAAW,oBAAoB,CAAC;KAAO,CAAA;KAC7H,kBAAC,OAAD;MAAK,WAAU;gBAAsB,aAAiB,QAAQ,EAAM,UAAU,EAAE,4BAA4B;KAAO,CAAA;KACnH,kBAAC,OAAD;MAAK,WAAU;gBAAiC,EAAE,2BAA2B;KAAO,CAAA;IACjF;;EACF,CAAA;CAET;AACF,CAAC"}
|
|
1
|
+
{"version":3,"file":"chart-candlestick-Dx8ZCMzl.js","names":[],"sources":["../../../src/client/components/charts/CandlestickChart.tsx"],"sourcesContent":["import React, { useLayoutEffect, useMemo, useRef, useState } from 'react'\nimport { useTranslation } from '../../hooks/useTranslation.js'\nimport { formatAxisValue } from '../../utils/chartUtils.js'\nimport type { ChartProps } from '../../types.js'\n\nconst BULL_COLOR_DEFAULT = '#22c55e'\nconst BEAR_COLOR_DEFAULT = '#ef4444'\nconst WICK_COLOR = '#94a3b8'\nconst MAX_CANDLES = 200\n\ninterface CandleData {\n label: string\n open: number\n close: number\n high: number\n low: number\n isBullish: boolean\n originalIndex: number\n}\n\nfunction parseNum(v: unknown): number | null {\n if (v === undefined || v === null) return null\n const n = typeof v === 'number' ? v : parseFloat(String(v))\n return isNaN(n) ? null : n\n}\n\nfunction Candle({\n x,\n candleWidth,\n openY,\n closeY,\n highY,\n lowY,\n isBullish,\n bullColor,\n bearColor,\n showWicks,\n label,\n}: {\n x: number\n candleWidth: number\n openY: number\n closeY: number\n highY: number\n lowY: number\n isBullish: boolean\n bullColor: string\n bearColor: string\n showWicks: boolean\n label: string\n}) {\n const fill = isBullish ? bullColor : bearColor\n const bodyTop = Math.min(openY, closeY)\n const bodyBottom = Math.max(openY, closeY)\n const bodyHeight = Math.max(bodyBottom - bodyTop, 1)\n const halfWidth = candleWidth / 2\n\n return (\n <g data-testid={`candle-${label}`}>\n <rect\n x={x - halfWidth}\n y={bodyTop}\n width={candleWidth}\n height={bodyHeight}\n fill={fill}\n data-testid={`candle-body-${label}`}\n data-bullish={isBullish}\n />\n {showWicks && (\n <>\n <line\n x1={x}\n y1={highY}\n x2={x}\n y2={bodyTop}\n stroke={WICK_COLOR}\n strokeWidth={1}\n data-testid={`wick-high-${label}`}\n />\n <line\n x1={x}\n y1={bodyBottom}\n x2={x}\n y2={lowY}\n stroke={WICK_COLOR}\n strokeWidth={1}\n data-testid={`wick-low-${label}`}\n />\n </>\n )}\n </g>\n )\n}\n\nfunction YAxisTicks({\n domainMin,\n domainMax,\n innerHeight,\n tickCount,\n format,\n}: {\n domainMin: number\n domainMax: number\n innerHeight: number\n tickCount: number\n format?: (v: number) => string\n}) {\n const ticks = useMemo(() => {\n const step = (domainMax - domainMin) / (tickCount - 1)\n return Array.from({ length: tickCount }, (_, i) => domainMin + i * step)\n }, [domainMin, domainMax, tickCount])\n\n const yScale = (v: number) => innerHeight - ((v - domainMin) / (domainMax - domainMin)) * innerHeight\n\n return (\n <g data-testid=\"y-axis\">\n <line y1={0} y2={innerHeight} stroke=\"currentColor\" strokeWidth={1} />\n {ticks.map((tick, i) => (\n <g key={i} transform={`translate(0, ${yScale(tick)})`}>\n <line x1={0} x2={-6} stroke=\"currentColor\" strokeWidth={1} />\n <text\n x={-10}\n textAnchor=\"end\"\n dominantBaseline=\"middle\"\n fontSize={11}\n fill=\"currentColor\"\n className=\"text-dc-text-secondary\"\n >\n {format ? format(tick) : tick.toLocaleString()}\n </text>\n <line x1={0} x2=\"100%\" stroke=\"currentColor\" strokeOpacity={0.1} strokeWidth={1} />\n </g>\n ))}\n </g>\n )\n}\n\nconst CandlestickChart = React.memo(function CandlestickChart({\n data,\n chartConfig,\n displayConfig = {},\n height = '100%',\n onDataPointClick,\n drillEnabled,\n}: ChartProps) {\n const { t } = useTranslation()\n const containerRef = useRef<HTMLDivElement>(null)\n const [dimensions, setDimensions] = useState({ width: 0, height: 0 })\n\n useLayoutEffect(() => {\n const el = containerRef.current\n if (!el) return\n const observer = new ResizeObserver((entries) => {\n for (const entry of entries) {\n const { width, height: h } = entry.contentRect\n if (width > 0 && h > 0) setDimensions({ width, height: h })\n }\n })\n observer.observe(el)\n const rect = el.getBoundingClientRect()\n if (rect.width > 0 && rect.height > 0) setDimensions({ width: rect.width, height: rect.height })\n return () => observer.disconnect()\n }, [])\n\n const bullColor = displayConfig?.bullColor ?? BULL_COLOR_DEFAULT\n const bearColor = displayConfig?.bearColor ?? BEAR_COLOR_DEFAULT\n const showWicks = displayConfig?.showWicks ?? true\n const rangeMode = displayConfig?.rangeMode ?? 'ohlc'\n const yAxisFormat = displayConfig?.leftYAxisFormat\n\n const { xField, openField, closeField, highField, lowField, configError } = useMemo(() => {\n const xField = Array.isArray(chartConfig?.xAxis)\n ? chartConfig.xAxis[0]\n : chartConfig?.xAxis ?? chartConfig?.x\n\n const yAxisFields: string[] = Array.isArray(chartConfig?.yAxis)\n ? chartConfig.yAxis\n : []\n\n const openField = yAxisFields[0] ?? ''\n const closeField = (rangeMode === 'range' ? yAxisFields[0] : yAxisFields[1]) ?? ''\n const highField = (rangeMode === 'range' ? yAxisFields[0] : yAxisFields[2]) ?? ''\n const lowField = (rangeMode === 'range' ? yAxisFields[1] : yAxisFields[3]) ?? ''\n\n if (!xField) {\n return {\n xField,\n openField,\n closeField,\n highField,\n lowField,\n configError: 'Candlestick chart requires an X-Axis (time or category dimension)',\n }\n }\n\n if (rangeMode === 'range' && (!highField || !lowField)) {\n return {\n xField,\n openField,\n closeField,\n highField,\n lowField,\n configError: 'Range mode requires at least 2 measures (high, low) in Y-Axis',\n }\n }\n\n if (rangeMode === 'ohlc' && (!openField || !closeField)) {\n return {\n xField,\n openField,\n closeField,\n highField,\n lowField,\n configError: 'OHLC mode requires at least 2 measures (open, close) in Y-Axis',\n }\n }\n\n return { xField, openField, closeField, highField, lowField, configError: null }\n }, [chartConfig, rangeMode])\n\n const candles: CandleData[] = useMemo(() => {\n if (configError || !data || data.length === 0) return []\n const rows = (data as Record<string, unknown>[]).slice(0, MAX_CANDLES)\n const result: CandleData[] = []\n for (let i = 0; i < rows.length; i++) {\n const row = rows[i]\n const label = String(row[xField!] ?? `Bar ${i + 1}`)\n const rawOpen = parseNum(row[openField])\n const rawClose = parseNum(row[closeField])\n if (rawOpen === null || rawClose === null) continue\n\n let open = rawOpen\n let close = rawClose\n const high = highField ? (parseNum(row[highField]) ?? Math.max(open, close)) : Math.max(open, close)\n const low = lowField ? (parseNum(row[lowField]) ?? Math.min(open, close)) : Math.min(open, close)\n\n if (rangeMode === 'range') {\n open = low\n close = high\n }\n\n result.push({\n label,\n open,\n close,\n high: Math.max(open, close, high),\n low: Math.min(open, close, low),\n isBullish: close >= open,\n originalIndex: i,\n })\n }\n return result\n }, [data, xField, openField, closeField, highField, lowField, rangeMode, configError])\n\n try {\n if (!data || data.length === 0) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-text-muted\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.noData')}</div>\n <div className=\"dc:text-xs text-dc-text-secondary\">{t('chart.runtime.noDataHint.candlestick')}</div>\n </div>\n </div>\n )\n }\n\n if (configError) {\n return (\n <div className=\"dc:flex dc:items-center dc:justify-center dc:w-full text-dc-warning\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.configError')}</div>\n <div className=\"dc:text-xs\">{configError}</div>\n </div>\n </div>\n )\n }\n const margin = { top: 20, right: 20, bottom: 60, left: 70 }\n const containerWidth = dimensions.width || 600\n const containerHeight =\n typeof height === 'number' ? height : dimensions.height || 400\n const innerWidth = Math.max(containerWidth - margin.left - margin.right, 50)\n const innerHeight = Math.max(\n (typeof containerHeight === 'number' ? containerHeight : parseInt(String(containerHeight)) || 400) -\n margin.top -\n margin.bottom,\n 50\n )\n\n const allValues = candles.flatMap((c) => [c.low, c.high])\n const rawMin = Math.min(...allValues)\n const rawMax = Math.max(...allValues)\n const pad = (rawMax - rawMin) * 0.05 || 1\n const domainMin = rawMin - pad\n const domainMax = rawMax + pad\n\n const yScale = (v: number) =>\n innerHeight - ((v - domainMin) / (domainMax - domainMin)) * innerHeight\n\n const candleSpacing = innerWidth / candles.length\n const candleWidth = Math.min(candleSpacing * 0.7, 20)\n\n const isTruncated = (data as unknown[]).length > MAX_CANDLES\n\n return (\n <div ref={containerRef} className=\"dc:relative dc:w-full\" style={{ height }}>\n <svg\n width=\"100%\"\n height={isTruncated ? 'calc(100% - 20px)' : '100%'}\n viewBox={`0 0 ${containerWidth} ${typeof containerHeight === 'number' ? containerHeight : 400}`}\n data-testid=\"candlestick-svg\"\n >\n <g transform={`translate(${margin.left}, ${margin.top})`}>\n <YAxisTicks\n domainMin={domainMin}\n domainMax={domainMax}\n innerHeight={innerHeight}\n tickCount={5}\n format={yAxisFormat ? (v) => formatAxisValue(v, yAxisFormat) : undefined}\n />\n\n {candles.map((candle, i) => {\n const cx = candleSpacing * i + candleSpacing / 2\n return (\n <g\n key={candle.label + i}\n onClick={(event: React.MouseEvent) => {\n if (onDataPointClick && drillEnabled) {\n onDataPointClick({\n dataPoint: { ...candle },\n clickedField: xField ?? '',\n xValue: candle.label,\n position: { x: event.clientX, y: event.clientY },\n nativeEvent: event,\n })\n }\n }}\n cursor={drillEnabled ? 'pointer' : undefined}\n >\n <title>{`${candle.label}: O=${candle.open} H=${candle.high} L=${candle.low} C=${candle.close}`}</title>\n <Candle\n x={cx}\n candleWidth={candleWidth}\n openY={yScale(candle.open)}\n closeY={yScale(candle.close)}\n highY={yScale(candle.high)}\n lowY={yScale(candle.low)}\n isBullish={candle.isBullish}\n bullColor={bullColor}\n bearColor={bearColor}\n showWicks={showWicks}\n label={candle.label}\n />\n <text\n x={cx}\n y={innerHeight + 20}\n textAnchor=\"middle\"\n fontSize={10}\n fill=\"currentColor\"\n className=\"text-dc-text-secondary\"\n data-testid={`x-label-${candle.label}`}\n >\n {candle.label}\n </text>\n </g>\n )\n })}\n </g>\n </svg>\n {isTruncated && (\n <div className=\"dc:text-xs text-dc-warning dc:text-center dc:mt-1\">\n {t('chart.runtime.candlestick.truncated', {\n max: MAX_CANDLES,\n total: (data as unknown[]).length\n })}\n </div>\n )}\n </div>\n )\n } catch (error) {\n return (\n <div className=\"dc:flex dc:flex-col dc:items-center dc:justify-center dc:w-full text-dc-error dc:p-4\" style={{ height }}>\n <div className=\"dc:text-center\">\n <div className=\"dc:text-sm dc:font-semibold dc:mb-1\">{t('chart.runtime.chartError', { chartType: 'Candlestick Chart' })}</div>\n <div className=\"dc:text-xs dc:mb-2\">{error instanceof Error ? error.message : t('chart.runtime.unknownError')}</div>\n <div className=\"dc:text-xs text-dc-text-muted\">{t('chart.runtime.checkConfig')}</div>\n </div>\n </div>\n )\n }\n})\n\nexport default CandlestickChart\n"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { i as e, n as t } from "./rolldown-runtime-CWhphoD1.js";
|
|
2
2
|
import { a as n, n as r, o as i } from "./chart-config-area-DxwIZ4Uf.js";
|
|
3
|
-
import { E as a, F as o, I as s, P as c, R as l, w as u, z as d } from "./chart-activity-grid-
|
|
3
|
+
import { E as a, F as o, I as s, P as c, R as l, w as u, z as d } from "./chart-activity-grid-DDqFVWoa.js";
|
|
4
4
|
import { n as f } from "./chart-config-bar-Cc8GY9aQ.js";
|
|
5
5
|
import { n as p } from "./chart-config-line-CBfM0Rds.js";
|
|
6
6
|
import { n as m } from "./chart-config-pie-ChfFz6DV.js";
|
|
@@ -543,7 +543,18 @@ function I(e) {
|
|
|
543
543
|
return JSON.stringify(e, (e, t) => Qe(t) ? Object.keys(t).sort().reduce((e, n) => (e[n] = t[n], e), {}) : t);
|
|
544
544
|
}
|
|
545
545
|
function L(e, t) {
|
|
546
|
-
|
|
546
|
+
if (e === t) return !0;
|
|
547
|
+
if (typeof e != typeof t) return !1;
|
|
548
|
+
if (e && t && typeof e == "object" && typeof t == "object") {
|
|
549
|
+
if (Array.isArray(e) && Array.isArray(t)) {
|
|
550
|
+
for (let n = 0; n < t.length; n++) if (!L(e[n], t[n])) return !1;
|
|
551
|
+
return !0;
|
|
552
|
+
}
|
|
553
|
+
let n = Object.keys(t);
|
|
554
|
+
for (let r of n) if (!L(e[r], t[r])) return !1;
|
|
555
|
+
return !0;
|
|
556
|
+
}
|
|
557
|
+
return !1;
|
|
547
558
|
}
|
|
548
559
|
var Je = Object.prototype.hasOwnProperty;
|
|
549
560
|
function Ye(e, t, n = 0) {
|
|
@@ -747,7 +758,7 @@ function ut(e) {
|
|
|
747
758
|
return Math.min(1e3 * 2 ** e, 3e4);
|
|
748
759
|
}
|
|
749
760
|
function dt(e) {
|
|
750
|
-
return (e ?? "online")
|
|
761
|
+
return (e ?? "online") !== "online" || V.isOnline();
|
|
751
762
|
}
|
|
752
763
|
var ft = class extends Error {
|
|
753
764
|
constructor(e) {
|
|
@@ -837,7 +848,7 @@ function ht(e) {
|
|
|
837
848
|
}, u = it(t.options, t.fetchOptions), d = async (e, r, i) => {
|
|
838
849
|
if (n) return Promise.reject(t.signal.reason);
|
|
839
850
|
if (r == null && e.pages.length) return Promise.resolve(e);
|
|
840
|
-
let a =
|
|
851
|
+
let a = (() => {
|
|
841
852
|
let e = {
|
|
842
853
|
client: t.client,
|
|
843
854
|
queryKey: t.queryKey,
|
|
@@ -846,10 +857,10 @@ function ht(e) {
|
|
|
846
857
|
meta: t.options.meta
|
|
847
858
|
};
|
|
848
859
|
return l(e), e;
|
|
849
|
-
})()), { maxPages:
|
|
860
|
+
})(), o = await u(a), { maxPages: s } = t.options, c = i ? rt : nt;
|
|
850
861
|
return {
|
|
851
|
-
pages:
|
|
852
|
-
pageParams:
|
|
862
|
+
pages: c(e.pages, o, s),
|
|
863
|
+
pageParams: c(e.pageParams, r, s)
|
|
853
864
|
};
|
|
854
865
|
};
|
|
855
866
|
if (i && a.length) {
|
|
@@ -956,7 +967,7 @@ var vt = class extends mt {
|
|
|
956
967
|
return this.state.dataUpdateCount + this.state.errorUpdateCount > 0;
|
|
957
968
|
}
|
|
958
969
|
isStatic() {
|
|
959
|
-
return this.getObserversCount() > 0
|
|
970
|
+
return this.getObserversCount() > 0 && this.observers.some((e) => P(e.options.staleTime, this) === "static");
|
|
960
971
|
}
|
|
961
972
|
isStale() {
|
|
962
973
|
return this.getObserversCount() > 0 ? this.observers.some((e) => e.getCurrentResult().isStale) : this.state.data === void 0 || this.state.isInvalidated;
|
|
@@ -1350,7 +1361,8 @@ var St = class extends j {
|
|
|
1350
1361
|
let t = b.data !== void 0, r = b.status === "error" && !t, i = (e) => {
|
|
1351
1362
|
r ? e.reject(b.error) : t && e.resolve(b.data);
|
|
1352
1363
|
}, a = () => {
|
|
1353
|
-
|
|
1364
|
+
let e = this.#o = b.promise = st();
|
|
1365
|
+
i(e);
|
|
1354
1366
|
}, o = this.#o;
|
|
1355
1367
|
switch (o.status) {
|
|
1356
1368
|
case "pending":
|
|
@@ -2342,7 +2354,7 @@ function ln(e, t, n, r, i) {
|
|
|
2342
2354
|
async function W() {
|
|
2343
2355
|
if (cn) return U;
|
|
2344
2356
|
try {
|
|
2345
|
-
return U = await import("./dist-
|
|
2357
|
+
return U = await import("./dist-BwQr11Fz.js"), cn = !0, U;
|
|
2346
2358
|
} catch {
|
|
2347
2359
|
return cn = !0, U = null, null;
|
|
2348
2360
|
}
|
|
@@ -2517,7 +2529,7 @@ function On(e, t) {
|
|
|
2517
2529
|
async function kn() {
|
|
2518
2530
|
if (vn) return _n;
|
|
2519
2531
|
try {
|
|
2520
|
-
return _n = await import("./exceljs.min-
|
|
2532
|
+
return _n = await import("./exceljs.min-Dey-qIFL.js").then((t) => /* @__PURE__ */ e(t.default, 1)), vn = !0, _n;
|
|
2521
2533
|
} catch {
|
|
2522
2534
|
return vn = !0, _n = null, null;
|
|
2523
2535
|
}
|
|
@@ -3500,7 +3512,7 @@ var Ci = (e, t, n) => {
|
|
|
3500
3512
|
let e = 0, n = t.id;
|
|
3501
3513
|
return typeof n == "string" && (n = n.replace(/-/g, "_")), c.dangerouslySetInnerHTML = { __html: pi(Cr(l.body, n ? () => n + "ID" + e++ : "iconifyReact")) }, ge("svg", c);
|
|
3502
3514
|
}
|
|
3503
|
-
let { body: d, width: f, height: p } = e, m = a === "mask" ||
|
|
3515
|
+
let { body: d, width: f, height: p } = e, m = a === "mask" || a !== "bg" && d.indexOf("currentColor") !== -1, h = ci(d, {
|
|
3504
3516
|
...u,
|
|
3505
3517
|
width: f + "",
|
|
3506
3518
|
height: p + ""
|
|
@@ -3577,10 +3589,13 @@ function wi(e) {
|
|
|
3577
3589
|
return;
|
|
3578
3590
|
}
|
|
3579
3591
|
let r = sr(n);
|
|
3580
|
-
l({
|
|
3592
|
+
if (l({
|
|
3581
3593
|
name: n,
|
|
3582
3594
|
data: r
|
|
3583
|
-
})
|
|
3595
|
+
})) if (r === void 0) {
|
|
3596
|
+
let e = ri([n], u);
|
|
3597
|
+
i({ callback: e });
|
|
3598
|
+
} else r && ((t = e.onLoad) == null || t.call(e, n));
|
|
3584
3599
|
}
|
|
3585
3600
|
S(() => (n(!0), c), []), S(() => {
|
|
3586
3601
|
t && u();
|
|
@@ -4833,7 +4848,8 @@ function Ao(e, t, n, r) {
|
|
|
4833
4848
|
t.dimensions.forEach((e, t) => {
|
|
4834
4849
|
f[e] = p[t] ?? "";
|
|
4835
4850
|
}), s > 1 && (f.__measure__ = r(e)), n.forEach((t) => {
|
|
4836
|
-
|
|
4851
|
+
let n = u.get(t);
|
|
4852
|
+
f[t] = n?.[e] ?? null;
|
|
4837
4853
|
});
|
|
4838
4854
|
let m = l === 0;
|
|
4839
4855
|
o.push({
|
|
@@ -5023,4 +5039,4 @@ function zo(e, t) {
|
|
|
5023
5039
|
//#endregion
|
|
5024
5040
|
export { St as $, Fn as A, Zt as B, Xa as C, Ga as D, Ka as E, pn as F, qt as G, Xt as H, fn as I, Ut as J, Ht as K, un as L, jn as M, dn as N, Ti as O, gn as P, At as Q, sn as R, $a as S, Ya as T, Gt as U, $t as V, Jt as W, Rt as X, Vt as Y, Ft as Z, to as _, Eo as a, at, qa as b, wo as c, A as ct, ro as d, Pe as dt, B as et, co as f, Me as ft, eo as g, io as h, To as i, Xe as it, An as j, Bn as k, $ as l, ke as lt, ao as m, je as mt, No as n, N as nt, jo as o, j as ot, oo as p, Ne as pt, Wt as q, Mo as r, Ye as rt, Co as s, Fe as st, Po as t, I as tt, Q as u, Ae as ut, Z as v, Za as w, Qa as x, Ja as y, rn as z };
|
|
5025
5041
|
|
|
5026
|
-
//# sourceMappingURL=chart-data-table-
|
|
5042
|
+
//# sourceMappingURL=chart-data-table-BP6DMdom.js.map
|