@schandlergarcia/sf-web-components 1.0.0
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/.a4drules/skills/building-data-visualization/SKILL.md +72 -0
- package/.a4drules/skills/building-data-visualization/implementation/bar-line-chart.md +316 -0
- package/.a4drules/skills/building-data-visualization/implementation/dashboard-layout.md +189 -0
- package/.a4drules/skills/building-data-visualization/implementation/donut-chart.md +181 -0
- package/.a4drules/skills/building-data-visualization/implementation/stat-card.md +150 -0
- package/.a4drules/skills/building-react-components/SKILL.md +96 -0
- package/.a4drules/skills/building-react-components/implementation/component.md +78 -0
- package/.a4drules/skills/building-react-components/implementation/header-footer.md +132 -0
- package/.a4drules/skills/building-react-components/implementation/page.md +93 -0
- package/.a4drules/skills/configuring-csp-trusted-sites/SKILL.md +90 -0
- package/.a4drules/skills/configuring-csp-trusted-sites/implementation/metadata-format.md +281 -0
- package/.a4drules/skills/configuring-webapp-metadata/SKILL.md +158 -0
- package/.a4drules/skills/creating-webapp/SKILL.md +140 -0
- package/.a4drules/skills/deploying-to-salesforce/SKILL.md +226 -0
- package/.a4drules/skills/implementing-file-upload/SKILL.md +396 -0
- package/.a4drules/skills/installing-webapp-features/SKILL.md +210 -0
- package/.a4drules/skills/managing-agentforce-conversation-client/SKILL.md +186 -0
- package/.a4drules/skills/managing-agentforce-conversation-client/references/constraints.md +134 -0
- package/.a4drules/skills/managing-agentforce-conversation-client/references/examples.md +132 -0
- package/.a4drules/skills/managing-agentforce-conversation-client/references/style-tokens.md +101 -0
- package/.a4drules/skills/managing-agentforce-conversation-client/references/troubleshooting.md +57 -0
- package/.a4drules/skills/using-salesforce-data/SKILL.md +363 -0
- package/.a4drules/skills/using-salesforce-data/graphql-search.sh +139 -0
- package/.a4drules/webapp-data.md +353 -0
- package/.a4drules/webapp-ui.md +16 -0
- package/README.md +124 -0
- package/dist/components/library/cards/ActionList.js +27 -0
- package/dist/components/library/cards/ActionList.js.map +1 -0
- package/dist/components/library/cards/ActivityCard.js +40 -0
- package/dist/components/library/cards/ActivityCard.js.map +1 -0
- package/dist/components/library/cards/BaseCard.js +89 -0
- package/dist/components/library/cards/BaseCard.js.map +1 -0
- package/dist/components/library/cards/CalloutCard.js +28 -0
- package/dist/components/library/cards/CalloutCard.js.map +1 -0
- package/dist/components/library/cards/ChartCard.js +79 -0
- package/dist/components/library/cards/ChartCard.js.map +1 -0
- package/dist/components/library/cards/FeedPanel.js +38 -0
- package/dist/components/library/cards/FeedPanel.js.map +1 -0
- package/dist/components/library/cards/ListCard.js +112 -0
- package/dist/components/library/cards/ListCard.js.map +1 -0
- package/dist/components/library/cards/MetricCard.js +86 -0
- package/dist/components/library/cards/MetricCard.js.map +1 -0
- package/dist/components/library/cards/MetricsStrip.js +60 -0
- package/dist/components/library/cards/MetricsStrip.js.map +1 -0
- package/dist/components/library/cards/SectionCard.js +59 -0
- package/dist/components/library/cards/SectionCard.js.map +1 -0
- package/dist/components/library/cards/StatusCard.js +137 -0
- package/dist/components/library/cards/StatusCard.js.map +1 -0
- package/dist/components/library/cards/TableCard.js +244 -0
- package/dist/components/library/cards/TableCard.js.map +1 -0
- package/dist/components/library/cards/WidgetCard.js +60 -0
- package/dist/components/library/cards/WidgetCard.js.map +1 -0
- package/dist/components/library/charts/D3Chart.js +74 -0
- package/dist/components/library/charts/D3Chart.js.map +1 -0
- package/dist/components/library/charts/D3ChartTemplates.js +44 -0
- package/dist/components/library/charts/D3ChartTemplates.js.map +1 -0
- package/dist/components/library/charts/GeoMap.js +229 -0
- package/dist/components/library/charts/GeoMap.js.map +1 -0
- package/dist/components/library/chat/ChatBar.js +194 -0
- package/dist/components/library/chat/ChatBar.js.map +1 -0
- package/dist/components/library/chat/ChatInput.js +67 -0
- package/dist/components/library/chat/ChatInput.js.map +1 -0
- package/dist/components/library/chat/ChatMessage.js +112 -0
- package/dist/components/library/chat/ChatMessage.js.map +1 -0
- package/dist/components/library/chat/ChatMessageList.js +50 -0
- package/dist/components/library/chat/ChatMessageList.js.map +1 -0
- package/dist/components/library/chat/ChatPanel.js +77 -0
- package/dist/components/library/chat/ChatPanel.js.map +1 -0
- package/dist/components/library/chat/ChatSuggestions.js +22 -0
- package/dist/components/library/chat/ChatSuggestions.js.map +1 -0
- package/dist/components/library/chat/ChatToolCall.js +87 -0
- package/dist/components/library/chat/ChatToolCall.js.map +1 -0
- package/dist/components/library/chat/ChatTypingIndicator.js +20 -0
- package/dist/components/library/chat/ChatTypingIndicator.js.map +1 -0
- package/dist/components/library/chat/ChatWelcome.js +24 -0
- package/dist/components/library/chat/ChatWelcome.js.map +1 -0
- package/dist/components/library/chat/useChatState.js +77 -0
- package/dist/components/library/chat/useChatState.js.map +1 -0
- package/dist/components/library/data/DataModeProvider.js +47 -0
- package/dist/components/library/data/DataModeProvider.js.map +1 -0
- package/dist/components/library/data/DataModeToggle.js +28 -0
- package/dist/components/library/data/DataModeToggle.js.map +1 -0
- package/dist/components/library/data/filterUtils.js +71 -0
- package/dist/components/library/data/filterUtils.js.map +1 -0
- package/dist/components/library/data/useDataSource.js +13 -0
- package/dist/components/library/data/useDataSource.js.map +1 -0
- package/dist/components/library/data/usePageFilters.js +46 -0
- package/dist/components/library/data/usePageFilters.js.map +1 -0
- package/dist/components/library/filters/FilterBar.js +89 -0
- package/dist/components/library/filters/FilterBar.js.map +1 -0
- package/dist/components/library/filters/SearchFilter.js +44 -0
- package/dist/components/library/filters/SearchFilter.js.map +1 -0
- package/dist/components/library/filters/SelectFilter.js +44 -0
- package/dist/components/library/filters/SelectFilter.js.map +1 -0
- package/dist/components/library/filters/ToggleFilter.js +48 -0
- package/dist/components/library/filters/ToggleFilter.js.map +1 -0
- package/dist/components/library/forms/FormField.js +256 -0
- package/dist/components/library/forms/FormField.js.map +1 -0
- package/dist/components/library/forms/FormModal.js +161 -0
- package/dist/components/library/forms/FormModal.js.map +1 -0
- package/dist/components/library/forms/FormRenderer.js +32 -0
- package/dist/components/library/forms/FormRenderer.js.map +1 -0
- package/dist/components/library/forms/FormSection.js +49 -0
- package/dist/components/library/forms/FormSection.js.map +1 -0
- package/dist/components/library/forms/useFormState.js +85 -0
- package/dist/components/library/forms/useFormState.js.map +1 -0
- package/dist/components/library/heroui/Accordion.js +12 -0
- package/dist/components/library/heroui/Accordion.js.map +1 -0
- package/dist/components/library/heroui/Alert.js +12 -0
- package/dist/components/library/heroui/Alert.js.map +1 -0
- package/dist/components/library/heroui/Badge.js +12 -0
- package/dist/components/library/heroui/Badge.js.map +1 -0
- package/dist/components/library/heroui/Breadcrumbs.js +12 -0
- package/dist/components/library/heroui/Breadcrumbs.js.map +1 -0
- package/dist/components/library/heroui/Button.js +18 -0
- package/dist/components/library/heroui/Button.js.map +1 -0
- package/dist/components/library/heroui/Card.js +12 -0
- package/dist/components/library/heroui/Card.js.map +1 -0
- package/dist/components/library/heroui/Drawer.js +12 -0
- package/dist/components/library/heroui/Drawer.js.map +1 -0
- package/dist/components/library/heroui/Dropdown.js +12 -0
- package/dist/components/library/heroui/Dropdown.js.map +1 -0
- package/dist/components/library/heroui/Input.js +10 -0
- package/dist/components/library/heroui/Input.js.map +1 -0
- package/dist/components/library/heroui/Kbd.js +12 -0
- package/dist/components/library/heroui/Kbd.js.map +1 -0
- package/dist/components/library/heroui/Meter.js +12 -0
- package/dist/components/library/heroui/Meter.js.map +1 -0
- package/dist/components/library/heroui/Modal.js +12 -0
- package/dist/components/library/heroui/Modal.js.map +1 -0
- package/dist/components/library/heroui/Pagination.js +12 -0
- package/dist/components/library/heroui/Pagination.js.map +1 -0
- package/dist/components/library/heroui/ProgressBar.js +12 -0
- package/dist/components/library/heroui/ProgressBar.js.map +1 -0
- package/dist/components/library/heroui/ProgressCircle.js +12 -0
- package/dist/components/library/heroui/ProgressCircle.js.map +1 -0
- package/dist/components/library/heroui/ScrollShadow.js +12 -0
- package/dist/components/library/heroui/ScrollShadow.js.map +1 -0
- package/dist/components/library/heroui/Select.js +12 -0
- package/dist/components/library/heroui/Select.js.map +1 -0
- package/dist/components/library/heroui/Separator.js +12 -0
- package/dist/components/library/heroui/Separator.js.map +1 -0
- package/dist/components/library/heroui/Skeleton.js +12 -0
- package/dist/components/library/heroui/Skeleton.js.map +1 -0
- package/dist/components/library/heroui/Tabs.js +12 -0
- package/dist/components/library/heroui/Tabs.js.map +1 -0
- package/dist/components/library/heroui/Toast.js +13 -0
- package/dist/components/library/heroui/Toast.js.map +1 -0
- package/dist/components/library/heroui/Toggle.js +12 -0
- package/dist/components/library/heroui/Toggle.js.map +1 -0
- package/dist/components/library/heroui/Tooltip.js +12 -0
- package/dist/components/library/heroui/Tooltip.js.map +1 -0
- package/dist/components/library/layout/PageContainer.js +9 -0
- package/dist/components/library/layout/PageContainer.js.map +1 -0
- package/dist/components/library/skeletons/CardSkeleton.js +29 -0
- package/dist/components/library/skeletons/CardSkeleton.js.map +1 -0
- package/dist/components/library/theme/AppThemeProvider.js +55 -0
- package/dist/components/library/theme/AppThemeProvider.js.map +1 -0
- package/dist/components/library/theme/tokens.js +55 -0
- package/dist/components/library/theme/tokens.js.map +1 -0
- package/dist/components/library/ui/Avatar.js +33 -0
- package/dist/components/library/ui/Avatar.js.map +1 -0
- package/dist/components/library/ui/Button.js +50 -0
- package/dist/components/library/ui/Button.js.map +1 -0
- package/dist/components/library/ui/Card.js +21 -0
- package/dist/components/library/ui/Card.js.map +1 -0
- package/dist/components/library/ui/Chip.js +31 -0
- package/dist/components/library/ui/Chip.js.map +1 -0
- package/dist/components/library/ui/Container.js +42 -0
- package/dist/components/library/ui/Container.js.map +1 -0
- package/dist/components/library/ui/EmptyState.js +27 -0
- package/dist/components/library/ui/EmptyState.js.map +1 -0
- package/dist/components/library/ui/Input.js +22 -0
- package/dist/components/library/ui/Input.js.map +1 -0
- package/dist/components/library/ui/Spinner.js +64 -0
- package/dist/components/library/ui/Spinner.js.map +1 -0
- package/dist/components/library/ui/Text.js +43 -0
- package/dist/components/library/ui/Text.js.map +1 -0
- package/dist/components/library/ui/Toggle.js +47 -0
- package/dist/components/library/ui/Toggle.js.map +1 -0
- package/dist/components/workspace/ComponentRegistry.js +231 -0
- package/dist/components/workspace/ComponentRegistry.js.map +1 -0
- package/dist/index.js +185 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/utils.js +9 -0
- package/dist/lib/utils.js.map +1 -0
- package/dist/node_modules/clsx/dist/clsx.js +17 -0
- package/dist/node_modules/clsx/dist/clsx.js.map +1 -0
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js +2925 -0
- package/dist/node_modules/tailwind-merge/dist/bundle-mjs.js.map +1 -0
- package/package.json +81 -0
- package/scripts/get-graphql-schema.mjs +68 -0
- package/scripts/reset-command-center.sh +358 -0
- package/scripts/rewrite-e2e-assets.mjs +23 -0
- package/scripts/validate-dashboard.sh +290 -0
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import * as e from "d3";
|
|
2
|
+
function C(n) {
|
|
3
|
+
e.select(n).selectAll("*").remove();
|
|
4
|
+
}
|
|
5
|
+
const F = {
|
|
6
|
+
lineChart(n, l, c, w = {}) {
|
|
7
|
+
const {
|
|
8
|
+
xKey: s = "x",
|
|
9
|
+
yKey: a = "y",
|
|
10
|
+
margin: r = { top: 12, right: 16, bottom: 28, left: 40 },
|
|
11
|
+
stroke: k = "#6366F1",
|
|
12
|
+
strokeWidth: b = 2,
|
|
13
|
+
showAxes: $ = !0,
|
|
14
|
+
showGrid: A = !0
|
|
15
|
+
} = w;
|
|
16
|
+
C(n);
|
|
17
|
+
const p = c.width, m = c.height, h = Math.max(0, p - r.left - r.right), i = Math.max(0, m - r.top - r.bottom), d = e.select(n).attr("viewBox", `0 0 ${p} ${m}`).append("g").attr("transform", `translate(${r.left},${r.top})`), x = l.map((t) => t?.[s]).filter((t) => t != null), f = l.map((t) => t?.[a]).filter((t) => t != null), g = e.extent(x), u = e.extent(f), y = e.scaleLinear().domain(g).nice().range([0, h]), o = e.scaleLinear().domain(u).nice().range([i, 0]);
|
|
18
|
+
A && d.append("g").attr("class", "grid").call(e.axisLeft(o).ticks(5).tickSize(-h).tickFormat("")).call((t) => t.selectAll("line").attr("stroke", "currentColor").attr("opacity", 0.12)).call((t) => t.selectAll("path").attr("stroke", "none"));
|
|
19
|
+
const B = e.line().x((t) => y(t[s])).y((t) => o(t[a])).defined((t) => t?.[s] != null && t?.[a] != null);
|
|
20
|
+
d.append("path").datum(l).attr("fill", "none").attr("stroke", k).attr("stroke-width", b).attr("d", B), $ && (d.append("g").attr("transform", `translate(0,${i})`).call(e.axisBottom(y).ticks(6)).call((t) => t.selectAll("text").attr("font-size", 10)), d.append("g").call(e.axisLeft(o).ticks(5)).call((t) => t.selectAll("text").attr("font-size", 10)));
|
|
21
|
+
},
|
|
22
|
+
groupedBarChart(n, l, c, w = {}) {
|
|
23
|
+
const {
|
|
24
|
+
groups: s = [],
|
|
25
|
+
margin: a = { top: 20, right: 20, bottom: 40, left: 55 },
|
|
26
|
+
xKey: r = "x",
|
|
27
|
+
colors: k = ["#6366F1", "#CBD5E1"],
|
|
28
|
+
barRadius: b = 4,
|
|
29
|
+
yFormat: $ = ",.0f",
|
|
30
|
+
showGrid: A = !0
|
|
31
|
+
} = w;
|
|
32
|
+
C(n);
|
|
33
|
+
const p = c.width, m = c.height, h = Math.max(0, p - a.left - a.right), i = Math.max(0, m - a.top - a.bottom), x = e.select(n).attr("viewBox", `0 0 ${p} ${m}`).append("g").attr("transform", `translate(${a.left},${a.top})`), f = s.length ? s : Object.keys(l[0] || {}).filter((t) => t !== r), g = e.scaleBand().domain(l.map((t) => t[r])).range([0, h]).padding(0.3), u = e.scaleBand().domain(f).range([0, g.bandwidth()]).padding(0.05), y = e.max(l, (t) => e.max(f, (z) => t[z])) * 1.15, o = e.scaleLinear().domain([0, y]).range([i, 0]);
|
|
34
|
+
x.append("g").attr("transform", `translate(0,${i})`).call(e.axisBottom(g).tickSize(0)).call((t) => t.selectAll("text").attr("fill", "#94a3b8").attr("font-size", "11px")).call((t) => t.select(".domain").remove()), x.append("g").call(e.axisLeft(o).ticks(5).tickFormat(e.format($)).tickSize(A ? -h : 0)).call((t) => t.selectAll("text").attr("fill", "#94a3b8").attr("font-size", "10px")).call((t) => t.selectAll(".tick line").attr("stroke", "#e2e8f0").attr("stroke-dasharray", "2,2")).call((t) => t.select(".domain").remove());
|
|
35
|
+
const B = x.selectAll(".bar-group").data(l).join("g").attr("class", "bar-group").attr("transform", (t) => `translate(${g(t[r])},0)`);
|
|
36
|
+
f.forEach((t, z) => {
|
|
37
|
+
B.append("rect").attr("x", u(t)).attr("y", (L) => o(L[t])).attr("width", u.bandwidth()).attr("height", (L) => i - o(L[t])).attr("rx", b).attr("fill", k[z % k.length]);
|
|
38
|
+
});
|
|
39
|
+
}
|
|
40
|
+
};
|
|
41
|
+
export {
|
|
42
|
+
F as D3ChartTemplates
|
|
43
|
+
};
|
|
44
|
+
//# sourceMappingURL=D3ChartTemplates.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"D3ChartTemplates.js","sources":["../../../../src/components/library/charts/D3ChartTemplates.jsx"],"sourcesContent":["import * as d3 from \"d3\";\n\nfunction clear(svg) {\n d3.select(svg).selectAll(\"*\").remove();\n}\n\nexport const D3ChartTemplates = {\n lineChart(svg, data, dims, opts = {}) {\n const {\n xKey = \"x\",\n yKey = \"y\",\n margin = { top: 12, right: 16, bottom: 28, left: 40 },\n stroke = \"#6366F1\",\n strokeWidth = 2,\n showAxes = true,\n showGrid = true\n } = opts;\n\n clear(svg);\n\n const width = dims.width;\n const height = dims.height;\n const innerW = Math.max(0, width - margin.left - margin.right);\n const innerH = Math.max(0, height - margin.top - margin.bottom);\n\n const g = d3.select(svg).attr(\"viewBox\", `0 0 ${width} ${height}`).append(\"g\").attr(\"transform\", `translate(${margin.left},${margin.top})`);\n\n const xs = data.map((d) => d?.[xKey]).filter((v) => v != null);\n const ys = data.map((d) => d?.[yKey]).filter((v) => v != null);\n\n const xDomain = d3.extent(xs);\n const yDomain = d3.extent(ys);\n\n const x = d3.scaleLinear().domain(xDomain).nice().range([0, innerW]);\n const y = d3.scaleLinear().domain(yDomain).nice().range([innerH, 0]);\n\n if (showGrid) {\n g.append(\"g\")\n .attr(\"class\", \"grid\")\n .call(d3.axisLeft(y).ticks(5).tickSize(-innerW).tickFormat(\"\"))\n .call((grid) => grid.selectAll(\"line\").attr(\"stroke\", \"currentColor\").attr(\"opacity\", 0.12))\n .call((grid) => grid.selectAll(\"path\").attr(\"stroke\", \"none\"));\n }\n\n const line = d3\n .line()\n .x((d) => x(d[xKey]))\n .y((d) => y(d[yKey]))\n .defined((d) => d?.[xKey] != null && d?.[yKey] != null);\n\n g.append(\"path\")\n .datum(data)\n .attr(\"fill\", \"none\")\n .attr(\"stroke\", stroke)\n .attr(\"stroke-width\", strokeWidth)\n .attr(\"d\", line);\n\n if (showAxes) {\n g.append(\"g\")\n .attr(\"transform\", `translate(0,${innerH})`)\n .call(d3.axisBottom(x).ticks(6))\n .call((ax) => ax.selectAll(\"text\").attr(\"font-size\", 10));\n\n g.append(\"g\")\n .call(d3.axisLeft(y).ticks(5))\n .call((ax) => ax.selectAll(\"text\").attr(\"font-size\", 10));\n }\n },\n\n groupedBarChart(svg, data, dims, opts = {}) {\n const {\n groups = [],\n margin = { top: 20, right: 20, bottom: 40, left: 55 },\n xKey = \"x\",\n colors = [\"#6366F1\", \"#CBD5E1\"],\n barRadius = 4,\n yFormat = \",.0f\",\n showGrid = true,\n } = opts;\n\n clear(svg);\n\n const width = dims.width;\n const height = dims.height;\n const innerW = Math.max(0, width - margin.left - margin.right);\n const innerH = Math.max(0, height - margin.top - margin.bottom);\n\n const sel = d3.select(svg).attr(\"viewBox\", `0 0 ${width} ${height}`);\n const g = sel.append(\"g\").attr(\"transform\", `translate(${margin.left},${margin.top})`);\n\n const groupKeys = groups.length ? groups : Object.keys(data[0] || {}).filter((k) => k !== xKey);\n\n const x0 = d3.scaleBand().domain(data.map((d) => d[xKey])).range([0, innerW]).padding(0.3);\n const x1 = d3.scaleBand().domain(groupKeys).range([0, x0.bandwidth()]).padding(0.05);\n const yMax = d3.max(data, (d) => d3.max(groupKeys, (k) => d[k])) * 1.15;\n const y = d3.scaleLinear().domain([0, yMax]).range([innerH, 0]);\n\n g.append(\"g\")\n .attr(\"transform\", `translate(0,${innerH})`)\n .call(d3.axisBottom(x0).tickSize(0))\n .call((ax) => ax.selectAll(\"text\").attr(\"fill\", \"#94a3b8\").attr(\"font-size\", \"11px\"))\n .call((ax) => ax.select(\".domain\").remove());\n\n g.append(\"g\")\n .call(d3.axisLeft(y).ticks(5).tickFormat(d3.format(yFormat)).tickSize(showGrid ? -innerW : 0))\n .call((ax) => ax.selectAll(\"text\").attr(\"fill\", \"#94a3b8\").attr(\"font-size\", \"10px\"))\n .call((ax) => ax.selectAll(\".tick line\").attr(\"stroke\", \"#e2e8f0\").attr(\"stroke-dasharray\", \"2,2\"))\n .call((ax) => ax.select(\".domain\").remove());\n\n const rows = g.selectAll(\".bar-group\").data(data).join(\"g\")\n .attr(\"class\", \"bar-group\")\n .attr(\"transform\", (d) => `translate(${x0(d[xKey])},0)`);\n\n groupKeys.forEach((key, i) => {\n rows.append(\"rect\")\n .attr(\"x\", x1(key))\n .attr(\"y\", (d) => y(d[key]))\n .attr(\"width\", x1.bandwidth())\n .attr(\"height\", (d) => innerH - y(d[key]))\n .attr(\"rx\", barRadius)\n .attr(\"fill\", colors[i % colors.length]);\n });\n },\n};\n\n\n"],"names":["clear","svg","d3","D3ChartTemplates","data","dims","opts","xKey","yKey","margin","stroke","strokeWidth","showAxes","showGrid","width","height","innerW","innerH","g","xs","d","v","ys","xDomain","yDomain","x","y","grid","line","ax","groups","colors","barRadius","yFormat","groupKeys","k","x0","x1","yMax","rows","key","i"],"mappings":"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"}
|
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
import { jsxs as p, jsx as o } from "react/jsx-runtime";
|
|
2
|
+
import { useRef as P, useState as ce, useMemo as w, useEffect as F, useCallback as le } from "react";
|
|
3
|
+
import * as a from "d3";
|
|
4
|
+
import { feature as se } from "topojson-client";
|
|
5
|
+
import H from "world-atlas/land-110m.json";
|
|
6
|
+
const ie = se(H, H.objects.land), _ = {
|
|
7
|
+
naturalEarth: a.geoNaturalEarth1,
|
|
8
|
+
mercator: a.geoMercator,
|
|
9
|
+
equirectangular: a.geoEquirectangular
|
|
10
|
+
}, q = {
|
|
11
|
+
dark: {
|
|
12
|
+
bg: "#050b15",
|
|
13
|
+
bgGradient: ["#0a1628", "#050b15"],
|
|
14
|
+
land: "#1a2d4a",
|
|
15
|
+
landStroke: "#2a4060",
|
|
16
|
+
sphere: "#1e3a5f",
|
|
17
|
+
graticule: "#162a45",
|
|
18
|
+
graticuleOpacity: 0.35,
|
|
19
|
+
markerActive: "#cbd5e1",
|
|
20
|
+
markerInactive: "#64748b",
|
|
21
|
+
label: "#cbd5e1",
|
|
22
|
+
labelInactive: "#64748b",
|
|
23
|
+
arc: "#818cf8",
|
|
24
|
+
arcHighlight: "#c4b5fd",
|
|
25
|
+
arcDanger: "#f87171",
|
|
26
|
+
dot: "#a5b4fc",
|
|
27
|
+
dotDanger: "#f87171",
|
|
28
|
+
overlayFill: "rgba(248,113,113,0.10)",
|
|
29
|
+
overlayStroke: "rgba(248,113,113,0.30)"
|
|
30
|
+
},
|
|
31
|
+
light: {
|
|
32
|
+
bg: "#f8fafc",
|
|
33
|
+
bgGradient: ["#f8fafc", "#f1f5f9"],
|
|
34
|
+
land: "#e2e8f0",
|
|
35
|
+
landStroke: "#cbd5e1",
|
|
36
|
+
sphere: "#cbd5e1",
|
|
37
|
+
graticule: "#e2e8f0",
|
|
38
|
+
graticuleOpacity: 0.6,
|
|
39
|
+
markerActive: "#334155",
|
|
40
|
+
markerInactive: "#94a3b8",
|
|
41
|
+
label: "#334155",
|
|
42
|
+
labelInactive: "#94a3b8",
|
|
43
|
+
arc: "#6366f1",
|
|
44
|
+
arcHighlight: "#4f46e5",
|
|
45
|
+
arcDanger: "#ef4444",
|
|
46
|
+
dot: "#6366f1",
|
|
47
|
+
dotDanger: "#ef4444",
|
|
48
|
+
overlayFill: "rgba(239,68,68,0.08)",
|
|
49
|
+
overlayStroke: "rgba(239,68,68,0.3)"
|
|
50
|
+
}
|
|
51
|
+
};
|
|
52
|
+
function fe(s, i, k) {
|
|
53
|
+
return (_[s] ?? _.naturalEarth)().fitSize([i, k], { type: "Sphere" });
|
|
54
|
+
}
|
|
55
|
+
function he({
|
|
56
|
+
width: s = 960,
|
|
57
|
+
height: i = 480,
|
|
58
|
+
projection: k = "naturalEarth",
|
|
59
|
+
theme: D = "dark",
|
|
60
|
+
markers: G = [],
|
|
61
|
+
arcs: E = [],
|
|
62
|
+
overlays: T = [],
|
|
63
|
+
selectedId: v = null,
|
|
64
|
+
onArcClick: j,
|
|
65
|
+
onMarkerClick: z,
|
|
66
|
+
zoomable: x = !0,
|
|
67
|
+
minZoom: S = 1,
|
|
68
|
+
maxZoom: M = 8,
|
|
69
|
+
initialBounds: $ = null,
|
|
70
|
+
className: B = "",
|
|
71
|
+
children: N
|
|
72
|
+
}) {
|
|
73
|
+
const n = q[D] ?? q.dark, g = P(null), [d, J] = ce(a.zoomIdentity), b = P(null), { proj: l, pathGen: Y, graticulePath: K, spherePath: L, landPath: Q } = w(() => {
|
|
74
|
+
const e = fe(k, s, i), t = a.geoPath(e);
|
|
75
|
+
return {
|
|
76
|
+
proj: e,
|
|
77
|
+
pathGen: t,
|
|
78
|
+
graticulePath: t(a.geoGraticule10()),
|
|
79
|
+
spherePath: t({ type: "Sphere" }),
|
|
80
|
+
landPath: t(ie)
|
|
81
|
+
};
|
|
82
|
+
}, [k, s, i]);
|
|
83
|
+
F(() => {
|
|
84
|
+
if (!x || !g.current) return;
|
|
85
|
+
const e = a.select(g.current), t = a.zoom().scaleExtent([S, M]).on("zoom", (r) => J(r.transform));
|
|
86
|
+
return b.current = t, e.call(t), () => e.on(".zoom", null);
|
|
87
|
+
}, [x, S, M]);
|
|
88
|
+
const C = P(!1);
|
|
89
|
+
F(() => {
|
|
90
|
+
if (!$ || C.current || !g.current || !b.current || !l) return;
|
|
91
|
+
const { sw: e, ne: t, padding: r = 40 } = $, c = l(e), u = l(t);
|
|
92
|
+
if (!c || !u) return;
|
|
93
|
+
const m = Math.min(c[0], u[0]), h = Math.min(c[1], u[1]), y = Math.max(c[0], u[0]), W = Math.max(c[1], u[1]), O = y - m, A = W - h;
|
|
94
|
+
if (O < 1 || A < 1) return;
|
|
95
|
+
const I = Math.min((s - r * 2) / O, (i - r * 2) / A), ee = (m + y) / 2, te = (h + W) / 2, re = s / 2 - ee * I, ne = i / 2 - te * I, oe = Math.max(S, Math.min(M, I)), ae = a.zoomIdentity.translate(re, ne).scale(oe);
|
|
96
|
+
a.select(g.current).call(b.current.transform, ae), C.current = !0;
|
|
97
|
+
}, [$, l, s, i, S, M]);
|
|
98
|
+
const U = le(() => {
|
|
99
|
+
!g.current || !b.current || a.select(g.current).transition().duration(400).call(b.current.transform, a.zoomIdentity);
|
|
100
|
+
}, []), V = d.k !== 1 || d.x !== 0 || d.y !== 0, R = w(() => {
|
|
101
|
+
const e = {};
|
|
102
|
+
return E.forEach((t) => {
|
|
103
|
+
const r = `${t.from[0]},${t.from[1]}-${t.to[0]},${t.to[1]}`;
|
|
104
|
+
if (e[r]) {
|
|
105
|
+
t._path = e[r];
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
const c = a.geoInterpolate(t.from, t.to), u = [];
|
|
109
|
+
for (let h = 0; h <= 1; h += 0.02) {
|
|
110
|
+
const y = l(c(h));
|
|
111
|
+
y && u.push(y);
|
|
112
|
+
}
|
|
113
|
+
const m = u.length > 1 ? a.line()(u) : null;
|
|
114
|
+
e[r] = m, t._path = m;
|
|
115
|
+
}), E;
|
|
116
|
+
}, [E, l]), X = w(() => {
|
|
117
|
+
const e = /* @__PURE__ */ new Set();
|
|
118
|
+
return G.forEach((t) => {
|
|
119
|
+
t.active && e.add(t.id);
|
|
120
|
+
}), e;
|
|
121
|
+
}, [G]), Z = `translate(${d.x},${d.y}) scale(${d.k})`, f = 1 / d.k;
|
|
122
|
+
return /* @__PURE__ */ p("div", { className: `relative overflow-hidden ${B}`, style: { background: n.bg }, children: [
|
|
123
|
+
/* @__PURE__ */ p("svg", { ref: g, viewBox: `0 0 ${s} ${i}`, className: "h-full w-full", preserveAspectRatio: "xMidYMid slice", style: x ? { cursor: "grab" } : void 0, children: [
|
|
124
|
+
/* @__PURE__ */ p("defs", { children: [
|
|
125
|
+
/* @__PURE__ */ p("radialGradient", { id: "geo-bg", cx: "50%", cy: "50%", r: "55%", children: [
|
|
126
|
+
/* @__PURE__ */ o("stop", { offset: "0%", stopColor: n.bgGradient[0] }),
|
|
127
|
+
/* @__PURE__ */ o("stop", { offset: "100%", stopColor: n.bgGradient[1] })
|
|
128
|
+
] }),
|
|
129
|
+
/* @__PURE__ */ p("filter", { id: "geo-glow", x: "-50%", y: "-50%", width: "200%", height: "200%", children: [
|
|
130
|
+
/* @__PURE__ */ o("feGaussianBlur", { in: "SourceGraphic", stdDeviation: "3", result: "b" }),
|
|
131
|
+
/* @__PURE__ */ p("feMerge", { children: [
|
|
132
|
+
/* @__PURE__ */ o("feMergeNode", { in: "b" }),
|
|
133
|
+
/* @__PURE__ */ o("feMergeNode", { in: "SourceGraphic" })
|
|
134
|
+
] })
|
|
135
|
+
] })
|
|
136
|
+
] }),
|
|
137
|
+
/* @__PURE__ */ o("style", { children: `
|
|
138
|
+
.geo-arc{stroke-dasharray:8,6;animation:geo-flow 1.5s linear infinite}
|
|
139
|
+
@keyframes geo-flow{to{stroke-dashoffset:-14}}
|
|
140
|
+
.geo-dot{animation:geo-pulse 2s ease-in-out infinite}
|
|
141
|
+
@keyframes geo-pulse{0%,100%{opacity:1}50%{opacity:.5}}
|
|
142
|
+
` }),
|
|
143
|
+
/* @__PURE__ */ o("rect", { width: s, height: i, fill: "url(#geo-bg)" }),
|
|
144
|
+
/* @__PURE__ */ p("g", { transform: Z, children: [
|
|
145
|
+
/* @__PURE__ */ o("path", { d: L, fill: "none", stroke: n.sphere, strokeWidth: 0.8 * f }),
|
|
146
|
+
/* @__PURE__ */ o("path", { d: Q, fill: n.land, stroke: n.landStroke, strokeWidth: 0.4 * f }),
|
|
147
|
+
/* @__PURE__ */ o("path", { d: K, fill: "none", stroke: n.graticule, strokeWidth: 0.3 * f, opacity: n.graticuleOpacity }),
|
|
148
|
+
T.map((e) => {
|
|
149
|
+
const t = l(e.center);
|
|
150
|
+
if (!t) return null;
|
|
151
|
+
const r = l([e.center[0] + (e.radius ?? 5), e.center[1]]), c = r ? Math.abs(r[0] - t[0]) : 30;
|
|
152
|
+
return /* @__PURE__ */ o(
|
|
153
|
+
"circle",
|
|
154
|
+
{
|
|
155
|
+
cx: t[0],
|
|
156
|
+
cy: t[1],
|
|
157
|
+
r: c,
|
|
158
|
+
fill: e.fill ?? n.overlayFill,
|
|
159
|
+
stroke: e.stroke ?? n.overlayStroke,
|
|
160
|
+
strokeWidth: 1 * f,
|
|
161
|
+
strokeDasharray: "5,5",
|
|
162
|
+
className: "animate-pulse"
|
|
163
|
+
},
|
|
164
|
+
e.id
|
|
165
|
+
);
|
|
166
|
+
}),
|
|
167
|
+
R.map((e) => {
|
|
168
|
+
if (!e._path) return null;
|
|
169
|
+
const t = v === e.id, r = e.danger;
|
|
170
|
+
return /* @__PURE__ */ o(
|
|
171
|
+
"path",
|
|
172
|
+
{
|
|
173
|
+
d: e._path,
|
|
174
|
+
fill: "none",
|
|
175
|
+
stroke: r ? n.arcDanger : t ? n.arcHighlight : e.color ?? n.arc,
|
|
176
|
+
strokeWidth: (t ? 3 : 2) * f,
|
|
177
|
+
opacity: v != null && !t ? 0.15 : r ? 0.85 : 0.65,
|
|
178
|
+
className: "geo-arc cursor-pointer",
|
|
179
|
+
onClick: () => j?.(e)
|
|
180
|
+
},
|
|
181
|
+
`arc-${e.id}`
|
|
182
|
+
);
|
|
183
|
+
}),
|
|
184
|
+
G.map((e) => {
|
|
185
|
+
const t = l([e.lon, e.lat]);
|
|
186
|
+
if (!t) return null;
|
|
187
|
+
const r = e.active ?? X.has(e.id);
|
|
188
|
+
return /* @__PURE__ */ p("g", { className: z ? "cursor-pointer" : "", onClick: () => z?.(e), children: [
|
|
189
|
+
/* @__PURE__ */ o("circle", { cx: t[0], cy: t[1], r: (r ? 3 : 2) * f, fill: r ? n.markerActive : n.markerInactive }),
|
|
190
|
+
e.label !== !1 && /* @__PURE__ */ o("text", { x: t[0] + 6 * f, y: t[1] + 4 * f, fontSize: 8 * f, fill: r ? n.label : n.labelInactive, fontFamily: "sans-serif", fontWeight: 600, children: e.label ?? e.id })
|
|
191
|
+
] }, e.id);
|
|
192
|
+
}),
|
|
193
|
+
R.map((e) => {
|
|
194
|
+
if (e.progress == null || e.progress <= 0) return null;
|
|
195
|
+
const t = a.geoInterpolate(e.from, e.to), r = l(t(Math.min(e.progress, 0.99)));
|
|
196
|
+
if (!r) return null;
|
|
197
|
+
const c = v === e.id;
|
|
198
|
+
return /* @__PURE__ */ o(
|
|
199
|
+
"circle",
|
|
200
|
+
{
|
|
201
|
+
cx: r[0],
|
|
202
|
+
cy: r[1],
|
|
203
|
+
r: (c ? 6 : 4.5) * f,
|
|
204
|
+
fill: e.danger ? n.dotDanger : e.dotColor ?? n.dot,
|
|
205
|
+
filter: "url(#geo-glow)",
|
|
206
|
+
className: "geo-dot cursor-pointer",
|
|
207
|
+
opacity: v != null && !c ? 0.3 : 1,
|
|
208
|
+
onClick: () => j?.(e)
|
|
209
|
+
},
|
|
210
|
+
`dot-${e.id}`
|
|
211
|
+
);
|
|
212
|
+
}),
|
|
213
|
+
typeof N == "function" ? N({ proj: l, pathGen: Y, theme: n, width: s, height: i, transform: d }) : N
|
|
214
|
+
] })
|
|
215
|
+
] }),
|
|
216
|
+
x && V && /* @__PURE__ */ o(
|
|
217
|
+
"button",
|
|
218
|
+
{
|
|
219
|
+
onClick: U,
|
|
220
|
+
className: "absolute bottom-3 right-3 rounded-lg border border-white/15 bg-black/50 px-2.5 py-1.5 text-[11px] font-medium text-white/80 backdrop-blur-md transition hover:bg-black/70 hover:text-white",
|
|
221
|
+
children: "Reset view"
|
|
222
|
+
}
|
|
223
|
+
)
|
|
224
|
+
] });
|
|
225
|
+
}
|
|
226
|
+
export {
|
|
227
|
+
he as default
|
|
228
|
+
};
|
|
229
|
+
//# sourceMappingURL=GeoMap.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GeoMap.js","sources":["../../../../src/components/library/charts/GeoMap.jsx"],"sourcesContent":["import React, { useMemo, useRef, useEffect, useState, useCallback } from \"react\";\nimport * as d3 from \"d3\";\nimport { feature } from \"topojson-client\";\nimport world from \"world-atlas/land-110m.json\";\n\nconst land = feature(world, world.objects.land);\n\nconst PROJECTIONS = {\n naturalEarth: d3.geoNaturalEarth1,\n mercator: d3.geoMercator,\n equirectangular: d3.geoEquirectangular,\n};\n\nconst THEMES = {\n dark: {\n bg: \"#050b15\",\n bgGradient: [\"#0a1628\", \"#050b15\"],\n land: \"#1a2d4a\",\n landStroke: \"#2a4060\",\n sphere: \"#1e3a5f\",\n graticule: \"#162a45\",\n graticuleOpacity: 0.35,\n markerActive: \"#cbd5e1\",\n markerInactive: \"#64748b\",\n label: \"#cbd5e1\",\n labelInactive: \"#64748b\",\n arc: \"#818cf8\",\n arcHighlight: \"#c4b5fd\",\n arcDanger: \"#f87171\",\n dot: \"#a5b4fc\",\n dotDanger: \"#f87171\",\n overlayFill: \"rgba(248,113,113,0.10)\",\n overlayStroke: \"rgba(248,113,113,0.30)\",\n },\n light: {\n bg: \"#f8fafc\",\n bgGradient: [\"#f8fafc\", \"#f1f5f9\"],\n land: \"#e2e8f0\",\n landStroke: \"#cbd5e1\",\n sphere: \"#cbd5e1\",\n graticule: \"#e2e8f0\",\n graticuleOpacity: 0.6,\n markerActive: \"#334155\",\n markerInactive: \"#94a3b8\",\n label: \"#334155\",\n labelInactive: \"#94a3b8\",\n arc: \"#6366f1\",\n arcHighlight: \"#4f46e5\",\n arcDanger: \"#ef4444\",\n dot: \"#6366f1\",\n dotDanger: \"#ef4444\",\n overlayFill: \"rgba(239,68,68,0.08)\",\n overlayStroke: \"rgba(239,68,68,0.3)\",\n },\n};\n\nfunction buildProjection(type, width, height) {\n const factory = PROJECTIONS[type] ?? PROJECTIONS.naturalEarth;\n return factory().fitSize([width, height], { type: \"Sphere\" });\n}\n\nexport default function GeoMap({\n width = 960,\n height = 480,\n projection: projType = \"naturalEarth\",\n theme = \"dark\",\n markers = [],\n arcs = [],\n overlays = [],\n selectedId = null,\n onArcClick,\n onMarkerClick,\n zoomable = true,\n minZoom = 1,\n maxZoom = 8,\n initialBounds = null,\n className = \"\",\n children,\n}) {\n const t = THEMES[theme] ?? THEMES.dark;\n const svgRef = useRef(null);\n const [transform, setTransform] = useState(d3.zoomIdentity);\n const zoomRef = useRef(null);\n\n const { proj, pathGen, graticulePath, spherePath, landPath } = useMemo(() => {\n const proj = buildProjection(projType, width, height);\n const pathGen = d3.geoPath(proj);\n return {\n proj,\n pathGen,\n graticulePath: pathGen(d3.geoGraticule10()),\n spherePath: pathGen({ type: \"Sphere\" }),\n landPath: pathGen(land),\n };\n }, [projType, width, height]);\n\n // D3 zoom behavior\n useEffect(() => {\n if (!zoomable || !svgRef.current) return;\n const svg = d3.select(svgRef.current);\n const zoom = d3.zoom()\n .scaleExtent([minZoom, maxZoom])\n .on(\"zoom\", (e) => setTransform(e.transform));\n zoomRef.current = zoom;\n svg.call(zoom);\n return () => svg.on(\".zoom\", null);\n }, [zoomable, minZoom, maxZoom]);\n\n // Apply initial zoom to fit bounds (markers/region) on mount\n const initialBoundsApplied = useRef(false);\n useEffect(() => {\n if (!initialBounds || initialBoundsApplied.current) return;\n if (!svgRef.current || !zoomRef.current || !proj) return;\n const { sw, ne, padding = 40 } = initialBounds; // sw=[lonMin,latMin], ne=[lonMax,latMax]\n const p0 = proj(sw);\n const p1 = proj(ne);\n if (!p0 || !p1) return;\n const bx0 = Math.min(p0[0], p1[0]);\n const by0 = Math.min(p0[1], p1[1]);\n const bx1 = Math.max(p0[0], p1[0]);\n const by1 = Math.max(p0[1], p1[1]);\n const bw = bx1 - bx0;\n const bh = by1 - by0;\n if (bw < 1 || bh < 1) return;\n const scale = Math.min((width - padding * 2) / bw, (height - padding * 2) / bh);\n const cx = (bx0 + bx1) / 2;\n const cy = (by0 + by1) / 2;\n const tx = width / 2 - cx * scale;\n const ty = height / 2 - cy * scale;\n const clampedScale = Math.max(minZoom, Math.min(maxZoom, scale));\n const t = d3.zoomIdentity.translate(tx, ty).scale(clampedScale);\n d3.select(svgRef.current).call(zoomRef.current.transform, t);\n initialBoundsApplied.current = true;\n }, [initialBounds, proj, width, height, minZoom, maxZoom]);\n\n const resetZoom = useCallback(() => {\n if (!svgRef.current || !zoomRef.current) return;\n d3.select(svgRef.current)\n .transition()\n .duration(400)\n .call(zoomRef.current.transform, d3.zoomIdentity);\n }, []);\n\n const isZoomed = transform.k !== 1 || transform.x !== 0 || transform.y !== 0;\n\n const arcPaths = useMemo(() => {\n const cache = {};\n arcs.forEach(a => {\n const key = `${a.from[0]},${a.from[1]}-${a.to[0]},${a.to[1]}`;\n if (cache[key]) { a._path = cache[key]; return; }\n const interp = d3.geoInterpolate(a.from, a.to);\n const pts = [];\n for (let i = 0; i <= 1; i += 0.02) {\n const p = proj(interp(i));\n if (p) pts.push(p);\n }\n const path = pts.length > 1 ? d3.line()(pts) : null;\n cache[key] = path;\n a._path = path;\n });\n return arcs;\n }, [arcs, proj]);\n\n const activeMarkerIds = useMemo(() => {\n const s = new Set();\n markers.forEach(m => { if (m.active) s.add(m.id); });\n return s;\n }, [markers]);\n\n const txStr = `translate(${transform.x},${transform.y}) scale(${transform.k})`;\n const invScale = 1 / transform.k;\n\n return (\n <div className={`relative overflow-hidden ${className}`} style={{ background: t.bg }}>\n <svg ref={svgRef} viewBox={`0 0 ${width} ${height}`} className=\"h-full w-full\" preserveAspectRatio=\"xMidYMid slice\" style={zoomable ? { cursor: \"grab\" } : undefined}>\n <defs>\n <radialGradient id=\"geo-bg\" cx=\"50%\" cy=\"50%\" r=\"55%\">\n <stop offset=\"0%\" stopColor={t.bgGradient[0]} />\n <stop offset=\"100%\" stopColor={t.bgGradient[1]} />\n </radialGradient>\n <filter id=\"geo-glow\" x=\"-50%\" y=\"-50%\" width=\"200%\" height=\"200%\">\n <feGaussianBlur in=\"SourceGraphic\" stdDeviation=\"3\" result=\"b\" />\n <feMerge><feMergeNode in=\"b\" /><feMergeNode in=\"SourceGraphic\" /></feMerge>\n </filter>\n </defs>\n <style>{`\n .geo-arc{stroke-dasharray:8,6;animation:geo-flow 1.5s linear infinite}\n @keyframes geo-flow{to{stroke-dashoffset:-14}}\n .geo-dot{animation:geo-pulse 2s ease-in-out infinite}\n @keyframes geo-pulse{0%,100%{opacity:1}50%{opacity:.5}}\n `}</style>\n\n <rect width={width} height={height} fill=\"url(#geo-bg)\" />\n\n {/* Zoomable content group */}\n <g transform={txStr}>\n <path d={spherePath} fill=\"none\" stroke={t.sphere} strokeWidth={0.8 * invScale} />\n <path d={landPath} fill={t.land} stroke={t.landStroke} strokeWidth={0.4 * invScale} />\n <path d={graticulePath} fill=\"none\" stroke={t.graticule} strokeWidth={0.3 * invScale} opacity={t.graticuleOpacity} />\n\n {/* Overlay zones (disruptions, weather) */}\n {overlays.map(o => {\n const c = proj(o.center);\n if (!c) return null;\n const edge = proj([o.center[0] + (o.radius ?? 5), o.center[1]]);\n const r = edge ? Math.abs(edge[0] - c[0]) : 30;\n return (\n <circle\n key={o.id}\n cx={c[0]} cy={c[1]} r={r}\n fill={o.fill ?? t.overlayFill}\n stroke={o.stroke ?? t.overlayStroke}\n strokeWidth={1 * invScale}\n strokeDasharray=\"5,5\"\n className=\"animate-pulse\"\n />\n );\n })}\n\n {/* Arcs */}\n {arcPaths.map(a => {\n if (!a._path) return null;\n const sel = selectedId === a.id;\n const danger = a.danger;\n return (\n <path\n key={`arc-${a.id}`}\n d={a._path}\n fill=\"none\"\n stroke={danger ? t.arcDanger : sel ? t.arcHighlight : a.color ?? t.arc}\n strokeWidth={(sel ? 3 : 2) * invScale}\n opacity={selectedId != null && !sel ? 0.15 : danger ? 0.85 : 0.65}\n className=\"geo-arc cursor-pointer\"\n onClick={() => onArcClick?.(a)}\n />\n );\n })}\n\n {/* Markers */}\n {markers.map(m => {\n const p = proj([m.lon, m.lat]);\n if (!p) return null;\n const active = m.active ?? activeMarkerIds.has(m.id);\n return (\n <g key={m.id} className={onMarkerClick ? \"cursor-pointer\" : \"\"} onClick={() => onMarkerClick?.(m)}>\n <circle cx={p[0]} cy={p[1]} r={(active ? 3 : 2) * invScale} fill={active ? t.markerActive : t.markerInactive} />\n {m.label !== false && (\n <text x={p[0] + 6 * invScale} y={p[1] + 4 * invScale} fontSize={8 * invScale} fill={active ? t.label : t.labelInactive} fontFamily=\"sans-serif\" fontWeight={600}>\n {m.label ?? m.id}\n </text>\n )}\n </g>\n );\n })}\n\n {/* Moving dots (flight positions) */}\n {arcPaths.map(a => {\n if (a.progress == null || a.progress <= 0) return null;\n const interp = d3.geoInterpolate(a.from, a.to);\n const p = proj(interp(Math.min(a.progress, 0.99)));\n if (!p) return null;\n const sel = selectedId === a.id;\n return (\n <circle\n key={`dot-${a.id}`}\n cx={p[0]} cy={p[1]}\n r={(sel ? 6 : 4.5) * invScale}\n fill={a.danger ? t.dotDanger : a.dotColor ?? t.dot}\n filter=\"url(#geo-glow)\"\n className=\"geo-dot cursor-pointer\"\n opacity={selectedId != null && !sel ? 0.3 : 1}\n onClick={() => onArcClick?.(a)}\n />\n );\n })}\n\n {/* Custom children get access to projection */}\n {typeof children === \"function\" ? children({ proj, pathGen, theme: t, width, height, transform }) : children}\n </g>\n </svg>\n\n {/* Reset zoom button */}\n {zoomable && isZoomed && (\n <button\n onClick={resetZoom}\n className=\"absolute bottom-3 right-3 rounded-lg border border-white/15 bg-black/50 px-2.5 py-1.5 text-[11px] font-medium text-white/80 backdrop-blur-md transition hover:bg-black/70 hover:text-white\"\n >\n Reset view\n </button>\n )}\n </div>\n );\n}\n"],"names":["land","feature","world","PROJECTIONS","d3","THEMES","buildProjection","type","width","height","GeoMap","projType","theme","markers","arcs","overlays","selectedId","onArcClick","onMarkerClick","zoomable","minZoom","maxZoom","initialBounds","className","children","t","svgRef","useRef","transform","setTransform","useState","zoomRef","proj","pathGen","graticulePath","spherePath","landPath","useMemo","useEffect","svg","zoom","e","initialBoundsApplied","sw","ne","padding","p0","p1","bx0","by0","bx1","by1","bw","bh","scale","cx","cy","tx","ty","clampedScale","resetZoom","useCallback","isZoomed","arcPaths","cache","a","key","interp","pts","i","p","path","activeMarkerIds","s","m","txStr","invScale","jsxs","jsx","o","c","edge","r","sel","danger","active"],"mappings":"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"}
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { jsx as e, jsxs as r, Fragment as x } from "react/jsx-runtime";
|
|
2
|
+
import { useState as m, useRef as I, useCallback as K, useEffect as d } from "react";
|
|
3
|
+
import { createPortal as M } from "react-dom";
|
|
4
|
+
import { AnimatePresence as P, motion as f } from "framer-motion";
|
|
5
|
+
import { SparklesIcon as i, ArrowTopRightOnSquareIcon as R, TrashIcon as O, XMarkIcon as V } from "@heroicons/react/24/outline";
|
|
6
|
+
import B from "./ChatMessageList.js";
|
|
7
|
+
import T from "./ChatInput.js";
|
|
8
|
+
import q from "./useChatState.js";
|
|
9
|
+
const z = {
|
|
10
|
+
hidden: { opacity: 0 },
|
|
11
|
+
visible: { opacity: 1, transition: { duration: 0.15 } },
|
|
12
|
+
exit: { opacity: 0, transition: { duration: 0.12 } }
|
|
13
|
+
}, D = {
|
|
14
|
+
hidden: { opacity: 0, y: 20, scale: 0.97 },
|
|
15
|
+
visible: {
|
|
16
|
+
opacity: 1,
|
|
17
|
+
y: 0,
|
|
18
|
+
scale: 1,
|
|
19
|
+
transition: { type: "spring", damping: 28, stiffness: 380 }
|
|
20
|
+
},
|
|
21
|
+
exit: { opacity: 0, y: 10, scale: 0.97, transition: { duration: 0.12 } }
|
|
22
|
+
};
|
|
23
|
+
function Y({
|
|
24
|
+
onSend: p,
|
|
25
|
+
suggestions: c = [],
|
|
26
|
+
placeholder: h = "Ask a question…",
|
|
27
|
+
title: g = "AI Assistant",
|
|
28
|
+
initialMessages: k = [],
|
|
29
|
+
className: v = "",
|
|
30
|
+
panelHeight: H,
|
|
31
|
+
renderAvatar: y,
|
|
32
|
+
onOpenInTab: u
|
|
33
|
+
}) {
|
|
34
|
+
const [s, n] = m(!1), [N, b] = m(!1), w = I(null), t = q({ initialMessages: k, onSend: p }), C = t.messages.length === 0, o = K(() => n(!1), []);
|
|
35
|
+
d(() => {
|
|
36
|
+
s && b(!0);
|
|
37
|
+
}, [s]), d(() => {
|
|
38
|
+
function a(l) {
|
|
39
|
+
(l.metaKey || l.ctrlKey) && l.key === "k" && (l.preventDefault(), n((E) => !E)), l.key === "Escape" && s && o();
|
|
40
|
+
}
|
|
41
|
+
return document.addEventListener("keydown", a), () => document.removeEventListener("keydown", a);
|
|
42
|
+
}, [s, o]), d(() => (s ? document.body.style.overflow = "hidden" : document.body.style.overflow = "", () => {
|
|
43
|
+
document.body.style.overflow = "";
|
|
44
|
+
}), [s]);
|
|
45
|
+
function A(a) {
|
|
46
|
+
s || n(!0), t.sendMessage(a);
|
|
47
|
+
}
|
|
48
|
+
const [S, L] = m("⌘K");
|
|
49
|
+
d(() => {
|
|
50
|
+
L(/Mac|iPhone|iPad/.test(navigator.userAgent) ? "⌘K" : "Ctrl K");
|
|
51
|
+
}, []);
|
|
52
|
+
const j = typeof document < "u" && N ? M(
|
|
53
|
+
/* @__PURE__ */ e(P, { onExitComplete: () => b(!1), children: s && /* @__PURE__ */ r(x, { children: [
|
|
54
|
+
/* @__PURE__ */ e(
|
|
55
|
+
f.div,
|
|
56
|
+
{
|
|
57
|
+
variants: z,
|
|
58
|
+
initial: "hidden",
|
|
59
|
+
animate: "visible",
|
|
60
|
+
exit: "exit",
|
|
61
|
+
className: "fixed inset-0 z-50 bg-black/30 backdrop-blur-sm",
|
|
62
|
+
onClick: o,
|
|
63
|
+
"aria-hidden": "true"
|
|
64
|
+
}
|
|
65
|
+
),
|
|
66
|
+
/* @__PURE__ */ r(
|
|
67
|
+
f.div,
|
|
68
|
+
{
|
|
69
|
+
ref: w,
|
|
70
|
+
variants: D,
|
|
71
|
+
initial: "hidden",
|
|
72
|
+
animate: "visible",
|
|
73
|
+
exit: "exit",
|
|
74
|
+
className: "fixed inset-x-0 top-[10vh] z-50 mx-auto flex w-full max-w-4xl flex-col overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-2xl dark:border-slate-700 dark:bg-slate-900",
|
|
75
|
+
style: { maxHeight: "75vh" },
|
|
76
|
+
children: [
|
|
77
|
+
/* @__PURE__ */ r("div", { className: "flex items-center justify-between border-b border-slate-100 px-4 py-2.5 dark:border-slate-800", children: [
|
|
78
|
+
/* @__PURE__ */ r("div", { className: "flex items-center gap-2", children: [
|
|
79
|
+
/* @__PURE__ */ e(i, { className: "h-4 w-4 text-brand-500" }),
|
|
80
|
+
/* @__PURE__ */ e("h3", { className: "text-sm font-semibold text-slate-900 dark:text-slate-50", children: g })
|
|
81
|
+
] }),
|
|
82
|
+
/* @__PURE__ */ r("div", { className: "flex items-center gap-1", children: [
|
|
83
|
+
u ? /* @__PURE__ */ e(
|
|
84
|
+
"button",
|
|
85
|
+
{
|
|
86
|
+
type: "button",
|
|
87
|
+
onClick: () => {
|
|
88
|
+
n(!1), b(!1), document.body.style.overflow = "", u(t.messages);
|
|
89
|
+
},
|
|
90
|
+
className: "rounded p-1 text-slate-400 transition hover:bg-slate-100 hover:text-slate-600 dark:text-slate-500 dark:hover:bg-slate-800 dark:hover:text-slate-300",
|
|
91
|
+
"aria-label": "Open in new tab",
|
|
92
|
+
title: "Open in new tab",
|
|
93
|
+
children: /* @__PURE__ */ e(R, { className: "h-4 w-4" })
|
|
94
|
+
}
|
|
95
|
+
) : null,
|
|
96
|
+
t.messages.length > 0 ? /* @__PURE__ */ e(
|
|
97
|
+
"button",
|
|
98
|
+
{
|
|
99
|
+
type: "button",
|
|
100
|
+
onClick: t.clearMessages,
|
|
101
|
+
className: "rounded p-1 text-slate-400 transition hover:bg-slate-100 hover:text-slate-600 dark:text-slate-500 dark:hover:bg-slate-800 dark:hover:text-slate-300",
|
|
102
|
+
"aria-label": "Clear chat",
|
|
103
|
+
children: /* @__PURE__ */ e(O, { className: "h-4 w-4" })
|
|
104
|
+
}
|
|
105
|
+
) : null,
|
|
106
|
+
/* @__PURE__ */ e(
|
|
107
|
+
"button",
|
|
108
|
+
{
|
|
109
|
+
type: "button",
|
|
110
|
+
onClick: o,
|
|
111
|
+
className: "rounded p-1 text-slate-400 transition hover:bg-slate-100 hover:text-slate-600 dark:text-slate-500 dark:hover:bg-slate-800 dark:hover:text-slate-300",
|
|
112
|
+
"aria-label": "Close",
|
|
113
|
+
children: /* @__PURE__ */ e(V, { className: "h-4 w-4" })
|
|
114
|
+
}
|
|
115
|
+
),
|
|
116
|
+
/* @__PURE__ */ e("kbd", { className: "ml-1 hidden rounded border border-slate-200 bg-slate-50 px-1.5 py-0.5 text-[10px] font-medium text-slate-400 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-500 sm:inline-block", children: "esc" })
|
|
117
|
+
] })
|
|
118
|
+
] }),
|
|
119
|
+
/* @__PURE__ */ e("div", { className: "min-h-0 flex-1", children: C ? /* @__PURE__ */ r("div", { className: "flex h-full min-h-[200px] flex-col items-center justify-center gap-4 px-6 py-8", children: [
|
|
120
|
+
/* @__PURE__ */ e("div", { className: "flex h-10 w-10 items-center justify-center rounded-full bg-brand-50 dark:bg-brand-950/30", children: /* @__PURE__ */ e(i, { className: "h-5 w-5 text-brand-500" }) }),
|
|
121
|
+
/* @__PURE__ */ e("p", { className: "text-sm text-slate-500 dark:text-slate-400", children: "Ask me anything about your data." }),
|
|
122
|
+
c.length > 0 ? /* @__PURE__ */ e("div", { className: "flex flex-wrap justify-center gap-2", children: c.map((a) => /* @__PURE__ */ r(
|
|
123
|
+
"button",
|
|
124
|
+
{
|
|
125
|
+
type: "button",
|
|
126
|
+
onClick: () => A(a),
|
|
127
|
+
className: "inline-flex items-center gap-1.5 rounded-full border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-600 shadow-sm transition hover:border-brand-300 hover:bg-brand-50 hover:text-brand-700 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300 dark:hover:border-brand-700 dark:hover:bg-brand-950/30 dark:hover:text-brand-300",
|
|
128
|
+
children: [
|
|
129
|
+
/* @__PURE__ */ e(
|
|
130
|
+
i,
|
|
131
|
+
{
|
|
132
|
+
className: "h-3 w-3",
|
|
133
|
+
"aria-hidden": "true"
|
|
134
|
+
}
|
|
135
|
+
),
|
|
136
|
+
a
|
|
137
|
+
]
|
|
138
|
+
},
|
|
139
|
+
a
|
|
140
|
+
)) }) : null
|
|
141
|
+
] }) : /* @__PURE__ */ e(
|
|
142
|
+
B,
|
|
143
|
+
{
|
|
144
|
+
messages: t.messages,
|
|
145
|
+
isLoading: t.isLoading,
|
|
146
|
+
isStreaming: t.isStreaming,
|
|
147
|
+
suggestions: c,
|
|
148
|
+
onSuggestion: (a) => t.sendMessage(a),
|
|
149
|
+
renderAvatar: y
|
|
150
|
+
}
|
|
151
|
+
) }),
|
|
152
|
+
/* @__PURE__ */ e("div", { className: "border-t border-slate-100 p-3 dark:border-slate-800", children: /* @__PURE__ */ e(
|
|
153
|
+
T,
|
|
154
|
+
{
|
|
155
|
+
onSend: (a) => t.sendMessage(a),
|
|
156
|
+
disabled: t.isLoading,
|
|
157
|
+
isLoading: t.isLoading,
|
|
158
|
+
placeholder: h
|
|
159
|
+
}
|
|
160
|
+
) })
|
|
161
|
+
]
|
|
162
|
+
}
|
|
163
|
+
)
|
|
164
|
+
] }) }),
|
|
165
|
+
document.body
|
|
166
|
+
) : null;
|
|
167
|
+
return /* @__PURE__ */ r(x, { children: [
|
|
168
|
+
j,
|
|
169
|
+
/* @__PURE__ */ r(
|
|
170
|
+
"button",
|
|
171
|
+
{
|
|
172
|
+
type: "button",
|
|
173
|
+
onClick: () => n(!0),
|
|
174
|
+
className: [
|
|
175
|
+
"group flex w-full items-center gap-3 rounded-xl border border-slate-200 bg-white px-4 py-2.5 text-left shadow-sm transition-all hover:border-brand-300 hover:shadow-md focus:outline-none focus:ring-2 focus:ring-brand-500/20 dark:border-slate-800 dark:bg-slate-900 dark:hover:border-brand-700",
|
|
176
|
+
v
|
|
177
|
+
].filter(Boolean).join(" "),
|
|
178
|
+
children: [
|
|
179
|
+
/* @__PURE__ */ e(i, { className: "h-5 w-5 shrink-0 text-brand-500" }),
|
|
180
|
+
/* @__PURE__ */ e("span", { className: "flex-1 text-sm text-slate-400 dark:text-slate-500", children: h }),
|
|
181
|
+
t.messages.length > 0 ? /* @__PURE__ */ r("span", { className: "rounded-full bg-brand-50 px-2 py-0.5 text-xs font-medium text-brand-600 dark:bg-brand-950/30 dark:text-brand-400", children: [
|
|
182
|
+
t.messages.length,
|
|
183
|
+
" msgs"
|
|
184
|
+
] }) : null,
|
|
185
|
+
/* @__PURE__ */ e("kbd", { className: "hidden rounded border border-slate-200 bg-slate-50 px-1.5 py-0.5 text-[10px] font-medium text-slate-400 group-hover:border-brand-200 group-hover:text-brand-500 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-500 sm:inline-block", children: S })
|
|
186
|
+
]
|
|
187
|
+
}
|
|
188
|
+
)
|
|
189
|
+
] });
|
|
190
|
+
}
|
|
191
|
+
export {
|
|
192
|
+
Y as default
|
|
193
|
+
};
|
|
194
|
+
//# sourceMappingURL=ChatBar.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ChatBar.js","sources":["../../../../src/components/library/chat/ChatBar.jsx"],"sourcesContent":["import React, { useState, useRef, useEffect, useCallback } from \"react\";\nimport { createPortal } from \"react-dom\";\nimport { AnimatePresence, motion } from \"framer-motion\";\nimport {\n SparklesIcon,\n XMarkIcon,\n TrashIcon,\n ArrowTopRightOnSquareIcon,\n} from \"@heroicons/react/24/outline\";\nimport ChatMessageList from \"./ChatMessageList\";\nimport ChatInput from \"./ChatInput\";\nimport useChatState from \"./useChatState\";\n\nconst BACKDROP_VARIANTS = {\n hidden: { opacity: 0 },\n visible: { opacity: 1, transition: { duration: 0.15 } },\n exit: { opacity: 0, transition: { duration: 0.12 } },\n};\n\nconst PANEL_VARIANTS = {\n hidden: { opacity: 0, y: 20, scale: 0.97 },\n visible: {\n opacity: 1,\n y: 0,\n scale: 1,\n transition: { type: \"spring\", damping: 28, stiffness: 380 },\n },\n exit: { opacity: 0, y: 10, scale: 0.97, transition: { duration: 0.12 } },\n};\n\n/**\n * Command-palette style AI chat bar.\n *\n * Collapsed: a slim, clickable input strip with sparkle icon and ⌘K hint.\n * Expanded: a centered floating overlay (portal) with backdrop, full chat,\n * suggestions, and message history. No layout shift.\n *\n * Activate: click the bar, press ⌘K / Ctrl+K, or click a suggestion chip.\n * Dismiss: Escape or click the backdrop.\n */\nexport default function ChatBar({\n onSend,\n suggestions = [],\n placeholder = \"Ask a question\\u2026\",\n title = \"AI Assistant\",\n initialMessages = [],\n className = \"\",\n panelHeight,\n renderAvatar,\n onOpenInTab,\n}) {\n const [open, setOpen] = useState(false);\n const [portalVisible, setPortalVisible] = useState(false);\n const panelRef = useRef(null);\n const chat = useChatState({ initialMessages, onSend });\n const isEmpty = chat.messages.length === 0;\n\n const close = useCallback(() => setOpen(false), []);\n\n useEffect(() => {\n if (open) setPortalVisible(true);\n }, [open]);\n\n useEffect(() => {\n function onKey(e) {\n if ((e.metaKey || e.ctrlKey) && e.key === \"k\") {\n e.preventDefault();\n setOpen((prev) => !prev);\n }\n if (e.key === \"Escape\" && open) close();\n }\n document.addEventListener(\"keydown\", onKey);\n return () => document.removeEventListener(\"keydown\", onKey);\n }, [open, close]);\n\n useEffect(() => {\n if (open) document.body.style.overflow = \"hidden\";\n else document.body.style.overflow = \"\";\n return () => { document.body.style.overflow = \"\"; };\n }, [open]);\n\n function handleSend(content) {\n if (!open) setOpen(true);\n chat.sendMessage(content);\n }\n\n const [shortcutLabel, setShortcutLabel] = useState(\"⌘K\");\n useEffect(() => {\n setShortcutLabel(/Mac|iPhone|iPad/.test(navigator.userAgent) ? \"⌘K\" : \"Ctrl K\");\n }, []);\n\n const overlay =\n typeof document !== \"undefined\" && portalVisible\n ? createPortal(\n <AnimatePresence onExitComplete={() => setPortalVisible(false)}>\n {open && (\n <>\n {/* Backdrop */}\n <motion.div\n variants={BACKDROP_VARIANTS}\n initial=\"hidden\"\n animate=\"visible\"\n exit=\"exit\"\n className=\"fixed inset-0 z-50 bg-black/30 backdrop-blur-sm\"\n onClick={close}\n aria-hidden=\"true\"\n />\n\n {/* Centered panel */}\n <motion.div\n ref={panelRef}\n variants={PANEL_VARIANTS}\n initial=\"hidden\"\n animate=\"visible\"\n exit=\"exit\"\n className=\"fixed inset-x-0 top-[10vh] z-50 mx-auto flex w-full max-w-4xl flex-col overflow-hidden rounded-2xl border border-slate-200 bg-white shadow-2xl dark:border-slate-700 dark:bg-slate-900\"\n style={{ maxHeight: \"75vh\" }}\n >\n {/* Header */}\n <div className=\"flex items-center justify-between border-b border-slate-100 px-4 py-2.5 dark:border-slate-800\">\n <div className=\"flex items-center gap-2\">\n <SparklesIcon className=\"h-4 w-4 text-brand-500\" />\n <h3 className=\"text-sm font-semibold text-slate-900 dark:text-slate-50\">\n {title}\n </h3>\n </div>\n <div className=\"flex items-center gap-1\">\n {onOpenInTab ? (\n <button\n type=\"button\"\n onClick={() => {\n setOpen(false);\n setPortalVisible(false);\n document.body.style.overflow = \"\";\n onOpenInTab(chat.messages);\n }}\n className=\"rounded p-1 text-slate-400 transition hover:bg-slate-100 hover:text-slate-600 dark:text-slate-500 dark:hover:bg-slate-800 dark:hover:text-slate-300\"\n aria-label=\"Open in new tab\"\n title=\"Open in new tab\"\n >\n <ArrowTopRightOnSquareIcon className=\"h-4 w-4\" />\n </button>\n ) : null}\n {chat.messages.length > 0 ? (\n <button\n type=\"button\"\n onClick={chat.clearMessages}\n className=\"rounded p-1 text-slate-400 transition hover:bg-slate-100 hover:text-slate-600 dark:text-slate-500 dark:hover:bg-slate-800 dark:hover:text-slate-300\"\n aria-label=\"Clear chat\"\n >\n <TrashIcon className=\"h-4 w-4\" />\n </button>\n ) : null}\n <button\n type=\"button\"\n onClick={close}\n className=\"rounded p-1 text-slate-400 transition hover:bg-slate-100 hover:text-slate-600 dark:text-slate-500 dark:hover:bg-slate-800 dark:hover:text-slate-300\"\n aria-label=\"Close\"\n >\n <XMarkIcon className=\"h-4 w-4\" />\n </button>\n <kbd className=\"ml-1 hidden rounded border border-slate-200 bg-slate-50 px-1.5 py-0.5 text-[10px] font-medium text-slate-400 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-500 sm:inline-block\">\n esc\n </kbd>\n </div>\n </div>\n\n {/* Body — messages or empty state */}\n <div className=\"min-h-0 flex-1\">\n {isEmpty ? (\n <div className=\"flex h-full min-h-[200px] flex-col items-center justify-center gap-4 px-6 py-8\">\n <div className=\"flex h-10 w-10 items-center justify-center rounded-full bg-brand-50 dark:bg-brand-950/30\">\n <SparklesIcon className=\"h-5 w-5 text-brand-500\" />\n </div>\n <p className=\"text-sm text-slate-500 dark:text-slate-400\">\n Ask me anything about your data.\n </p>\n {suggestions.length > 0 ? (\n <div className=\"flex flex-wrap justify-center gap-2\">\n {suggestions.map((text) => (\n <button\n key={text}\n type=\"button\"\n onClick={() => handleSend(text)}\n className=\"inline-flex items-center gap-1.5 rounded-full border border-slate-200 bg-white px-3 py-1.5 text-xs font-medium text-slate-600 shadow-sm transition hover:border-brand-300 hover:bg-brand-50 hover:text-brand-700 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-300 dark:hover:border-brand-700 dark:hover:bg-brand-950/30 dark:hover:text-brand-300\"\n >\n <SparklesIcon\n className=\"h-3 w-3\"\n aria-hidden=\"true\"\n />\n {text}\n </button>\n ))}\n </div>\n ) : null}\n </div>\n ) : (\n <ChatMessageList\n messages={chat.messages}\n isLoading={chat.isLoading}\n isStreaming={chat.isStreaming}\n suggestions={suggestions}\n onSuggestion={(text) => chat.sendMessage(text)}\n renderAvatar={renderAvatar}\n />\n )}\n </div>\n\n {/* Input */}\n <div className=\"border-t border-slate-100 p-3 dark:border-slate-800\">\n <ChatInput\n onSend={(content) => chat.sendMessage(content)}\n disabled={chat.isLoading}\n isLoading={chat.isLoading}\n placeholder={placeholder}\n />\n </div>\n </motion.div>\n </>\n )}\n </AnimatePresence>,\n document.body\n )\n : null;\n\n return (\n <>\n {overlay}\n\n {/* Trigger bar */}\n <button\n type=\"button\"\n onClick={() => setOpen(true)}\n className={[\n \"group flex w-full items-center gap-3 rounded-xl border border-slate-200 bg-white px-4 py-2.5 text-left shadow-sm transition-all hover:border-brand-300 hover:shadow-md focus:outline-none focus:ring-2 focus:ring-brand-500/20 dark:border-slate-800 dark:bg-slate-900 dark:hover:border-brand-700\",\n className,\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n <SparklesIcon className=\"h-5 w-5 shrink-0 text-brand-500\" />\n <span className=\"flex-1 text-sm text-slate-400 dark:text-slate-500\">\n {placeholder}\n </span>\n {chat.messages.length > 0 ? (\n <span className=\"rounded-full bg-brand-50 px-2 py-0.5 text-xs font-medium text-brand-600 dark:bg-brand-950/30 dark:text-brand-400\">\n {chat.messages.length} msgs\n </span>\n ) : null}\n <kbd className=\"hidden rounded border border-slate-200 bg-slate-50 px-1.5 py-0.5 text-[10px] font-medium text-slate-400 group-hover:border-brand-200 group-hover:text-brand-500 dark:border-slate-700 dark:bg-slate-800 dark:text-slate-500 sm:inline-block\">\n {shortcutLabel}\n </kbd>\n </button>\n </>\n );\n}\n"],"names":["BACKDROP_VARIANTS","PANEL_VARIANTS","ChatBar","onSend","suggestions","placeholder","title","initialMessages","className","panelHeight","renderAvatar","onOpenInTab","open","setOpen","useState","portalVisible","setPortalVisible","panelRef","useRef","chat","useChatState","isEmpty","close","useCallback","useEffect","onKey","e","prev","handleSend","content","shortcutLabel","setShortcutLabel","overlay","createPortal","jsx","AnimatePresence","jsxs","Fragment","motion","SparklesIcon","ArrowTopRightOnSquareIcon","TrashIcon","XMarkIcon","text","ChatMessageList","ChatInput"],"mappings":"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"}
|