react-open-source-grid 1.6.7 → 1.7.2

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/lib/index.js CHANGED
@@ -5302,6 +5302,7 @@ var ContextMenu = ({
5302
5302
  onClose
5303
5303
  }) => {
5304
5304
  const menuRef = useRef6(null);
5305
+ const [openSubmenu, setOpenSubmenu] = React15.useState(null);
5305
5306
  useEffect6(() => {
5306
5307
  const handleClickOutside = (event) => {
5307
5308
  if (menuRef.current && !menuRef.current.contains(event.target)) {
@@ -5356,16 +5357,18 @@ var ContextMenu = ({
5356
5357
  }
5357
5358
  }, [x, y]);
5358
5359
  const handleItemClick = useCallback3((item) => {
5359
- if (item.disabled || item.type === "separator") {
5360
+ if (item.disabled) {
5361
+ return;
5362
+ }
5363
+ if (item.submenu) {
5364
+ setOpenSubmenu(openSubmenu === item.id ? null : item.id || null);
5360
5365
  return;
5361
5366
  }
5362
5367
  if (item.onClick) {
5363
5368
  item.onClick();
5364
5369
  }
5365
- if (!item.submenu) {
5366
- onClose();
5367
- }
5368
- }, [onClose]);
5370
+ onClose();
5371
+ }, [onClose, openSubmenu]);
5369
5372
  const renderMenuItem = (item, index) => {
5370
5373
  if (item.type === "separator") {
5371
5374
  return /* @__PURE__ */ React15.createElement(
@@ -5377,11 +5380,10 @@ var ContextMenu = ({
5377
5380
  }
5378
5381
  );
5379
5382
  }
5380
- return /* @__PURE__ */ React15.createElement(
5383
+ return /* @__PURE__ */ React15.createElement("div", { key: item.id || index, className: "context-menu-item-wrapper" }, /* @__PURE__ */ React15.createElement(
5381
5384
  "div",
5382
5385
  {
5383
- key: item.id || index,
5384
- className: `context-menu-item ${item.disabled ? "disabled" : ""} ${item.danger ? "danger" : ""}`,
5386
+ className: `context-menu-item ${item.disabled ? "disabled" : ""} ${item.danger ? "danger" : ""} ${item.submenu ? "has-submenu" : ""}`,
5385
5387
  onClick: () => handleItemClick(item),
5386
5388
  role: "menuitem",
5387
5389
  "aria-disabled": item.disabled,
@@ -5391,7 +5393,7 @@ var ContextMenu = ({
5391
5393
  /* @__PURE__ */ React15.createElement("span", { className: "context-menu-label" }, item.label),
5392
5394
  item.shortcut && /* @__PURE__ */ React15.createElement("span", { className: "context-menu-shortcut" }, item.shortcut),
5393
5395
  item.submenu && /* @__PURE__ */ React15.createElement("span", { className: "context-menu-arrow" }, "\u25B6")
5394
- );
5396
+ ), item.submenu && openSubmenu === item.id && /* @__PURE__ */ React15.createElement("div", { className: "context-menu-submenu" }, item.submenu.map((subItem, subIndex) => renderMenuItem(subItem, subIndex))));
5395
5397
  };
5396
5398
  return /* @__PURE__ */ React15.createElement(
5397
5399
  "div",
@@ -5559,16 +5561,20 @@ var useContextMenu = ({
5559
5561
  showExport: (config == null ? void 0 : config.showExport) !== false,
5560
5562
  showColumnOptions: (config == null ? void 0 : config.showColumnOptions) !== false,
5561
5563
  showFilterByValue: (config == null ? void 0 : config.showFilterByValue) !== false,
5564
+ showChartOptions: (config == null ? void 0 : config.showChartOptions) !== false,
5562
5565
  customItems: (config == null ? void 0 : config.customItems) || [],
5563
- onBeforeShow: config == null ? void 0 : config.onBeforeShow
5566
+ onBeforeShow: config == null ? void 0 : config.onBeforeShow,
5567
+ onCreateChart: config == null ? void 0 : config.onCreateChart
5564
5568
  }), [
5565
5569
  config == null ? void 0 : config.enabled,
5566
5570
  config == null ? void 0 : config.showCopy,
5567
5571
  config == null ? void 0 : config.showExport,
5568
5572
  config == null ? void 0 : config.showColumnOptions,
5569
5573
  config == null ? void 0 : config.showFilterByValue,
5574
+ config == null ? void 0 : config.showChartOptions,
5570
5575
  config == null ? void 0 : config.customItems,
5571
- config == null ? void 0 : config.onBeforeShow
5576
+ config == null ? void 0 : config.onBeforeShow,
5577
+ config == null ? void 0 : config.onCreateChart
5572
5578
  ]);
5573
5579
  const buildCellMenuItems = useCallback4((row, column) => {
5574
5580
  const items = [];
@@ -5654,6 +5660,58 @@ var useContextMenu = ({
5654
5660
  disabled: cellValue == null
5655
5661
  });
5656
5662
  }
5663
+ if (menuConfig.showChartOptions !== false && hasSelection) {
5664
+ if (items.length > 0) {
5665
+ items.push({ type: "separator" });
5666
+ }
5667
+ items.push({
5668
+ id: "create-chart",
5669
+ label: "Create Chart",
5670
+ icon: "\u{1F4CA}",
5671
+ submenu: [
5672
+ {
5673
+ id: "chart-line",
5674
+ label: "Line Chart",
5675
+ icon: "\u{1F4C8}",
5676
+ onClick: () => {
5677
+ if (menuConfig.onCreateChart) {
5678
+ menuConfig.onCreateChart("line", selectedRows, row, column);
5679
+ }
5680
+ }
5681
+ },
5682
+ {
5683
+ id: "chart-bar",
5684
+ label: "Bar Chart",
5685
+ icon: "\u{1F4CA}",
5686
+ onClick: () => {
5687
+ if (menuConfig.onCreateChart) {
5688
+ menuConfig.onCreateChart("bar", selectedRows, row, column);
5689
+ }
5690
+ }
5691
+ },
5692
+ {
5693
+ id: "chart-area",
5694
+ label: "Area Chart",
5695
+ icon: "\u{1F4C9}",
5696
+ onClick: () => {
5697
+ if (menuConfig.onCreateChart) {
5698
+ menuConfig.onCreateChart("area", selectedRows, row, column);
5699
+ }
5700
+ }
5701
+ },
5702
+ {
5703
+ id: "chart-pie",
5704
+ label: "Pie Chart",
5705
+ icon: "\u{1F967}",
5706
+ onClick: () => {
5707
+ if (menuConfig.onCreateChart) {
5708
+ menuConfig.onCreateChart("pie", selectedRows, row, column);
5709
+ }
5710
+ }
5711
+ }
5712
+ ]
5713
+ });
5714
+ }
5657
5715
  if (menuConfig.customItems.length > 0) {
5658
5716
  if (items.length > 0) {
5659
5717
  items.push({ type: "separator" });
@@ -13515,10 +13573,516 @@ function renderMarkdownPreview(markdown) {
13515
13573
  }
13516
13574
  return html;
13517
13575
  }
13576
+
13577
+ // src/charts/rangeToChart.ts
13578
+ function normalizeRange(range) {
13579
+ const startRow = Math.min(range.start.rowIndex, range.end.rowIndex);
13580
+ const endRow = Math.max(range.start.rowIndex, range.end.rowIndex);
13581
+ const startCol = Math.min(range.start.colIndex, range.end.colIndex);
13582
+ const endCol = Math.max(range.start.colIndex, range.end.colIndex);
13583
+ return { startRow, endRow, startCol, endCol };
13584
+ }
13585
+ function isNumeric(value) {
13586
+ if (value === null || value === void 0 || value === "") {
13587
+ return false;
13588
+ }
13589
+ const num = Number(value);
13590
+ return !isNaN(num) && isFinite(num);
13591
+ }
13592
+ function toNumber2(value) {
13593
+ if (isNumeric(value)) {
13594
+ return Number(value);
13595
+ }
13596
+ return 0;
13597
+ }
13598
+ function generateChartId() {
13599
+ return `chart-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
13600
+ }
13601
+ var DEFAULT_COLORS = [
13602
+ "#2563eb",
13603
+ // vibrant blue
13604
+ "#10b981",
13605
+ // emerald green
13606
+ "#f59e0b",
13607
+ // amber/orange
13608
+ "#ef4444",
13609
+ // bright red
13610
+ "#8b5cf6",
13611
+ // purple
13612
+ "#ec4899",
13613
+ // pink
13614
+ "#06b6d4",
13615
+ // cyan
13616
+ "#f97316",
13617
+ // orange
13618
+ "#14b8a6",
13619
+ // teal
13620
+ "#a855f7",
13621
+ // violet
13622
+ "#84cc16",
13623
+ // lime
13624
+ "#f43f5e"
13625
+ // rose
13626
+ ];
13627
+ function buildChartConfigFromRange(options) {
13628
+ const {
13629
+ range,
13630
+ rows,
13631
+ columns,
13632
+ chartType,
13633
+ useFirstColumnAsCategory = true,
13634
+ title,
13635
+ theme = "light"
13636
+ } = options;
13637
+ const normalized = normalizeRange(range);
13638
+ const { startRow, endRow, startCol, endCol } = normalized;
13639
+ if (startRow < 0 || endRow >= rows.length) {
13640
+ throw new Error("Invalid row range");
13641
+ }
13642
+ if (startCol < 0 || endCol >= columns.length) {
13643
+ throw new Error("Invalid column range");
13644
+ }
13645
+ const selectedRows = rows.slice(startRow, endRow + 1);
13646
+ const selectedColumns = columns.slice(startCol, endCol + 1);
13647
+ let categoryColumnIndex = 0;
13648
+ let dataColumnStartIndex = 0;
13649
+ if (useFirstColumnAsCategory && selectedColumns.length > 1) {
13650
+ categoryColumnIndex = 0;
13651
+ dataColumnStartIndex = 1;
13652
+ } else {
13653
+ categoryColumnIndex = -1;
13654
+ dataColumnStartIndex = 0;
13655
+ }
13656
+ const xLabels = [];
13657
+ if (categoryColumnIndex >= 0) {
13658
+ const categoryField = selectedColumns[categoryColumnIndex].field;
13659
+ selectedRows.forEach((row) => {
13660
+ const value = row[categoryField];
13661
+ xLabels.push(value !== null && value !== void 0 ? String(value) : "");
13662
+ });
13663
+ } else {
13664
+ for (let i = 0; i < selectedRows.length; i++) {
13665
+ xLabels.push(i + 1);
13666
+ }
13667
+ }
13668
+ const series = [];
13669
+ const dataColumns = selectedColumns.slice(dataColumnStartIndex);
13670
+ dataColumns.forEach((column, index) => {
13671
+ const seriesData = [];
13672
+ const field = column.field;
13673
+ let hasNumericData = false;
13674
+ selectedRows.forEach((row) => {
13675
+ const value = row[field];
13676
+ if (isNumeric(value)) {
13677
+ hasNumericData = true;
13678
+ seriesData.push(toNumber2(value));
13679
+ } else {
13680
+ seriesData.push(0);
13681
+ }
13682
+ });
13683
+ if (hasNumericData) {
13684
+ series.push({
13685
+ name: column.headerName || field,
13686
+ data: seriesData,
13687
+ color: DEFAULT_COLORS[index % DEFAULT_COLORS.length]
13688
+ });
13689
+ }
13690
+ });
13691
+ if (series.length === 0) {
13692
+ throw new Error("No numeric data found in the selected range");
13693
+ }
13694
+ if (chartType === "pie") {
13695
+ if (series.length === 1) {
13696
+ } else {
13697
+ const summedData = new Array(xLabels.length).fill(0);
13698
+ series.forEach((s) => {
13699
+ s.data.forEach((value, idx) => {
13700
+ summedData[idx] += value;
13701
+ });
13702
+ });
13703
+ series.length = 0;
13704
+ series.push({
13705
+ name: "Total",
13706
+ data: summedData,
13707
+ color: DEFAULT_COLORS[0]
13708
+ });
13709
+ }
13710
+ }
13711
+ return {
13712
+ id: generateChartId(),
13713
+ type: chartType,
13714
+ title: title || `${chartType.charAt(0).toUpperCase() + chartType.slice(1)} Chart`,
13715
+ xLabels,
13716
+ series,
13717
+ theme
13718
+ };
13719
+ }
13720
+ function updateChartType(config, newType) {
13721
+ var _a;
13722
+ return {
13723
+ ...config,
13724
+ type: newType,
13725
+ title: ((_a = config.title) == null ? void 0 : _a.replace(
13726
+ /^(Line|Bar|Area|Pie)/i,
13727
+ newType.charAt(0).toUpperCase() + newType.slice(1)
13728
+ )) || `${newType.charAt(0).toUpperCase() + newType.slice(1)} Chart`
13729
+ };
13730
+ }
13731
+ function updateChartTheme(config, newTheme) {
13732
+ return {
13733
+ ...config,
13734
+ theme: newTheme
13735
+ };
13736
+ }
13737
+
13738
+ // src/charts/QuickChart.tsx
13739
+ import React35, { useRef as useRef20 } from "react";
13740
+ import {
13741
+ LineChart,
13742
+ Line,
13743
+ BarChart,
13744
+ Bar,
13745
+ AreaChart,
13746
+ Area,
13747
+ PieChart,
13748
+ Pie,
13749
+ Cell,
13750
+ XAxis,
13751
+ YAxis,
13752
+ CartesianGrid,
13753
+ Tooltip as Tooltip2,
13754
+ Legend,
13755
+ ResponsiveContainer
13756
+ } from "recharts";
13757
+ import { toPng } from "html-to-image";
13758
+ var QuickChart = ({
13759
+ config,
13760
+ onClose,
13761
+ onChangeType,
13762
+ onToggleTheme,
13763
+ allowTypeSwitch = true,
13764
+ allowThemeSwitch = true,
13765
+ width = 600,
13766
+ height = 400
13767
+ }) => {
13768
+ const chartRef = useRef20(null);
13769
+ const theme = config.theme || "light";
13770
+ const transformedData = config.xLabels.map((label, index) => {
13771
+ const dataPoint = { name: label };
13772
+ config.series.forEach((series) => {
13773
+ dataPoint[series.name] = series.data[index] || 0;
13774
+ });
13775
+ return dataPoint;
13776
+ });
13777
+ const pieData = config.series.length > 0 ? config.xLabels.map((label, index) => ({
13778
+ name: label,
13779
+ value: config.series[0].data[index] || 0
13780
+ })) : [];
13781
+ const handleExportPNG = async () => {
13782
+ if (!chartRef.current) return;
13783
+ try {
13784
+ const dataUrl = await toPng(chartRef.current, {
13785
+ quality: 1,
13786
+ pixelRatio: 2,
13787
+ backgroundColor: theme === "dark" ? "#1a1a1a" : "#ffffff"
13788
+ });
13789
+ const link = document.createElement("a");
13790
+ link.download = `${config.title || "chart"}-${Date.now()}.png`;
13791
+ link.href = dataUrl;
13792
+ link.click();
13793
+ } catch (error) {
13794
+ console.error("Failed to export chart:", error);
13795
+ }
13796
+ };
13797
+ const chartTypeIcon = (type) => {
13798
+ switch (type) {
13799
+ case "line":
13800
+ return "\u{1F4C8}";
13801
+ case "bar":
13802
+ return "\u{1F4CA}";
13803
+ case "area":
13804
+ return "\u{1F4C9}";
13805
+ case "pie":
13806
+ return "\u{1F967}";
13807
+ default:
13808
+ return "\u{1F4CA}";
13809
+ }
13810
+ };
13811
+ const renderChart = () => {
13812
+ const commonProps = {
13813
+ data: config.type === "pie" ? pieData : transformedData,
13814
+ margin: { top: 5, right: 30, left: 20, bottom: 5 }
13815
+ };
13816
+ const axisProps = {
13817
+ stroke: theme === "dark" ? "#888" : "#666"
13818
+ };
13819
+ const gridProps = {
13820
+ strokeDasharray: "3 3",
13821
+ stroke: theme === "dark" ? "#333" : "#ddd"
13822
+ };
13823
+ switch (config.type) {
13824
+ case "line":
13825
+ return /* @__PURE__ */ React35.createElement(ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ React35.createElement(LineChart, { ...commonProps }, /* @__PURE__ */ React35.createElement(CartesianGrid, { ...gridProps }), /* @__PURE__ */ React35.createElement(XAxis, { dataKey: "name", ...axisProps }), /* @__PURE__ */ React35.createElement(YAxis, { ...axisProps }), /* @__PURE__ */ React35.createElement(
13826
+ Tooltip2,
13827
+ {
13828
+ contentStyle: {
13829
+ backgroundColor: theme === "dark" ? "#2a2a2a" : "#fff",
13830
+ border: `1px solid ${theme === "dark" ? "#444" : "#ccc"}`,
13831
+ color: theme === "dark" ? "#fff" : "#000"
13832
+ }
13833
+ }
13834
+ ), /* @__PURE__ */ React35.createElement(Legend, null), config.series.map((series) => /* @__PURE__ */ React35.createElement(
13835
+ Line,
13836
+ {
13837
+ key: series.name,
13838
+ type: "monotone",
13839
+ dataKey: series.name,
13840
+ stroke: series.color,
13841
+ strokeWidth: 2,
13842
+ dot: { r: 4 },
13843
+ activeDot: { r: 6 }
13844
+ }
13845
+ ))));
13846
+ case "bar":
13847
+ return /* @__PURE__ */ React35.createElement(ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ React35.createElement(BarChart, { ...commonProps }, /* @__PURE__ */ React35.createElement(CartesianGrid, { ...gridProps }), /* @__PURE__ */ React35.createElement(XAxis, { dataKey: "name", ...axisProps }), /* @__PURE__ */ React35.createElement(YAxis, { ...axisProps }), /* @__PURE__ */ React35.createElement(
13848
+ Tooltip2,
13849
+ {
13850
+ contentStyle: {
13851
+ backgroundColor: theme === "dark" ? "#2a2a2a" : "#fff",
13852
+ border: `1px solid ${theme === "dark" ? "#444" : "#ccc"}`,
13853
+ color: theme === "dark" ? "#fff" : "#000"
13854
+ }
13855
+ }
13856
+ ), /* @__PURE__ */ React35.createElement(Legend, null), config.series.map((series) => /* @__PURE__ */ React35.createElement(Bar, { key: series.name, dataKey: series.name, fill: series.color }))));
13857
+ case "area":
13858
+ return /* @__PURE__ */ React35.createElement(ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ React35.createElement(AreaChart, { ...commonProps }, /* @__PURE__ */ React35.createElement(CartesianGrid, { ...gridProps }), /* @__PURE__ */ React35.createElement(XAxis, { dataKey: "name", ...axisProps }), /* @__PURE__ */ React35.createElement(YAxis, { ...axisProps }), /* @__PURE__ */ React35.createElement(
13859
+ Tooltip2,
13860
+ {
13861
+ contentStyle: {
13862
+ backgroundColor: theme === "dark" ? "#2a2a2a" : "#fff",
13863
+ border: `1px solid ${theme === "dark" ? "#444" : "#ccc"}`,
13864
+ color: theme === "dark" ? "#fff" : "#000"
13865
+ }
13866
+ }
13867
+ ), /* @__PURE__ */ React35.createElement(Legend, null), config.series.map((series) => /* @__PURE__ */ React35.createElement(
13868
+ Area,
13869
+ {
13870
+ key: series.name,
13871
+ type: "monotone",
13872
+ dataKey: series.name,
13873
+ fill: series.color,
13874
+ stroke: series.color,
13875
+ fillOpacity: 0.6
13876
+ }
13877
+ ))));
13878
+ case "pie":
13879
+ return /* @__PURE__ */ React35.createElement(ResponsiveContainer, { width: "100%", height: "100%" }, /* @__PURE__ */ React35.createElement(PieChart, null, /* @__PURE__ */ React35.createElement(
13880
+ Pie,
13881
+ {
13882
+ data: pieData,
13883
+ cx: "50%",
13884
+ cy: "50%",
13885
+ labelLine: false,
13886
+ label: ({ name, percent }) => `${name}: ${(percent * 100).toFixed(0)}%`,
13887
+ outerRadius: Math.min(height, width) / 4,
13888
+ fill: "#8884d8",
13889
+ dataKey: "value"
13890
+ },
13891
+ pieData.map((_, index) => /* @__PURE__ */ React35.createElement(
13892
+ Cell,
13893
+ {
13894
+ key: `cell-${index}`,
13895
+ fill: DEFAULT_COLORS[index % DEFAULT_COLORS.length]
13896
+ }
13897
+ ))
13898
+ ), /* @__PURE__ */ React35.createElement(
13899
+ Tooltip2,
13900
+ {
13901
+ contentStyle: {
13902
+ backgroundColor: theme === "dark" ? "#2a2a2a" : "#fff",
13903
+ border: `1px solid ${theme === "dark" ? "#444" : "#ccc"}`,
13904
+ color: theme === "dark" ? "#fff" : "#000"
13905
+ }
13906
+ }
13907
+ ), /* @__PURE__ */ React35.createElement(Legend, null)));
13908
+ default:
13909
+ return /* @__PURE__ */ React35.createElement("div", null, "Unsupported chart type");
13910
+ }
13911
+ };
13912
+ return /* @__PURE__ */ React35.createElement(
13913
+ "div",
13914
+ {
13915
+ ref: chartRef,
13916
+ className: `quick-chart quick-chart--${theme}`,
13917
+ style: { width, height }
13918
+ },
13919
+ /* @__PURE__ */ React35.createElement("div", { className: "quick-chart__header" }, /* @__PURE__ */ React35.createElement("h3", { className: "quick-chart__title" }, config.title), /* @__PURE__ */ React35.createElement("div", { className: "quick-chart__controls" }, allowTypeSwitch && onChangeType && /* @__PURE__ */ React35.createElement("div", { className: "quick-chart__type-selector" }, ["line", "bar", "area", "pie"].map((type) => /* @__PURE__ */ React35.createElement(
13920
+ "button",
13921
+ {
13922
+ key: type,
13923
+ className: `quick-chart__type-btn ${config.type === type ? "quick-chart__type-btn--active" : ""}`,
13924
+ onClick: () => onChangeType(type),
13925
+ title: `${type.charAt(0).toUpperCase() + type.slice(1)} Chart`,
13926
+ "aria-label": `Switch to ${type} chart`
13927
+ },
13928
+ chartTypeIcon(type)
13929
+ ))), allowThemeSwitch && onToggleTheme && /* @__PURE__ */ React35.createElement(
13930
+ "button",
13931
+ {
13932
+ className: "quick-chart__btn",
13933
+ onClick: onToggleTheme,
13934
+ title: "Toggle theme",
13935
+ "aria-label": "Toggle theme"
13936
+ },
13937
+ theme === "dark" ? "\u2600\uFE0F" : "\u{1F319}"
13938
+ ), /* @__PURE__ */ React35.createElement(
13939
+ "button",
13940
+ {
13941
+ className: "quick-chart__btn",
13942
+ onClick: handleExportPNG,
13943
+ title: "Export as PNG",
13944
+ "aria-label": "Export chart as PNG"
13945
+ },
13946
+ "\u{1F4E5}"
13947
+ ), onClose && /* @__PURE__ */ React35.createElement(
13948
+ "button",
13949
+ {
13950
+ className: "quick-chart__btn quick-chart__close",
13951
+ onClick: onClose,
13952
+ title: "Close",
13953
+ "aria-label": "Close chart"
13954
+ },
13955
+ "\xD7"
13956
+ ))),
13957
+ /* @__PURE__ */ React35.createElement("div", { className: "quick-chart__body" }, renderChart())
13958
+ );
13959
+ };
13960
+
13961
+ // src/charts/ChartOverlay.tsx
13962
+ import React36, { useEffect as useEffect17, useRef as useRef21, useState as useState26 } from "react";
13963
+ var ChartOverlay = ({
13964
+ config,
13965
+ onClose,
13966
+ onChangeType,
13967
+ onToggleTheme,
13968
+ position = "bottom-right",
13969
+ draggable = true
13970
+ }) => {
13971
+ const overlayRef = useRef21(null);
13972
+ const [isDragging, setIsDragging] = useState26(false);
13973
+ const [dragOffset, setDragOffset] = useState26({ x: 0, y: 0 });
13974
+ const [chartPosition, setChartPosition] = useState26({ x: 0, y: 0 });
13975
+ const [dimensions] = useState26({ width: 600, height: 400 });
13976
+ useEffect17(() => {
13977
+ if (!overlayRef.current) return;
13978
+ const updatePosition = () => {
13979
+ const viewport = {
13980
+ width: window.innerWidth,
13981
+ height: window.innerHeight
13982
+ };
13983
+ let x = 0;
13984
+ let y = 0;
13985
+ switch (position) {
13986
+ case "top-right":
13987
+ x = viewport.width - dimensions.width - 40;
13988
+ y = 40;
13989
+ break;
13990
+ case "top-left":
13991
+ x = 40;
13992
+ y = 40;
13993
+ break;
13994
+ case "bottom-right":
13995
+ x = viewport.width - dimensions.width - 40;
13996
+ y = viewport.height - dimensions.height - 40;
13997
+ break;
13998
+ case "bottom-left":
13999
+ x = 40;
14000
+ y = viewport.height - dimensions.height - 40;
14001
+ break;
14002
+ case "center":
14003
+ x = (viewport.width - dimensions.width) / 2;
14004
+ y = (viewport.height - dimensions.height) / 2;
14005
+ break;
14006
+ }
14007
+ setChartPosition({ x, y });
14008
+ };
14009
+ updatePosition();
14010
+ window.addEventListener("resize", updatePosition);
14011
+ return () => window.removeEventListener("resize", updatePosition);
14012
+ }, [position, dimensions]);
14013
+ const handleMouseDown = (e) => {
14014
+ if (!draggable) return;
14015
+ if (e.target.closest(".quick-chart__body")) return;
14016
+ setIsDragging(true);
14017
+ setDragOffset({
14018
+ x: e.clientX - chartPosition.x,
14019
+ y: e.clientY - chartPosition.y
14020
+ });
14021
+ };
14022
+ useEffect17(() => {
14023
+ if (!isDragging) return;
14024
+ const handleMouseMove = (e) => {
14025
+ const newX = e.clientX - dragOffset.x;
14026
+ const newY = e.clientY - dragOffset.y;
14027
+ const maxX = window.innerWidth - dimensions.width;
14028
+ const maxY = window.innerHeight - dimensions.height;
14029
+ setChartPosition({
14030
+ x: Math.max(0, Math.min(newX, maxX)),
14031
+ y: Math.max(0, Math.min(newY, maxY))
14032
+ });
14033
+ };
14034
+ const handleMouseUp = () => {
14035
+ setIsDragging(false);
14036
+ };
14037
+ document.addEventListener("mousemove", handleMouseMove);
14038
+ document.addEventListener("mouseup", handleMouseUp);
14039
+ return () => {
14040
+ document.removeEventListener("mousemove", handleMouseMove);
14041
+ document.removeEventListener("mouseup", handleMouseUp);
14042
+ };
14043
+ }, [isDragging, dragOffset, dimensions]);
14044
+ useEffect17(() => {
14045
+ const handleKeyDown = (e) => {
14046
+ if (e.key === "Escape") {
14047
+ onClose();
14048
+ }
14049
+ };
14050
+ document.addEventListener("keydown", handleKeyDown);
14051
+ return () => document.removeEventListener("keydown", handleKeyDown);
14052
+ }, [onClose]);
14053
+ return /* @__PURE__ */ React36.createElement("div", { className: "chart-overlay" }, /* @__PURE__ */ React36.createElement("div", { className: "chart-overlay__backdrop", onClick: onClose }), /* @__PURE__ */ React36.createElement(
14054
+ "div",
14055
+ {
14056
+ ref: overlayRef,
14057
+ className: `chart-overlay__container ${isDragging ? "chart-overlay__container--dragging" : ""} ${draggable ? "chart-overlay__container--draggable" : ""}`,
14058
+ style: {
14059
+ left: chartPosition.x,
14060
+ top: chartPosition.y,
14061
+ width: dimensions.width,
14062
+ height: dimensions.height
14063
+ },
14064
+ onMouseDown: handleMouseDown
14065
+ },
14066
+ /* @__PURE__ */ React36.createElement(
14067
+ QuickChart,
14068
+ {
14069
+ config,
14070
+ onClose,
14071
+ onChangeType,
14072
+ onToggleTheme,
14073
+ allowTypeSwitch: true,
14074
+ allowThemeSwitch: true,
14075
+ width: dimensions.width,
14076
+ height: dimensions.height
14077
+ }
14078
+ )
14079
+ ));
14080
+ };
13518
14081
  export {
13519
14082
  AdvancedFilterBuilder,
13520
14083
  BadgeCell,
13521
14084
  ButtonCell,
14085
+ ChartOverlay,
13522
14086
  ColumnChooser,
13523
14087
  ColumnFilters,
13524
14088
  CurrencyCell,
@@ -13544,6 +14108,7 @@ export {
13544
14108
  PivotToolbar,
13545
14109
  PriorityIndicator,
13546
14110
  ProgressBar,
14111
+ QuickChart,
13547
14112
  Rating,
13548
14113
  RichSelectEditor,
13549
14114
  ServerAdapter,
@@ -13555,6 +14120,7 @@ export {
13555
14120
  VirtualScroller,
13556
14121
  WebSocketMockFeed,
13557
14122
  alpineTheme,
14123
+ buildChartConfigFromRange,
13558
14124
  buildPivot,
13559
14125
  buildTreeFromFlat,
13560
14126
  collapseAllNodes,
@@ -13593,11 +14159,14 @@ export {
13593
14159
  isTreeNode,
13594
14160
  loadDensityMode,
13595
14161
  materialTheme,
14162
+ normalizeRange,
13596
14163
  parseFormattedNumber,
13597
14164
  quartzTheme,
13598
14165
  saveDensityMode,
13599
14166
  themes,
13600
14167
  toggleNodeExpansion,
14168
+ updateChartTheme,
14169
+ updateChartType,
13601
14170
  useDensityMode,
13602
14171
  useEditorAutoFocus,
13603
14172
  useEditorClickOutside,