@inkindcards/semantic-layer 2.4.0 → 2.4.1

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.
@@ -1083,6 +1083,14 @@ function generateMigrationPrompt(config) {
1083
1083
  }
1084
1084
 
1085
1085
  // src/components/report-prompt-generator.ts
1086
+ var TIME_PRESET_LABELS = {
1087
+ "12m": "12 months",
1088
+ "6m": "6 months",
1089
+ "3m": "3 months",
1090
+ "1m": "1 month",
1091
+ "1w": "1 week",
1092
+ "1d": "1 day"
1093
+ };
1086
1094
  var PALETTE = [
1087
1095
  "#3b82f6",
1088
1096
  "#10b981",
@@ -1140,8 +1148,19 @@ function generateReportPrompt(config) {
1140
1148
  parts.push("};");
1141
1149
  parts.push("```");
1142
1150
  parts.push("");
1143
- parts.push("For each filter dropdown, query the distinct values of the dimension using useSemanticQuery with that dimension as a groupBy and any single metric, then populate the dropdown options from the returned rows.");
1144
- parts.push("");
1151
+ const timeFilters = sharedFilters.filter((f) => f.dimension.type === "time_dimension" && f.timePreset);
1152
+ const dimFilters = sharedFilters.filter((f) => f.dimension.type !== "time_dimension" || !f.timePreset);
1153
+ if (timeFilters.length > 0) {
1154
+ parts.push("For time filters, compute a date range relative to today:");
1155
+ for (const f of timeFilters) {
1156
+ parts.push(` - "${f.dimension.name}": default to the last ${TIME_PRESET_LABELS[f.timePreset]}. Compute a start date (e.g. \`new Date(); startDate.setMonth(startDate.getMonth() - N)\`) and pass it as a filter value. Include preset buttons (${Object.values(TIME_PRESET_LABELS).join(", ")}) so the user can switch ranges.`);
1157
+ }
1158
+ parts.push("");
1159
+ }
1160
+ if (dimFilters.length > 0) {
1161
+ parts.push("For each dimension filter dropdown, query the distinct values of the dimension using useSemanticQuery with that dimension as a groupBy and any single metric, then populate the dropdown options from the returned rows.");
1162
+ parts.push("");
1163
+ }
1145
1164
  }
1146
1165
  parts.push("## Layout");
1147
1166
  parts.push("");
@@ -1296,6 +1315,13 @@ function sanitize(name) {
1296
1315
  return name.replace(/[^a-zA-Z0-9_]/g, "_");
1297
1316
  }
1298
1317
  var LOVABLE_CHAR_LIMIT = 5e4;
1318
+ function isRunningInIframe() {
1319
+ try {
1320
+ return window.self !== window.top;
1321
+ } catch {
1322
+ return true;
1323
+ }
1324
+ }
1299
1325
  function canOpenInLovable(prompt) {
1300
1326
  return prompt.length <= LOVABLE_CHAR_LIMIT;
1301
1327
  }
@@ -1441,16 +1467,48 @@ function UnifiedModal({
1441
1467
  entry,
1442
1468
  onClose
1443
1469
  }) {
1470
+ const [dragPos, setDragPos] = react.useState(null);
1471
+ const dragRef = react.useRef(null);
1472
+ const modalRef = react.useRef(null);
1473
+ const handleHeaderMouseDown = react.useCallback((e) => {
1474
+ if (e.target.closest("button")) return;
1475
+ e.preventDefault();
1476
+ const modal = modalRef.current;
1477
+ if (!modal) return;
1478
+ const rect = modal.getBoundingClientRect();
1479
+ dragRef.current = { startX: e.clientX, startY: e.clientY, origX: rect.left, origY: rect.top };
1480
+ const onMove = (ev) => {
1481
+ if (!dragRef.current) return;
1482
+ const dx = ev.clientX - dragRef.current.startX;
1483
+ const dy = ev.clientY - dragRef.current.startY;
1484
+ setDragPos({ x: dragRef.current.origX + dx, y: dragRef.current.origY + dy });
1485
+ };
1486
+ const onUp = () => {
1487
+ dragRef.current = null;
1488
+ document.removeEventListener("mousemove", onMove);
1489
+ document.removeEventListener("mouseup", onUp);
1490
+ };
1491
+ document.addEventListener("mousemove", onMove);
1492
+ document.addEventListener("mouseup", onUp);
1493
+ }, []);
1494
+ const positionStyle = dragPos ? { position: "fixed", top: dragPos.y, left: dragPos.x, transform: "none" } : { position: "fixed", top: "50%", left: "50%", transform: "translate(-50%, -50%)" };
1444
1495
  return /* @__PURE__ */ jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [
1445
1496
  /* @__PURE__ */ jsxRuntime.jsx("div", { onClick: onClose, style: backdropStyle }),
1446
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: modalStyle, children: [
1447
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: modalHeaderStyle, children: [
1448
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 0 }, children: [
1449
- /* @__PURE__ */ jsxRuntime.jsx(TabButton, { label: "Migrate", active: tab === "migrate", onClick: () => onTabChange("migrate") }),
1450
- /* @__PURE__ */ jsxRuntime.jsx(TabButton, { label: "Build", active: tab === "build", onClick: () => onTabChange("build") })
1451
- ] }),
1452
- /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: onClose, style: closeBtnStyle, children: "\xD7" })
1453
- ] }),
1497
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { ref: modalRef, style: { ...modalStyle, ...positionStyle }, children: [
1498
+ /* @__PURE__ */ jsxRuntime.jsxs(
1499
+ "div",
1500
+ {
1501
+ onMouseDown: handleHeaderMouseDown,
1502
+ style: { ...modalHeaderStyle, cursor: dragRef.current ? "grabbing" : "grab" },
1503
+ children: [
1504
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", gap: 0 }, children: [
1505
+ /* @__PURE__ */ jsxRuntime.jsx(TabButton, { label: "Migrate", active: tab === "migrate", onClick: () => onTabChange("migrate") }),
1506
+ /* @__PURE__ */ jsxRuntime.jsx(TabButton, { label: "Build", active: tab === "build", onClick: () => onTabChange("build") })
1507
+ ] }),
1508
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: onClose, style: closeBtnStyle, children: "\xD7" })
1509
+ ]
1510
+ }
1511
+ ),
1454
1512
  tab === "migrate" ? /* @__PURE__ */ jsxRuntime.jsx(MigrateTab, { entry, onClose }) : /* @__PURE__ */ jsxRuntime.jsx(BuildTab, {})
1455
1513
  ] })
1456
1514
  ] });
@@ -1683,7 +1741,14 @@ var WIDGET_TYPES = [
1683
1741
  function BuildTab() {
1684
1742
  const { fields: catalog, isLoading: catalogLoading } = chunkT2C43AAL_cjs.useMetrics();
1685
1743
  const allMetrics = react.useMemo(() => catalog.filter((f) => f.type === "metric"), [catalog]);
1686
- const allDimensions = react.useMemo(() => catalog.filter((f) => f.type === "dimension" || f.type === "time_dimension"), [catalog]);
1744
+ const allDimensions = react.useMemo(() => {
1745
+ const dims = catalog.filter((f) => f.type === "dimension" || f.type === "time_dimension");
1746
+ return dims.sort((a, b) => {
1747
+ if (a.name === "metric_time") return -1;
1748
+ if (b.name === "metric_time") return 1;
1749
+ return 0;
1750
+ });
1751
+ }, [catalog]);
1687
1752
  const [dashboardTitle, setDashboardTitle] = react.useState("Dashboard");
1688
1753
  const [layout, setLayout] = react.useState("dashboard");
1689
1754
  const [widgets, setWidgets] = react.useState([]);
@@ -1692,29 +1757,74 @@ function BuildTab() {
1692
1757
  const [copied, setCopied] = react.useState(false);
1693
1758
  const [lovableSent, setLovableSent] = react.useState(false);
1694
1759
  const [previewOpen, setPreviewOpen] = react.useState(false);
1760
+ const [catalogWidth, setCatalogWidth] = react.useState(220);
1761
+ const catalogDragRef = react.useRef(null);
1762
+ const inIframe = react.useMemo(() => isRunningInIframe(), []);
1763
+ const handleCatalogDragStart = react.useCallback((e) => {
1764
+ e.preventDefault();
1765
+ catalogDragRef.current = { startX: e.clientX, startW: catalogWidth };
1766
+ const onMove = (ev) => {
1767
+ if (!catalogDragRef.current) return;
1768
+ const delta = ev.clientX - catalogDragRef.current.startX;
1769
+ setCatalogWidth(Math.max(160, Math.min(400, catalogDragRef.current.startW + delta)));
1770
+ };
1771
+ const onUp = () => {
1772
+ catalogDragRef.current = null;
1773
+ document.removeEventListener("mousemove", onMove);
1774
+ document.removeEventListener("mouseup", onUp);
1775
+ };
1776
+ document.addEventListener("mousemove", onMove);
1777
+ document.addEventListener("mouseup", onUp);
1778
+ }, [catalogWidth]);
1695
1779
  const addWidget = react.useCallback((type) => {
1780
+ const isTimeSeries = type === "line" || type === "area" || type === "kpi";
1781
+ const metricTime = allDimensions.find((d) => d.name === "metric_time");
1696
1782
  setWidgets((prev) => [...prev, {
1697
1783
  id: nextWidgetId(),
1698
1784
  title: `${WIDGET_TYPES.find((t) => t.type === type)?.label ?? "Widget"} ${prev.length + 1}`,
1699
1785
  type,
1700
1786
  metrics: [],
1701
- groupBy: [],
1702
- grain: null
1787
+ groupBy: isTimeSeries && metricTime ? [metricTime] : [],
1788
+ grain: isTimeSeries && metricTime ? "month" : null
1703
1789
  }]);
1704
- }, []);
1790
+ }, [allDimensions]);
1705
1791
  const removeWidget = react.useCallback((id) => {
1706
1792
  setWidgets((prev) => prev.filter((w) => w.id !== id));
1707
1793
  }, []);
1708
1794
  const updateWidget = react.useCallback((id, patch) => {
1709
1795
  setWidgets((prev) => prev.map((w) => w.id === id ? { ...w, ...patch } : w));
1710
1796
  }, []);
1797
+ const duplicateWidget = react.useCallback((id) => {
1798
+ setWidgets((prev) => {
1799
+ const source = prev.find((w) => w.id === id);
1800
+ if (!source) return prev;
1801
+ const copy = {
1802
+ ...source,
1803
+ id: nextWidgetId(),
1804
+ title: `${source.title} (2)`,
1805
+ metrics: [...source.metrics],
1806
+ groupBy: [...source.groupBy]
1807
+ };
1808
+ const idx = prev.findIndex((w) => w.id === id);
1809
+ return [...prev.slice(0, idx + 1), copy, ...prev.slice(idx + 1)];
1810
+ });
1811
+ }, []);
1711
1812
  const addFilter = react.useCallback((dim) => {
1712
1813
  if (sharedFilters.some((f) => f.dimension.name === dim.name)) return;
1713
- setSharedFilters((prev) => [...prev, { dimension: dim, label: dim.displayName }]);
1814
+ setSharedFilters((prev) => [...prev, {
1815
+ dimension: dim,
1816
+ label: dim.displayName,
1817
+ timePreset: dim.type === "time_dimension" ? "12m" : null
1818
+ }]);
1714
1819
  }, [sharedFilters]);
1715
1820
  const removeFilter = react.useCallback((name) => {
1716
1821
  setSharedFilters((prev) => prev.filter((f) => f.dimension.name !== name));
1717
1822
  }, []);
1823
+ const updateFilterPreset = react.useCallback((name, preset) => {
1824
+ setSharedFilters((prev) => prev.map(
1825
+ (f) => f.dimension.name === name ? { ...f, timePreset: preset } : f
1826
+ ));
1827
+ }, []);
1718
1828
  const addFieldToWidget = react.useCallback((widgetId, field) => {
1719
1829
  setWidgets((prev) => prev.map((w) => {
1720
1830
  if (w.id !== widgetId) return w;
@@ -1748,11 +1858,17 @@ function BuildTab() {
1748
1858
  setCopied(true);
1749
1859
  setTimeout(() => setCopied(false), 2e3);
1750
1860
  }, [prompt]);
1751
- const handleLovable = react.useCallback(() => {
1752
- openInLovable(prompt);
1753
- setLovableSent(true);
1754
- setTimeout(() => setLovableSent(false), 3e3);
1755
- }, [prompt]);
1861
+ const handleLovable = react.useCallback(async () => {
1862
+ if (inIframe) {
1863
+ await copyToClipboard(prompt);
1864
+ setLovableSent(true);
1865
+ setTimeout(() => setLovableSent(false), 3e3);
1866
+ } else {
1867
+ openInLovable(prompt);
1868
+ setLovableSent(true);
1869
+ setTimeout(() => setLovableSent(false), 3e3);
1870
+ }
1871
+ }, [prompt, inIframe]);
1756
1872
  const filteredMetrics = react.useMemo(() => {
1757
1873
  const q = catalogSearch.toLowerCase();
1758
1874
  if (!q) return allMetrics;
@@ -1796,7 +1912,7 @@ function BuildTab() {
1796
1912
  )) })
1797
1913
  ] }),
1798
1914
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { display: "flex", flex: 1, minHeight: 0 }, children: [
1799
- /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { width: 220, borderRight: "1px solid #e5e7eb", overflow: "auto", flexShrink: 0 }, children: [
1915
+ /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { width: catalogWidth, borderRight: "1px solid #e5e7eb", overflow: "auto", flexShrink: 0 }, children: [
1800
1916
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: { padding: "8px 12px" }, children: /* @__PURE__ */ jsxRuntime.jsx(
1801
1917
  "input",
1802
1918
  {
@@ -1822,11 +1938,40 @@ function BuildTab() {
1822
1938
  filteredDimensions.length,
1823
1939
  ")"
1824
1940
  ] }),
1825
- filteredDimensions.map((f) => /* @__PURE__ */ jsxRuntime.jsx(CatalogChip, { field: f, widgets, onAddToWidget: addFieldToWidget, onAddAsFilter: addFilter }, f.name)),
1941
+ filteredDimensions.map((f) => /* @__PURE__ */ jsxRuntime.jsx(
1942
+ CatalogChip,
1943
+ {
1944
+ field: f,
1945
+ widgets,
1946
+ onAddToWidget: addFieldToWidget,
1947
+ onAddAsFilter: addFilter,
1948
+ suffix: f.name === "metric_time" ? " (recommended)" : void 0
1949
+ },
1950
+ f.name
1951
+ )),
1826
1952
  filteredDimensions.length === 0 && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, color: "#9ca3af", padding: "4px 0" }, children: "None found" })
1827
1953
  ] })
1828
1954
  ] })
1829
1955
  ] }),
1956
+ /* @__PURE__ */ jsxRuntime.jsx(
1957
+ "div",
1958
+ {
1959
+ onMouseDown: handleCatalogDragStart,
1960
+ style: {
1961
+ width: 4,
1962
+ cursor: "col-resize",
1963
+ backgroundColor: "transparent",
1964
+ flexShrink: 0,
1965
+ position: "relative"
1966
+ },
1967
+ onMouseEnter: (e) => {
1968
+ e.currentTarget.style.backgroundColor = "#d1d5db";
1969
+ },
1970
+ onMouseLeave: (e) => {
1971
+ e.currentTarget.style.backgroundColor = "transparent";
1972
+ }
1973
+ }
1974
+ ),
1830
1975
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: { flex: 1, overflow: "auto", padding: "12px 16px" }, children: widgets.length === 0 ? /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { textAlign: "center", padding: "40px 20px", color: "#9ca3af" }, children: [
1831
1976
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 14, fontWeight: 500, marginBottom: 12 }, children: "Compose your dashboard" }),
1832
1977
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 12, marginBottom: 20 }, children: "Add widgets below, then pick metrics and dimensions from the catalog on the left." }),
@@ -1838,6 +1983,7 @@ function BuildTab() {
1838
1983
  widget: w,
1839
1984
  onUpdate: updateWidget,
1840
1985
  onRemove: removeWidget,
1986
+ onDuplicate: duplicateWidget,
1841
1987
  onRemoveField: removeFieldFromWidget,
1842
1988
  allDimensions
1843
1989
  },
@@ -1847,9 +1993,31 @@ function BuildTab() {
1847
1993
  /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginTop: 16, padding: "12px 0", borderTop: "1px solid #f3f4f6" }, children: [
1848
1994
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: sectionTitleStyle, children: "Shared Filters" }),
1849
1995
  /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 11, color: "#9ca3af", marginBottom: 8 }, children: "Dimensions that filter all widgets together. Add from the catalog sidebar." }),
1850
- sharedFilters.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 12, color: "#d1d5db", fontStyle: "italic" }, children: "None added yet" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", gap: 6, flexWrap: "wrap" }, children: sharedFilters.map((f) => /* @__PURE__ */ jsxRuntime.jsxs("span", { style: chipStyle, children: [
1851
- f.label,
1852
- /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => removeFilter(f.dimension.name), style: chipRemoveStyle, children: "\xD7" })
1996
+ sharedFilters.length === 0 ? /* @__PURE__ */ jsxRuntime.jsx("div", { style: { fontSize: 12, color: "#d1d5db", fontStyle: "italic" }, children: "None added yet" }) : /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", flexDirection: "column", gap: 8 }, children: sharedFilters.map((f) => /* @__PURE__ */ jsxRuntime.jsxs("div", { children: [
1997
+ /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", alignItems: "center", gap: 6 }, children: /* @__PURE__ */ jsxRuntime.jsxs("span", { style: chipStyle, children: [
1998
+ f.label,
1999
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => removeFilter(f.dimension.name), style: chipRemoveStyle, children: "\xD7" })
2000
+ ] }) }),
2001
+ f.dimension.type === "time_dimension" && /* @__PURE__ */ jsxRuntime.jsx("div", { style: { display: "flex", gap: 4, marginTop: 4, marginLeft: 4 }, children: Object.keys(TIME_PRESET_LABELS).map((p) => /* @__PURE__ */ jsxRuntime.jsx(
2002
+ "button",
2003
+ {
2004
+ onClick: () => updateFilterPreset(f.dimension.name, p),
2005
+ style: {
2006
+ padding: "2px 8px",
2007
+ fontSize: 10,
2008
+ fontWeight: 600,
2009
+ fontFamily: "system-ui, -apple-system, sans-serif",
2010
+ borderRadius: 999,
2011
+ border: f.timePreset === p ? "1px solid #3b82f6" : "1px solid #e5e7eb",
2012
+ backgroundColor: f.timePreset === p ? "#eff6ff" : "#fff",
2013
+ color: f.timePreset === p ? "#3b82f6" : "#9ca3af",
2014
+ cursor: "pointer",
2015
+ transition: "all 0.1s"
2016
+ },
2017
+ children: TIME_PRESET_LABELS[p]
2018
+ },
2019
+ p
2020
+ )) })
1853
2021
  ] }, f.dimension.name)) })
1854
2022
  ] }),
1855
2023
  canGenerate && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { marginTop: 12 }, children: [
@@ -1901,8 +2069,8 @@ function BuildTab() {
1901
2069
  gap: 6
1902
2070
  },
1903
2071
  children: [
1904
- lovableSent ? "Opening Lovable..." : "Build in Lovable",
1905
- !lovableSent && /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
2072
+ lovableSent ? inIframe ? "Copied! Paste into Lovable chat" : "Opening Lovable..." : inIframe ? "Send to Lovable \u2764\uFE0F" : "Build in Lovable \u2764\uFE0F",
2073
+ !lovableSent && !inIframe && /* @__PURE__ */ jsxRuntime.jsxs("svg", { width: "12", height: "12", viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2.5", strokeLinecap: "round", strokeLinejoin: "round", children: [
1906
2074
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 17L17 7" }),
1907
2075
  /* @__PURE__ */ jsxRuntime.jsx("path", { d: "M7 7h10v10" })
1908
2076
  ] })
@@ -1916,7 +2084,8 @@ function CatalogChip({
1916
2084
  field,
1917
2085
  widgets,
1918
2086
  onAddToWidget,
1919
- onAddAsFilter
2087
+ onAddAsFilter,
2088
+ suffix
1920
2089
  }) {
1921
2090
  const [menuOpen, setMenuOpen] = react.useState(false);
1922
2091
  const typeIcon = field.type === "metric" ? "\u2581" : field.type === "time_dimension" ? "\u25F7" : "\u2022";
@@ -1958,7 +2127,10 @@ ${field.description}`,
1958
2127
  },
1959
2128
  children: [
1960
2129
  /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: typeColor, fontSize: 10, flexShrink: 0 }, children: typeIcon }),
1961
- /* @__PURE__ */ jsxRuntime.jsx("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: field.displayName })
2130
+ /* @__PURE__ */ jsxRuntime.jsxs("span", { style: { overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }, children: [
2131
+ field.displayName,
2132
+ suffix && /* @__PURE__ */ jsxRuntime.jsx("span", { style: { color: "#9ca3af", fontWeight: 400 }, children: suffix })
2133
+ ] })
1962
2134
  ]
1963
2135
  }
1964
2136
  ),
@@ -2048,6 +2220,7 @@ function WidgetCard({
2048
2220
  widget,
2049
2221
  onUpdate,
2050
2222
  onRemove,
2223
+ onDuplicate,
2051
2224
  onRemoveField,
2052
2225
  allDimensions
2053
2226
  }) {
@@ -2086,6 +2259,7 @@ function WidgetCard({
2086
2259
  },
2087
2260
  wt.type
2088
2261
  )) }),
2262
+ /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => onDuplicate(widget.id), style: { background: "none", border: "none", cursor: "pointer", fontSize: 12, color: "#d1d5db", padding: "0 2px" }, title: "Duplicate widget", children: "\u2398" }),
2089
2263
  /* @__PURE__ */ jsxRuntime.jsx("button", { onClick: () => onRemove(widget.id), style: { background: "none", border: "none", cursor: "pointer", fontSize: 14, color: "#d1d5db", padding: "0 2px" }, title: "Remove widget", children: "\xD7" })
2090
2264
  ] }),
2091
2265
  !collapsed && /* @__PURE__ */ jsxRuntime.jsxs("div", { style: { padding: "8px 12px" }, children: [
@@ -2144,12 +2318,9 @@ var backdropStyle = {
2144
2318
  zIndex: 1e5
2145
2319
  };
2146
2320
  var modalStyle = {
2147
- position: "fixed",
2148
- top: "50%",
2149
- left: "50%",
2150
- transform: "translate(-50%, -50%)",
2151
2321
  zIndex: 100001,
2152
2322
  width: "min(900px, 95vw)",
2323
+ height: "85vh",
2153
2324
  maxHeight: "85vh",
2154
2325
  backgroundColor: "#fff",
2155
2326
  borderRadius: 12,
@@ -2303,6 +2474,7 @@ exports.analyzeChartData = analyzeChartData;
2303
2474
  exports.canOpenInLovable = canOpenInLovable;
2304
2475
  exports.generateMigrationPrompt = generateMigrationPrompt;
2305
2476
  exports.generateReportPrompt = generateReportPrompt;
2477
+ exports.isRunningInIframe = isRunningInIframe;
2306
2478
  exports.matchField = matchField;
2307
2479
  exports.matchFields = matchFields;
2308
2480
  exports.openInLovable = openInLovable;