@schandlergarcia/sf-web-components 1.7.0 → 1.8.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/dist/components/library/cards/ActionList.d.ts +10 -10
- package/dist/components/library/cards/ActionList.js +2 -3
- package/dist/components/library/cards/ActionList.js.map +1 -1
- package/dist/components/library/cards/ActivityCard.d.ts +18 -5
- package/dist/components/library/cards/ActivityCard.js +3 -4
- package/dist/components/library/cards/ActivityCard.js.map +1 -1
- package/dist/components/library/cards/BaseCard.d.ts +30 -24
- package/dist/components/library/cards/BaseCard.js +2 -3
- package/dist/components/library/cards/BaseCard.js.map +1 -1
- package/dist/components/library/cards/CalloutCard.d.ts +11 -9
- package/dist/components/library/cards/CalloutCard.js +2 -3
- package/dist/components/library/cards/CalloutCard.js.map +1 -1
- package/dist/components/library/cards/ChartCard.d.ts +29 -17
- package/dist/components/library/cards/ChartCard.js +13 -14
- package/dist/components/library/cards/ChartCard.js.map +1 -1
- package/dist/components/library/cards/FeedPanel.d.ts +12 -11
- package/dist/components/library/cards/FeedPanel.js +3 -4
- package/dist/components/library/cards/FeedPanel.js.map +1 -1
- package/dist/components/library/cards/ListCard.d.ts +33 -20
- package/dist/components/library/cards/ListCard.js +35 -35
- package/dist/components/library/cards/ListCard.js.map +1 -1
- package/dist/components/library/cards/MetricCard.d.ts +23 -17
- package/dist/components/library/cards/MetricCard.js +10 -11
- package/dist/components/library/cards/MetricCard.js.map +1 -1
- package/dist/components/library/cards/MetricsStrip.d.ts +11 -11
- package/dist/components/library/cards/MetricsStrip.js +1 -1
- package/dist/components/library/cards/MetricsStrip.js.map +1 -1
- package/dist/components/library/cards/SectionCard.d.ts +17 -12
- package/dist/components/library/cards/SectionCard.js +18 -19
- package/dist/components/library/cards/SectionCard.js.map +1 -1
- package/dist/components/library/cards/SemanticMetricCard.d.ts +15 -20
- package/dist/components/library/cards/SemanticMetricCardWithLoading.d.ts +8 -7
- package/dist/components/library/cards/SemanticTableCard.d.ts +13 -18
- package/dist/components/library/cards/SemanticTableCardWithLoading.d.ts +8 -7
- package/dist/components/library/cards/StatusCard.d.ts +29 -15
- package/dist/components/library/cards/StatusCard.js +16 -17
- package/dist/components/library/cards/StatusCard.js.map +1 -1
- package/dist/components/library/cards/TableCard.d.ts +40 -23
- package/dist/components/library/cards/TableCard.js +59 -59
- package/dist/components/library/cards/TableCard.js.map +1 -1
- package/dist/components/library/cards/WidgetCard.d.ts +19 -11
- package/dist/components/library/cards/WidgetCard.js.map +1 -1
- package/dist/components/library/charts/D3Chart.d.ts +23 -16
- package/dist/components/library/charts/D3Chart.js.map +1 -1
- package/dist/components/library/charts/D3ChartTemplates.d.ts +33 -3
- package/dist/components/library/charts/D3ChartTemplates.js +7 -7
- package/dist/components/library/charts/D3ChartTemplates.js.map +1 -1
- package/dist/components/library/charts/GeoMap.d.ts +81 -18
- package/dist/components/library/charts/GeoMap.js +28 -26
- package/dist/components/library/charts/GeoMap.js.map +1 -1
- package/dist/components/library/filters/FilterBar.d.ts +18 -8
- package/dist/components/library/filters/FilterBar.js +2 -3
- package/dist/components/library/filters/FilterBar.js.map +1 -1
- package/dist/components/library/filters/SearchFilter.d.ts +7 -6
- package/dist/components/library/filters/SearchFilter.js +2 -3
- package/dist/components/library/filters/SearchFilter.js.map +1 -1
- package/dist/components/library/filters/SelectFilter.d.ts +13 -7
- package/dist/components/library/filters/SelectFilter.js +2 -3
- package/dist/components/library/filters/SelectFilter.js.map +1 -1
- package/dist/components/library/filters/ToggleFilter.d.ts +7 -5
- package/dist/components/library/filters/ToggleFilter.js +2 -3
- package/dist/components/library/filters/ToggleFilter.js.map +1 -1
- package/dist/components/library/forms/FormField.d.ts +10 -8
- package/dist/components/library/forms/FormField.js +3 -4
- package/dist/components/library/forms/FormField.js.map +1 -1
- package/dist/components/library/forms/FormModal.d.ts +23 -14
- package/dist/components/library/forms/FormModal.js.map +1 -1
- package/dist/components/library/forms/FormRenderer.d.ts +29 -9
- package/dist/components/library/forms/FormRenderer.js +6 -7
- package/dist/components/library/forms/FormRenderer.js.map +1 -1
- package/dist/components/library/forms/FormSection.d.ts +10 -8
- package/dist/components/library/forms/FormSection.js +2 -3
- package/dist/components/library/forms/FormSection.js.map +1 -1
- package/dist/components/library/forms/index.d.ts +5 -0
- package/dist/components/library/forms/useFormState.d.ts +23 -15
- package/dist/components/library/forms/useFormState.js +53 -47
- package/dist/components/library/forms/useFormState.js.map +1 -1
- package/dist/components/library/layout/PageContainer.d.ts +6 -4
- package/dist/components/library/layout/PageContainer.js +4 -5
- package/dist/components/library/layout/PageContainer.js.map +1 -1
- package/package.json +4 -1
- package/src/components/library/cards/{ActionList.jsx → ActionList.tsx} +13 -9
- package/src/components/library/cards/{ActivityCard.jsx → ActivityCard.tsx} +33 -4
- package/src/components/library/cards/{BaseCard.jsx → BaseCard.tsx} +33 -6
- package/src/components/library/cards/{CalloutCard.jsx → CalloutCard.tsx} +12 -10
- package/src/components/library/cards/{ChartCard.jsx → ChartCard.tsx} +32 -6
- package/src/components/library/cards/{FeedPanel.jsx → FeedPanel.tsx} +13 -2
- package/src/components/library/cards/{ListCard.jsx → ListCard.tsx} +43 -7
- package/src/components/library/cards/{MetricCard.jsx → MetricCard.tsx} +25 -6
- package/src/components/library/cards/{MetricsStrip.jsx → MetricsStrip.tsx} +22 -12
- package/src/components/library/cards/{SectionCard.jsx → SectionCard.tsx} +27 -8
- package/src/components/library/cards/{SemanticMetricCard.jsx → SemanticMetricCard.tsx} +17 -5
- package/src/components/library/cards/{SemanticMetricCardWithLoading.jsx → SemanticMetricCardWithLoading.tsx} +9 -3
- package/src/components/library/cards/{SemanticTableCard.jsx → SemanticTableCard.tsx} +14 -3
- package/src/components/library/cards/{SemanticTableCardWithLoading.jsx → SemanticTableCardWithLoading.tsx} +9 -5
- package/src/components/library/cards/{StatusCard.jsx → StatusCard.tsx} +61 -12
- package/src/components/library/cards/{TableCard.jsx → TableCard.tsx} +51 -12
- package/src/components/library/cards/{WidgetCard.jsx → WidgetCard.tsx} +28 -5
- package/src/components/library/charts/{D3Chart.jsx → D3Chart.tsx} +27 -7
- package/src/components/library/charts/{D3ChartTemplates.jsx → D3ChartTemplates.tsx} +60 -28
- package/src/components/library/charts/{GeoMap.jsx → GeoMap.tsx} +106 -17
- package/src/components/library/filters/{FilterBar.jsx → FilterBar.tsx} +21 -11
- package/src/components/library/filters/{SearchFilter.jsx → SearchFilter.tsx} +8 -2
- package/src/components/library/filters/{SelectFilter.jsx → SelectFilter.tsx} +15 -8
- package/src/components/library/filters/{ToggleFilter.jsx → ToggleFilter.tsx} +7 -6
- package/src/components/library/forms/{FormField.jsx → FormField.tsx} +91 -45
- package/src/components/library/forms/{FormModal.jsx → FormModal.tsx} +21 -20
- package/src/components/library/forms/{FormRenderer.jsx → FormRenderer.tsx} +32 -10
- package/src/components/library/forms/{FormSection.jsx → FormSection.tsx} +13 -7
- package/src/components/library/forms/index.tsx +11 -0
- package/src/components/library/forms/{useFormState.jsx → useFormState.tsx} +43 -23
- package/src/components/library/layout/{PageContainer.jsx → PageContainer.tsx} +6 -3
- package/src/components/library/forms/index.jsx +0 -5
- /package/src/components/library/filters/{index.jsx → index.ts} +0 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { jsxs as p, jsx as
|
|
1
|
+
import { jsxs as p, jsx as n } from "react/jsx-runtime";
|
|
2
2
|
import { useRef as P, useState as ce, useMemo as w, useEffect as F, useCallback as le } from "react";
|
|
3
3
|
import * as a from "d3";
|
|
4
4
|
import { feature as se } from "topojson-client";
|
|
@@ -70,7 +70,7 @@ function he({
|
|
|
70
70
|
className: B = "",
|
|
71
71
|
children: N
|
|
72
72
|
}) {
|
|
73
|
-
const
|
|
73
|
+
const o = 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
74
|
const e = fe(k, s, i), t = a.geoPath(e);
|
|
75
75
|
return {
|
|
76
76
|
proj: e,
|
|
@@ -83,7 +83,9 @@ function he({
|
|
|
83
83
|
F(() => {
|
|
84
84
|
if (!x || !g.current) return;
|
|
85
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), () =>
|
|
86
|
+
return b.current = t, e.call(t), () => {
|
|
87
|
+
e.on(".zoom", null);
|
|
88
|
+
};
|
|
87
89
|
}, [x, S, M]);
|
|
88
90
|
const C = P(!1);
|
|
89
91
|
F(() => {
|
|
@@ -92,7 +94,7 @@ function he({
|
|
|
92
94
|
if (!c || !u) return;
|
|
93
95
|
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
96
|
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,
|
|
97
|
+
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, oe = i / 2 - te * I, ne = Math.max(S, Math.min(M, I)), ae = a.zoomIdentity.translate(re, oe).scale(ne);
|
|
96
98
|
a.select(g.current).call(b.current.transform, ae), C.current = !0;
|
|
97
99
|
}, [$, l, s, i, S, M]);
|
|
98
100
|
const U = le(() => {
|
|
@@ -119,44 +121,44 @@ function he({
|
|
|
119
121
|
t.active && e.add(t.id);
|
|
120
122
|
}), e;
|
|
121
123
|
}, [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:
|
|
124
|
+
return /* @__PURE__ */ p("div", { className: `relative overflow-hidden ${B}`, style: { background: o.bg }, children: [
|
|
123
125
|
/* @__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
126
|
/* @__PURE__ */ p("defs", { children: [
|
|
125
127
|
/* @__PURE__ */ p("radialGradient", { id: "geo-bg", cx: "50%", cy: "50%", r: "55%", children: [
|
|
126
|
-
/* @__PURE__ */
|
|
127
|
-
/* @__PURE__ */
|
|
128
|
+
/* @__PURE__ */ n("stop", { offset: "0%", stopColor: o.bgGradient[0] }),
|
|
129
|
+
/* @__PURE__ */ n("stop", { offset: "100%", stopColor: o.bgGradient[1] })
|
|
128
130
|
] }),
|
|
129
131
|
/* @__PURE__ */ p("filter", { id: "geo-glow", x: "-50%", y: "-50%", width: "200%", height: "200%", children: [
|
|
130
|
-
/* @__PURE__ */
|
|
132
|
+
/* @__PURE__ */ n("feGaussianBlur", { in: "SourceGraphic", stdDeviation: "3", result: "b" }),
|
|
131
133
|
/* @__PURE__ */ p("feMerge", { children: [
|
|
132
|
-
/* @__PURE__ */
|
|
133
|
-
/* @__PURE__ */
|
|
134
|
+
/* @__PURE__ */ n("feMergeNode", { in: "b" }),
|
|
135
|
+
/* @__PURE__ */ n("feMergeNode", { in: "SourceGraphic" })
|
|
134
136
|
] })
|
|
135
137
|
] })
|
|
136
138
|
] }),
|
|
137
|
-
/* @__PURE__ */
|
|
139
|
+
/* @__PURE__ */ n("style", { children: `
|
|
138
140
|
.geo-arc{stroke-dasharray:8,6;animation:geo-flow 1.5s linear infinite}
|
|
139
141
|
@keyframes geo-flow{to{stroke-dashoffset:-14}}
|
|
140
142
|
.geo-dot{animation:geo-pulse 2s ease-in-out infinite}
|
|
141
143
|
@keyframes geo-pulse{0%,100%{opacity:1}50%{opacity:.5}}
|
|
142
144
|
` }),
|
|
143
|
-
/* @__PURE__ */
|
|
145
|
+
/* @__PURE__ */ n("rect", { width: s, height: i, fill: "url(#geo-bg)" }),
|
|
144
146
|
/* @__PURE__ */ p("g", { transform: Z, children: [
|
|
145
|
-
/* @__PURE__ */
|
|
146
|
-
/* @__PURE__ */
|
|
147
|
-
/* @__PURE__ */
|
|
147
|
+
/* @__PURE__ */ n("path", { d: L ?? void 0, fill: "none", stroke: o.sphere, strokeWidth: 0.8 * f }),
|
|
148
|
+
/* @__PURE__ */ n("path", { d: Q ?? void 0, fill: o.land, stroke: o.landStroke, strokeWidth: 0.4 * f }),
|
|
149
|
+
/* @__PURE__ */ n("path", { d: K ?? void 0, fill: "none", stroke: o.graticule, strokeWidth: 0.3 * f, opacity: o.graticuleOpacity }),
|
|
148
150
|
T.map((e) => {
|
|
149
151
|
const t = l(e.center);
|
|
150
152
|
if (!t) return null;
|
|
151
153
|
const r = l([e.center[0] + (e.radius ?? 5), e.center[1]]), c = r ? Math.abs(r[0] - t[0]) : 30;
|
|
152
|
-
return /* @__PURE__ */
|
|
154
|
+
return /* @__PURE__ */ n(
|
|
153
155
|
"circle",
|
|
154
156
|
{
|
|
155
157
|
cx: t[0],
|
|
156
158
|
cy: t[1],
|
|
157
159
|
r: c,
|
|
158
|
-
fill: e.fill ??
|
|
159
|
-
stroke: e.stroke ??
|
|
160
|
+
fill: e.fill ?? o.overlayFill,
|
|
161
|
+
stroke: e.stroke ?? o.overlayStroke,
|
|
160
162
|
strokeWidth: 1 * f,
|
|
161
163
|
strokeDasharray: "5,5",
|
|
162
164
|
className: "animate-pulse"
|
|
@@ -167,12 +169,12 @@ function he({
|
|
|
167
169
|
R.map((e) => {
|
|
168
170
|
if (!e._path) return null;
|
|
169
171
|
const t = v === e.id, r = e.danger;
|
|
170
|
-
return /* @__PURE__ */
|
|
172
|
+
return /* @__PURE__ */ n(
|
|
171
173
|
"path",
|
|
172
174
|
{
|
|
173
175
|
d: e._path,
|
|
174
176
|
fill: "none",
|
|
175
|
-
stroke: r ?
|
|
177
|
+
stroke: r ? o.arcDanger : t ? o.arcHighlight : e.color ?? o.arc,
|
|
176
178
|
strokeWidth: (t ? 3 : 2) * f,
|
|
177
179
|
opacity: v != null && !t ? 0.15 : r ? 0.85 : 0.65,
|
|
178
180
|
className: "geo-arc cursor-pointer",
|
|
@@ -186,8 +188,8 @@ function he({
|
|
|
186
188
|
if (!t) return null;
|
|
187
189
|
const r = e.active ?? X.has(e.id);
|
|
188
190
|
return /* @__PURE__ */ p("g", { className: z ? "cursor-pointer" : "", onClick: () => z?.(e), children: [
|
|
189
|
-
/* @__PURE__ */
|
|
190
|
-
e.label !== !1 && /* @__PURE__ */
|
|
191
|
+
/* @__PURE__ */ n("circle", { cx: t[0], cy: t[1], r: (r ? 3 : 2) * f, fill: r ? o.markerActive : o.markerInactive }),
|
|
192
|
+
e.label !== !1 && /* @__PURE__ */ n("text", { x: t[0] + 6 * f, y: t[1] + 4 * f, fontSize: 8 * f, fill: r ? o.label : o.labelInactive, fontFamily: "sans-serif", fontWeight: 600, children: e.label ?? e.id })
|
|
191
193
|
] }, e.id);
|
|
192
194
|
}),
|
|
193
195
|
R.map((e) => {
|
|
@@ -195,13 +197,13 @@ function he({
|
|
|
195
197
|
const t = a.geoInterpolate(e.from, e.to), r = l(t(Math.min(e.progress, 0.99)));
|
|
196
198
|
if (!r) return null;
|
|
197
199
|
const c = v === e.id;
|
|
198
|
-
return /* @__PURE__ */
|
|
200
|
+
return /* @__PURE__ */ n(
|
|
199
201
|
"circle",
|
|
200
202
|
{
|
|
201
203
|
cx: r[0],
|
|
202
204
|
cy: r[1],
|
|
203
205
|
r: (c ? 6 : 4.5) * f,
|
|
204
|
-
fill: e.danger ?
|
|
206
|
+
fill: e.danger ? o.dotDanger : e.dotColor ?? o.dot,
|
|
205
207
|
filter: "url(#geo-glow)",
|
|
206
208
|
className: "geo-dot cursor-pointer",
|
|
207
209
|
opacity: v != null && !c ? 0.3 : 1,
|
|
@@ -210,10 +212,10 @@ function he({
|
|
|
210
212
|
`dot-${e.id}`
|
|
211
213
|
);
|
|
212
214
|
}),
|
|
213
|
-
typeof N == "function" ? N({ proj: l, pathGen: Y, theme:
|
|
215
|
+
typeof N == "function" ? N({ proj: l, pathGen: Y, theme: o, width: s, height: i, transform: d }) : N
|
|
214
216
|
] })
|
|
215
217
|
] }),
|
|
216
|
-
x && V && /* @__PURE__ */
|
|
218
|
+
x && V && /* @__PURE__ */ n(
|
|
217
219
|
"button",
|
|
218
220
|
{
|
|
219
221
|
onClick: U,
|
|
@@ -1 +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":";;;;;AAKA,MAAMA,KAAOC,GAAQC,GAAOA,EAAM,QAAQ,IAAI,GAExCC,IAAc;AAAA,EAClB,cAAcC,EAAG;AAAA,EACjB,UAAUA,EAAG;AAAA,EACb,iBAAiBA,EAAG;AACtB,GAEMC,IAAS;AAAA,EACb,MAAM;AAAA,IACJ,IAAI;AAAA,IACJ,YAAY,CAAC,WAAW,SAAS;AAAA,IACjC,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,OAAO;AAAA,IACP,eAAe;AAAA,IACf,KAAK;AAAA,IACL,cAAc;AAAA,IACd,WAAW;AAAA,IACX,KAAK;AAAA,IACL,WAAW;AAAA,IACX,aAAa;AAAA,IACb,eAAe;AAAA,EAAA;AAAA,EAEjB,OAAO;AAAA,IACL,IAAI;AAAA,IACJ,YAAY,CAAC,WAAW,SAAS;AAAA,IACjC,MAAM;AAAA,IACN,YAAY;AAAA,IACZ,QAAQ;AAAA,IACR,WAAW;AAAA,IACX,kBAAkB;AAAA,IAClB,cAAc;AAAA,IACd,gBAAgB;AAAA,IAChB,OAAO;AAAA,IACP,eAAe;AAAA,IACf,KAAK;AAAA,IACL,cAAc;AAAA,IACd,WAAW;AAAA,IACX,KAAK;AAAA,IACL,WAAW;AAAA,IACX,aAAa;AAAA,IACb,eAAe;AAAA,EAAA;AAEnB;AAEA,SAASC,GAAgBC,GAAMC,GAAOC,GAAQ;AAE5C,UADgBN,EAAYI,CAAI,KAAKJ,EAAY,cAC1C,EAAU,QAAQ,CAACK,GAAOC,CAAM,GAAG,EAAE,MAAM,UAAU;AAC9D;AAEA,SAAwBC,GAAO;AAAA,EAC7B,OAAAF,IAAQ;AAAA,EACR,QAAAC,IAAS;AAAA,EACT,YAAYE,IAAW;AAAA,EACvB,OAAAC,IAAQ;AAAA,EACR,SAAAC,IAAU,CAAA;AAAA,EACV,MAAAC,IAAO,CAAA;AAAA,EACP,UAAAC,IAAW,CAAA;AAAA,EACX,YAAAC,IAAa;AAAA,EACb,YAAAC;AAAA,EACA,eAAAC;AAAA,EACA,UAAAC,IAAW;AAAA,EACX,SAAAC,IAAU;AAAA,EACV,SAAAC,IAAU;AAAA,EACV,eAAAC,IAAgB;AAAA,EAChB,WAAAC,IAAY;AAAA,EACZ,UAAAC;AACF,GAAG;AACD,QAAMC,IAAIpB,EAAOO,CAAK,KAAKP,EAAO,MAC5BqB,IAASC,EAAO,IAAI,GACpB,CAACC,GAAWC,CAAY,IAAIC,GAAS1B,EAAG,YAAY,GACpD2B,IAAUJ,EAAO,IAAI,GAErB,EAAE,MAAAK,GAAM,SAAAC,GAAS,eAAAC,GAAe,YAAAC,GAAY,UAAAC,EAAA,IAAaC,EAAQ,MAAM;AAC3E,UAAML,IAAO1B,GAAgBK,GAAUH,GAAOC,CAAM,GAC9CwB,IAAU7B,EAAG,QAAQ4B,CAAI;AAC/B,WAAO;AAAA,MACL,MAAAA;AAAAA,MACA,SAAAC;AAAAA,MACA,eAAeA,EAAQ7B,EAAG,gBAAgB;AAAA,MAC1C,YAAY6B,EAAQ,EAAE,MAAM,UAAU;AAAA,MACtC,UAAUA,EAAQjC,EAAI;AAAA,IAAA;AAAA,EAE1B,GAAG,CAACW,GAAUH,GAAOC,CAAM,CAAC;AAG5B,EAAA6B,EAAU,MAAM;AACd,QAAI,CAACnB,KAAY,CAACO,EAAO,QAAS;AAClC,UAAMa,IAAMnC,EAAG,OAAOsB,EAAO,OAAO,GAC9Bc,IAAOpC,EAAG,KAAA,EACb,YAAY,CAACgB,GAASC,CAAO,CAAC,EAC9B,GAAG,QAAQ,CAACoB,MAAMZ,EAAaY,EAAE,SAAS,CAAC;AAC9C,WAAAV,EAAQ,UAAUS,GAClBD,EAAI,KAAKC,CAAI,GACN,MAAMD,EAAI,GAAG,SAAS,IAAI;AAAA,EACnC,GAAG,CAACpB,GAAUC,GAASC,CAAO,CAAC;AAG/B,QAAMqB,IAAuBf,EAAO,EAAK;AACzC,EAAAW,EAAU,MAAM;AAEd,QADI,CAAChB,KAAiBoB,EAAqB,WACvC,CAAChB,EAAO,WAAW,CAACK,EAAQ,WAAW,CAACC,EAAM;AAClD,UAAM,EAAE,IAAAW,GAAI,IAAAC,GAAI,SAAAC,IAAU,OAAOvB,GAC3BwB,IAAKd,EAAKW,CAAE,GACZI,IAAKf,EAAKY,CAAE;AAClB,QAAI,CAACE,KAAM,CAACC,EAAI;AAChB,UAAMC,IAAM,KAAK,IAAIF,EAAG,CAAC,GAAGC,EAAG,CAAC,CAAC,GAC3BE,IAAM,KAAK,IAAIH,EAAG,CAAC,GAAGC,EAAG,CAAC,CAAC,GAC3BG,IAAM,KAAK,IAAIJ,EAAG,CAAC,GAAGC,EAAG,CAAC,CAAC,GAC3BI,IAAM,KAAK,IAAIL,EAAG,CAAC,GAAGC,EAAG,CAAC,CAAC,GAC3BK,IAAKF,IAAMF,GACXK,IAAKF,IAAMF;AACjB,QAAIG,IAAK,KAAKC,IAAK,EAAG;AACtB,UAAMC,IAAQ,KAAK,KAAK9C,IAAQqC,IAAU,KAAKO,IAAK3C,IAASoC,IAAU,KAAKQ,CAAE,GACxEE,MAAMP,IAAME,KAAO,GACnBM,MAAMP,IAAME,KAAO,GACnBM,KAAKjD,IAAQ,IAAI+C,KAAKD,GACtBI,KAAKjD,IAAS,IAAI+C,KAAKF,GACvBK,KAAe,KAAK,IAAIvC,GAAS,KAAK,IAAIC,GAASiC,CAAK,CAAC,GACzD7B,KAAIrB,EAAG,aAAa,UAAUqD,IAAIC,EAAE,EAAE,MAAMC,EAAY;AAC9D,IAAAvD,EAAG,OAAOsB,EAAO,OAAO,EAAE,KAAKK,EAAQ,QAAQ,WAAWN,EAAC,GAC3DiB,EAAqB,UAAU;AAAA,EACjC,GAAG,CAACpB,GAAeU,GAAMxB,GAAOC,GAAQW,GAASC,CAAO,CAAC;AAEzD,QAAMuC,IAAYC,GAAY,MAAM;AAClC,IAAI,CAACnC,EAAO,WAAW,CAACK,EAAQ,WAChC3B,EAAG,OAAOsB,EAAO,OAAO,EACrB,aACA,SAAS,GAAG,EACZ,KAAKK,EAAQ,QAAQ,WAAW3B,EAAG,YAAY;AAAA,EACpD,GAAG,CAAA,CAAE,GAEC0D,IAAWlC,EAAU,MAAM,KAAKA,EAAU,MAAM,KAAKA,EAAU,MAAM,GAErEmC,IAAW1B,EAAQ,MAAM;AAC7B,UAAM2B,IAAQ,CAAA;AACd,WAAAlD,EAAK,QAAQ,CAAAmD,MAAK;AAChB,YAAMC,IAAM,GAAGD,EAAE,KAAK,CAAC,CAAC,IAAIA,EAAE,KAAK,CAAC,CAAC,IAAIA,EAAE,GAAG,CAAC,CAAC,IAAIA,EAAE,GAAG,CAAC,CAAC;AAC3D,UAAID,EAAME,CAAG,GAAG;AAAE,QAAAD,EAAE,QAAQD,EAAME,CAAG;AAAG;AAAA,MAAQ;AAChD,YAAMC,IAAS/D,EAAG,eAAe6D,EAAE,MAAMA,EAAE,EAAE,GACvCG,IAAM,CAAA;AACZ,eAASC,IAAI,GAAGA,KAAK,GAAGA,KAAK,MAAM;AACjC,cAAMC,IAAItC,EAAKmC,EAAOE,CAAC,CAAC;AACxB,QAAIC,KAAGF,EAAI,KAAKE,CAAC;AAAA,MACnB;AACA,YAAMC,IAAOH,EAAI,SAAS,IAAIhE,EAAG,KAAA,EAAOgE,CAAG,IAAI;AAC/C,MAAAJ,EAAME,CAAG,IAAIK,GACbN,EAAE,QAAQM;AAAA,IACZ,CAAC,GACMzD;AAAA,EACT,GAAG,CAACA,GAAMkB,CAAI,CAAC,GAETwC,IAAkBnC,EAAQ,MAAM;AACpC,UAAMoC,wBAAQ,IAAA;AACd,WAAA5D,EAAQ,QAAQ,CAAA6D,MAAK;AAAE,MAAIA,EAAE,UAAQD,EAAE,IAAIC,EAAE,EAAE;AAAA,IAAG,CAAC,GAC5CD;AAAA,EACT,GAAG,CAAC5D,CAAO,CAAC,GAEN8D,IAAQ,aAAa/C,EAAU,CAAC,IAAIA,EAAU,CAAC,WAAWA,EAAU,CAAC,KACrEgD,IAAW,IAAIhD,EAAU;AAE/B,SACE,gBAAAiD,EAAC,OAAA,EAAI,WAAW,4BAA4BtD,CAAS,IAAI,OAAO,EAAE,YAAYE,EAAE,GAAA,GAC9E,UAAA;AAAA,IAAA,gBAAAoD,EAAC,SAAI,KAAKnD,GAAQ,SAAS,OAAOlB,CAAK,IAAIC,CAAM,IAAI,WAAU,iBAAgB,qBAAoB,kBAAiB,OAAOU,IAAW,EAAE,QAAQ,OAAA,IAAW,QACzJ,UAAA;AAAA,MAAA,gBAAA0D,EAAC,QAAA,EACC,UAAA;AAAA,QAAA,gBAAAA,EAAC,kBAAA,EAAe,IAAG,UAAS,IAAG,OAAM,IAAG,OAAM,GAAE,OAC9C,UAAA;AAAA,UAAA,gBAAAC,EAAC,UAAK,QAAO,MAAK,WAAWrD,EAAE,WAAW,CAAC,GAAG;AAAA,UAC9C,gBAAAqD,EAAC,UAAK,QAAO,QAAO,WAAWrD,EAAE,WAAW,CAAC,EAAA,CAAG;AAAA,QAAA,GAClD;AAAA,QACA,gBAAAoD,EAAC,UAAA,EAAO,IAAG,YAAW,GAAE,QAAO,GAAE,QAAO,OAAM,QAAO,QAAO,QAC1D,UAAA;AAAA,UAAA,gBAAAC,EAAC,oBAAe,IAAG,iBAAgB,cAAa,KAAI,QAAO,KAAI;AAAA,4BAC9D,WAAA,EAAQ,UAAA;AAAA,YAAA,gBAAAA,EAAC,eAAA,EAAY,IAAG,IAAA,CAAI;AAAA,YAAE,gBAAAA,EAAC,eAAA,EAAY,IAAG,gBAAA,CAAgB;AAAA,UAAA,EAAA,CAAE;AAAA,QAAA,EAAA,CACnE;AAAA,MAAA,GACF;AAAA,wBACC,SAAA,EAAO,UAAA;AAAA;AAAA;AAAA;AAAA;AAAA,WAKN;AAAA,MAEF,gBAAAA,EAAC,QAAA,EAAK,OAAAtE,GAAc,QAAAC,GAAgB,MAAK,gBAAe;AAAA,MAGxD,gBAAAoE,EAAC,KAAA,EAAE,WAAWF,GACZ,UAAA;AAAA,QAAA,gBAAAG,EAAC,QAAA,EAAK,GAAG3C,GAAY,MAAK,QAAO,QAAQV,EAAE,QAAQ,aAAa,MAAMmD,EAAA,CAAU;AAAA,QAChF,gBAAAE,EAAC,QAAA,EAAK,GAAG1C,GAAU,MAAMX,EAAE,MAAM,QAAQA,EAAE,YAAY,aAAa,MAAMmD,EAAA,CAAU;AAAA,QACpF,gBAAAE,EAAC,QAAA,EAAK,GAAG5C,GAAe,MAAK,QAAO,QAAQT,EAAE,WAAW,aAAa,MAAMmD,GAAU,SAASnD,EAAE,kBAAkB;AAAA,QAGlHV,EAAS,IAAI,CAAAgE,MAAK;AACjB,gBAAMC,IAAIhD,EAAK+C,EAAE,MAAM;AACvB,cAAI,CAACC,EAAG,QAAO;AACf,gBAAMC,IAAOjD,EAAK,CAAC+C,EAAE,OAAO,CAAC,KAAKA,EAAE,UAAU,IAAIA,EAAE,OAAO,CAAC,CAAC,CAAC,GACxDG,IAAID,IAAO,KAAK,IAAIA,EAAK,CAAC,IAAID,EAAE,CAAC,CAAC,IAAI;AAC5C,iBACE,gBAAAF;AAAA,YAAC;AAAA,YAAA;AAAA,cAEC,IAAIE,EAAE,CAAC;AAAA,cAAG,IAAIA,EAAE,CAAC;AAAA,cAAG,GAAAE;AAAA,cACpB,MAAMH,EAAE,QAAQtD,EAAE;AAAA,cAClB,QAAQsD,EAAE,UAAUtD,EAAE;AAAA,cACtB,aAAa,IAAImD;AAAA,cACjB,iBAAgB;AAAA,cAChB,WAAU;AAAA,YAAA;AAAA,YANLG,EAAE;AAAA,UAAA;AAAA,QASb,CAAC;AAAA,QAGAhB,EAAS,IAAI,CAAAE,MAAK;AACjB,cAAI,CAACA,EAAE,MAAO,QAAO;AACrB,gBAAMkB,IAAMnE,MAAeiD,EAAE,IACvBmB,IAASnB,EAAE;AACjB,iBACE,gBAAAa;AAAA,YAAC;AAAA,YAAA;AAAA,cAEC,GAAGb,EAAE;AAAA,cACL,MAAK;AAAA,cACL,QAAQmB,IAAS3D,EAAE,YAAY0D,IAAM1D,EAAE,eAAewC,EAAE,SAASxC,EAAE;AAAA,cACnE,cAAc0D,IAAM,IAAI,KAAKP;AAAA,cAC7B,SAAS5D,KAAc,QAAQ,CAACmE,IAAM,OAAOC,IAAS,OAAO;AAAA,cAC7D,WAAU;AAAA,cACV,SAAS,MAAMnE,IAAagD,CAAC;AAAA,YAAA;AAAA,YAPxB,OAAOA,EAAE,EAAE;AAAA,UAAA;AAAA,QAUtB,CAAC;AAAA,QAGApD,EAAQ,IAAI,CAAA6D,MAAK;AAChB,gBAAMJ,IAAItC,EAAK,CAAC0C,EAAE,KAAKA,EAAE,GAAG,CAAC;AAC7B,cAAI,CAACJ,EAAG,QAAO;AACf,gBAAMe,IAASX,EAAE,UAAUF,EAAgB,IAAIE,EAAE,EAAE;AACnD,iBACE,gBAAAG,EAAC,KAAA,EAAa,WAAW3D,IAAgB,mBAAmB,IAAI,SAAS,MAAMA,IAAgBwD,CAAC,GAC9F,UAAA;AAAA,YAAA,gBAAAI,EAAC,YAAO,IAAIR,EAAE,CAAC,GAAG,IAAIA,EAAE,CAAC,GAAG,IAAIe,IAAS,IAAI,KAAKT,GAAU,MAAMS,IAAS5D,EAAE,eAAeA,EAAE,gBAAgB;AAAA,YAC7GiD,EAAE,UAAU,MACX,gBAAAI,EAAC,UAAK,GAAGR,EAAE,CAAC,IAAI,IAAIM,GAAU,GAAGN,EAAE,CAAC,IAAI,IAAIM,GAAU,UAAU,IAAIA,GAAU,MAAMS,IAAS5D,EAAE,QAAQA,EAAE,eAAe,YAAW,cAAa,YAAY,KACzJ,UAAAiD,EAAE,SAASA,EAAE,GAAA,CAChB;AAAA,UAAA,EAAA,GALIA,EAAE,EAOV;AAAA,QAEJ,CAAC;AAAA,QAGAX,EAAS,IAAI,CAAAE,MAAK;AACjB,cAAIA,EAAE,YAAY,QAAQA,EAAE,YAAY,EAAG,QAAO;AAClD,gBAAME,IAAS/D,EAAG,eAAe6D,EAAE,MAAMA,EAAE,EAAE,GACvCK,IAAItC,EAAKmC,EAAO,KAAK,IAAIF,EAAE,UAAU,IAAI,CAAC,CAAC;AACjD,cAAI,CAACK,EAAG,QAAO;AACf,gBAAMa,IAAMnE,MAAeiD,EAAE;AAC7B,iBACE,gBAAAa;AAAA,YAAC;AAAA,YAAA;AAAA,cAEC,IAAIR,EAAE,CAAC;AAAA,cAAG,IAAIA,EAAE,CAAC;AAAA,cACjB,IAAIa,IAAM,IAAI,OAAOP;AAAA,cACrB,MAAMX,EAAE,SAASxC,EAAE,YAAYwC,EAAE,YAAYxC,EAAE;AAAA,cAC/C,QAAO;AAAA,cACP,WAAU;AAAA,cACV,SAAST,KAAc,QAAQ,CAACmE,IAAM,MAAM;AAAA,cAC5C,SAAS,MAAMlE,IAAagD,CAAC;AAAA,YAAA;AAAA,YAPxB,OAAOA,EAAE,EAAE;AAAA,UAAA;AAAA,QAUtB,CAAC;AAAA,QAGA,OAAOzC,KAAa,aAAaA,EAAS,EAAE,MAAAQ,GAAM,SAAAC,GAAS,OAAOR,GAAG,OAAAjB,GAAO,QAAAC,GAAQ,WAAAmB,EAAA,CAAW,IAAIJ;AAAA,MAAA,EAAA,CACtG;AAAA,IAAA,GACF;AAAA,IAGCL,KAAY2C,KACX,gBAAAgB;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,SAASlB;AAAA,QACT,WAAU;AAAA,QACX,UAAA;AAAA,MAAA;AAAA,IAAA;AAAA,EAED,GAEJ;AAEJ;"}
|
|
1
|
+
{"version":3,"file":"GeoMap.js","sources":["../../../../src/components/library/charts/GeoMap.tsx"],"sourcesContent":["import React, { useMemo, useRef, useEffect, useState, useCallback } from \"react\";\nimport * as d3 from \"d3\";\nimport { feature } from \"topojson-client\";\nimport type { Topology, GeometryCollection } from \"topojson-specification\";\nimport world from \"world-atlas/land-110m.json\";\n\nconst land = feature(world as unknown as Topology<{ land: GeometryCollection }>, (world.objects.land as unknown) as GeometryCollection);\n\ntype ProjectionType = \"naturalEarth\" | \"mercator\" | \"equirectangular\";\n\nconst PROJECTIONS = {\n naturalEarth: d3.geoNaturalEarth1,\n mercator: d3.geoMercator,\n equirectangular: d3.geoEquirectangular,\n};\n\ninterface Theme {\n bg: string;\n bgGradient: [string, string];\n land: string;\n landStroke: string;\n sphere: string;\n graticule: string;\n graticuleOpacity: number;\n markerActive: string;\n markerInactive: string;\n label: string;\n labelInactive: string;\n arc: string;\n arcHighlight: string;\n arcDanger: string;\n dot: string;\n dotDanger: string;\n overlayFill: string;\n overlayStroke: string;\n}\n\ntype ThemeName = \"dark\" | \"light\";\n\nconst THEMES: Record<ThemeName, Theme> = {\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: ProjectionType, width: number, height: number): d3.GeoProjection {\n const factory = PROJECTIONS[type] ?? PROJECTIONS.naturalEarth;\n return factory().fitSize([width, height], { type: \"Sphere\" });\n}\n\nexport interface Marker {\n id: string;\n lon: number;\n lat: number;\n label?: string | false;\n active?: boolean;\n}\n\nexport interface Arc {\n id: string;\n from: [number, number];\n to: [number, number];\n danger?: boolean;\n color?: string;\n dotColor?: string;\n progress?: number;\n _path?: string | null;\n}\n\nexport interface Overlay {\n id: string;\n center: [number, number];\n radius?: number;\n fill?: string;\n stroke?: string;\n}\n\nexport interface InitialBounds {\n sw: [number, number];\n ne: [number, number];\n padding?: number;\n}\n\ninterface ChildrenFunctionProps {\n proj: d3.GeoProjection;\n pathGen: d3.GeoPath;\n theme: Theme;\n width: number;\n height: number;\n transform: d3.ZoomTransform;\n}\n\nexport interface GeoMapProps {\n width?: number;\n height?: number;\n projection?: ProjectionType;\n theme?: ThemeName;\n markers?: Marker[];\n arcs?: Arc[];\n overlays?: Overlay[];\n selectedId?: string | null;\n onArcClick?: (arc: Arc) => void;\n onMarkerClick?: (marker: Marker) => void;\n zoomable?: boolean;\n minZoom?: number;\n maxZoom?: number;\n initialBounds?: InitialBounds | null;\n className?: string;\n children?: React.ReactNode | ((props: ChildrenFunctionProps) => React.ReactNode);\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}: GeoMapProps): React.ReactElement {\n const t = THEMES[theme] ?? THEMES.dark;\n const svgRef = useRef<SVGSVGElement>(null);\n const [transform, setTransform] = useState<d3.ZoomTransform>(d3.zoomIdentity);\n const zoomRef = useRef<d3.ZoomBehavior<SVGSVGElement, unknown> | null>(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<SVGSVGElement, unknown>()\n .scaleExtent([minZoom, maxZoom])\n .on(\"zoom\", (e: d3.D3ZoomEvent<SVGSVGElement, unknown>) => setTransform(e.transform));\n zoomRef.current = zoom;\n svg.call(zoom);\n return () => {\n svg.on(\".zoom\", null);\n };\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: Record<string, string | null> = {};\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: [number, number][] = [];\n for (let i = 0; i <= 1; i += 0.02) {\n const p = proj(interp(i));\n if (p) pts.push(p as [number, number]);\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<string>();\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 ?? undefined} fill=\"none\" stroke={t.sphere} strokeWidth={0.8 * invScale} />\n <path d={landPath ?? undefined} fill={t.land} stroke={t.landStroke} strokeWidth={0.4 * invScale} />\n <path d={graticulePath ?? undefined} 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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"}
|
|
@@ -1,12 +1,22 @@
|
|
|
1
|
+
import { SelectOption } from "./SelectFilter";
|
|
2
|
+
export interface FilterDefinition {
|
|
3
|
+
id: string;
|
|
4
|
+
type: "search" | "select" | "toggle";
|
|
5
|
+
label?: string;
|
|
6
|
+
placeholder?: string;
|
|
7
|
+
options?: (string | SelectOption)[];
|
|
8
|
+
className?: string;
|
|
9
|
+
}
|
|
10
|
+
export interface FilterBarProps {
|
|
11
|
+
filters?: FilterDefinition[];
|
|
12
|
+
values?: Record<string, any>;
|
|
13
|
+
onChange?: (filterId: string, value: any) => void;
|
|
14
|
+
onReset?: () => void;
|
|
15
|
+
activeCount?: number;
|
|
16
|
+
layout?: "inline" | "stacked";
|
|
17
|
+
}
|
|
1
18
|
/**
|
|
2
19
|
* Renders a row of filter controls from a definitions array.
|
|
3
20
|
* Pairs with usePageFilters hook for state management.
|
|
4
|
-
*
|
|
5
|
-
* @param {Array} filters — filter definitions [{ id, type, ... }]
|
|
6
|
-
* @param {Object} values — current filter values keyed by filter id
|
|
7
|
-
* @param {Function} onChange — (filterId, value) => void
|
|
8
|
-
* @param {Function} onReset — () => void
|
|
9
|
-
* @param {number} activeCount — number of active filters (for badge)
|
|
10
|
-
* @param {string} layout — "inline" (default) or "stacked"
|
|
11
21
|
*/
|
|
12
|
-
export default function FilterBar({ filters, values, onChange, onReset, activeCount, layout, }:
|
|
22
|
+
export default function FilterBar({ filters, values, onChange, onReset, activeCount, layout, }: FilterBarProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -1,10 +1,9 @@
|
|
|
1
1
|
import { jsxs as m, jsx as a } from "react/jsx-runtime";
|
|
2
|
-
import "react";
|
|
3
2
|
import p from "./SearchFilter.js";
|
|
4
3
|
import u from "./SelectFilter.js";
|
|
5
4
|
import h from "./ToggleFilter.js";
|
|
6
5
|
import { XMarkIcon as x } from "@heroicons/react/24/outline";
|
|
7
|
-
function
|
|
6
|
+
function w({
|
|
8
7
|
filters: o = [],
|
|
9
8
|
values: d = {},
|
|
10
9
|
onChange: s,
|
|
@@ -84,6 +83,6 @@ function f({
|
|
|
84
83
|
);
|
|
85
84
|
}
|
|
86
85
|
export {
|
|
87
|
-
|
|
86
|
+
w as default
|
|
88
87
|
};
|
|
89
88
|
//# sourceMappingURL=FilterBar.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FilterBar.js","sources":["../../../../src/components/library/filters/FilterBar.
|
|
1
|
+
{"version":3,"file":"FilterBar.js","sources":["../../../../src/components/library/filters/FilterBar.tsx"],"sourcesContent":["import SearchFilter from \"./SearchFilter\";\nimport SelectFilter, { SelectOption } from \"./SelectFilter\";\nimport ToggleFilter from \"./ToggleFilter\";\nimport { XMarkIcon } from \"@heroicons/react/24/outline\";\n\nexport interface FilterDefinition {\n id: string;\n type: \"search\" | \"select\" | \"toggle\";\n label?: string;\n placeholder?: string;\n options?: (string | SelectOption)[];\n className?: string;\n}\n\nexport interface FilterBarProps {\n filters?: FilterDefinition[];\n values?: Record<string, any>;\n onChange?: (filterId: string, value: any) => void;\n onReset?: () => void;\n activeCount?: number;\n layout?: \"inline\" | \"stacked\";\n}\n\n/**\n * Renders a row of filter controls from a definitions array.\n * Pairs with usePageFilters hook for state management.\n */\nexport default function FilterBar({\n filters = [],\n values = {},\n onChange,\n onReset,\n activeCount = 0,\n layout = \"inline\",\n}: FilterBarProps) {\n if (!filters.length) return null;\n\n const isStacked = layout === \"stacked\";\n\n return (\n <div\n className={[\n \"flex gap-3\",\n isStacked\n ? \"flex-col\"\n : \"flex-col sm:flex-row sm:flex-wrap sm:items-center\",\n ].join(\" \")}\n >\n {filters.map((filter) => {\n const val = values[filter.id];\n\n switch (filter.type) {\n case \"search\":\n return (\n <SearchFilter\n key={filter.id}\n value={val ?? \"\"}\n onChange={(v) => onChange?.(filter.id, v)}\n placeholder={filter.placeholder ?? \"Search…\"}\n className={filter.className ?? (isStacked ? \"w-full\" : \"w-full sm:w-64\")}\n />\n );\n\n case \"select\":\n return (\n <SelectFilter\n key={filter.id}\n value={val ?? \"all\"}\n onChange={(v) => onChange?.(filter.id, v)}\n options={filter.options ?? []}\n label={filter.label}\n placeholder={filter.placeholder ?? \"All\"}\n className={filter.className}\n />\n );\n\n case \"toggle\":\n return (\n <ToggleFilter\n key={filter.id}\n value={val ?? false}\n onChange={(v) => onChange?.(filter.id, v)}\n label={filter.label}\n className={filter.className}\n />\n );\n\n default:\n return null;\n }\n })}\n\n {activeCount > 0 && onReset ? (\n <button\n type=\"button\"\n onClick={onReset}\n className=\"inline-flex items-center gap-1.5 rounded-lg px-2.5 py-1.5 text-xs font-medium text-slate-500 transition hover:bg-slate-100 hover:text-slate-700 dark:text-slate-400 dark:hover:bg-slate-800 dark:hover:text-slate-200\"\n >\n <XMarkIcon className=\"h-3.5 w-3.5\" aria-hidden=\"true\" />\n Clear {activeCount} {activeCount === 1 ? \"filter\" : \"filters\"}\n </button>\n ) : null}\n </div>\n );\n}\n"],"names":["FilterBar","filters","values","onChange","onReset","activeCount","layout","isStacked","jsxs","filter","val","jsx","SearchFilter","v","SelectFilter","ToggleFilter","XMarkIcon"],"mappings":";;;;;AA2BA,SAAwBA,EAAU;AAAA,EAChC,SAAAC,IAAU,CAAA;AAAA,EACV,QAAAC,IAAS,CAAA;AAAA,EACT,UAAAC;AAAA,EACA,SAAAC;AAAA,EACA,aAAAC,IAAc;AAAA,EACd,QAAAC,IAAS;AACX,GAAmB;AACjB,MAAI,CAACL,EAAQ,OAAQ,QAAO;AAE5B,QAAMM,IAAYD,MAAW;AAE7B,SACE,gBAAAE;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACAD,IACI,aACA;AAAA,MAAA,EACJ,KAAK,GAAG;AAAA,MAET,UAAA;AAAA,QAAAN,EAAQ,IAAI,CAACQ,MAAW;AACvB,gBAAMC,IAAMR,EAAOO,EAAO,EAAE;AAE5B,kBAAQA,EAAO,MAAA;AAAA,YACb,KAAK;AACH,qBACE,gBAAAE;AAAA,gBAACC;AAAA,gBAAA;AAAA,kBAEC,OAAOF,KAAO;AAAA,kBACd,UAAU,CAACG,MAAMV,IAAWM,EAAO,IAAII,CAAC;AAAA,kBACxC,aAAaJ,EAAO,eAAe;AAAA,kBACnC,WAAWA,EAAO,cAAcF,IAAY,WAAW;AAAA,gBAAA;AAAA,gBAJlDE,EAAO;AAAA,cAAA;AAAA,YAQlB,KAAK;AACH,qBACE,gBAAAE;AAAA,gBAACG;AAAA,gBAAA;AAAA,kBAEC,OAAOJ,KAAO;AAAA,kBACd,UAAU,CAACG,MAAMV,IAAWM,EAAO,IAAII,CAAC;AAAA,kBACxC,SAASJ,EAAO,WAAW,CAAA;AAAA,kBAC3B,OAAOA,EAAO;AAAA,kBACd,aAAaA,EAAO,eAAe;AAAA,kBACnC,WAAWA,EAAO;AAAA,gBAAA;AAAA,gBANbA,EAAO;AAAA,cAAA;AAAA,YAUlB,KAAK;AACH,qBACE,gBAAAE;AAAA,gBAACI;AAAA,gBAAA;AAAA,kBAEC,OAAOL,KAAO;AAAA,kBACd,UAAU,CAACG,MAAMV,IAAWM,EAAO,IAAII,CAAC;AAAA,kBACxC,OAAOJ,EAAO;AAAA,kBACd,WAAWA,EAAO;AAAA,gBAAA;AAAA,gBAJbA,EAAO;AAAA,cAAA;AAAA,YAQlB;AACE,qBAAO;AAAA,UAAA;AAAA,QAEb,CAAC;AAAA,QAEAJ,IAAc,KAAKD,IAClB,gBAAAI;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL,SAASJ;AAAA,YACT,WAAU;AAAA,YAEV,UAAA;AAAA,cAAA,gBAAAO,EAACK,GAAA,EAAU,WAAU,eAAc,eAAY,QAAO;AAAA,cAAE;AAAA,cACjDX;AAAA,cAAY;AAAA,cAAEA,MAAgB,IAAI,WAAW;AAAA,YAAA;AAAA,UAAA;AAAA,QAAA,IAEpD;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGV;"}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
export
|
|
2
|
-
value?: string
|
|
3
|
-
onChange:
|
|
4
|
-
placeholder?: string
|
|
5
|
-
className?: string
|
|
6
|
-
}
|
|
1
|
+
export interface SearchFilterProps {
|
|
2
|
+
value?: string;
|
|
3
|
+
onChange?: (value: string) => void;
|
|
4
|
+
placeholder?: string;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
7
|
+
export default function SearchFilter({ value, onChange, placeholder, className, }: SearchFilterProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { jsxs as o, jsx as e } from "react/jsx-runtime";
|
|
2
|
-
import "react";
|
|
3
2
|
import { MagnifyingGlassIcon as n, XMarkIcon as i } from "@heroicons/react/24/outline";
|
|
4
|
-
function
|
|
3
|
+
function u({
|
|
5
4
|
value: t = "",
|
|
6
5
|
onChange: a,
|
|
7
6
|
placeholder: r = "Search…",
|
|
@@ -39,6 +38,6 @@ function f({
|
|
|
39
38
|
] });
|
|
40
39
|
}
|
|
41
40
|
export {
|
|
42
|
-
|
|
41
|
+
u as default
|
|
43
42
|
};
|
|
44
43
|
//# sourceMappingURL=SearchFilter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SearchFilter.js","sources":["../../../../src/components/library/filters/SearchFilter.
|
|
1
|
+
{"version":3,"file":"SearchFilter.js","sources":["../../../../src/components/library/filters/SearchFilter.tsx"],"sourcesContent":["import { MagnifyingGlassIcon, XMarkIcon } from \"@heroicons/react/24/outline\";\n\nexport interface SearchFilterProps {\n value?: string;\n onChange?: (value: string) => void;\n placeholder?: string;\n className?: string;\n}\n\nexport default function SearchFilter({\n value = \"\",\n onChange,\n placeholder = \"Search…\",\n className = \"\",\n}: SearchFilterProps) {\n return (\n <div className={[\"relative\", className].filter(Boolean).join(\" \")}>\n <MagnifyingGlassIcon\n className=\"pointer-events-none absolute left-3 top-1/2 h-4 w-4 -translate-y-1/2 text-slate-400 dark:text-slate-500\"\n aria-hidden=\"true\"\n />\n <input\n type=\"text\"\n value={value}\n onChange={(e) => onChange?.(e.target.value)}\n placeholder={placeholder}\n className=\"h-9 w-full rounded-lg border border-slate-200 bg-white pl-9 pr-8 text-sm text-slate-900 shadow-sm placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-brand-500 focus:ring-offset-2 dark:border-slate-800 dark:bg-slate-900 dark:text-slate-50 dark:placeholder:text-slate-500 dark:focus:ring-offset-slate-950\"\n aria-label={placeholder}\n />\n {value ? (\n <button\n type=\"button\"\n onClick={() => onChange?.(\"\")}\n className=\"absolute right-2 top-1/2 -translate-y-1/2 rounded p-0.5 text-slate-400 hover:text-slate-600 dark:text-slate-500 dark:hover:text-slate-300\"\n aria-label=\"Clear search\"\n >\n <XMarkIcon className=\"h-4 w-4\" />\n </button>\n ) : null}\n </div>\n );\n}\n"],"names":["SearchFilter","value","onChange","placeholder","className","jsxs","jsx","MagnifyingGlassIcon","e","XMarkIcon"],"mappings":";;AASA,SAAwBA,EAAa;AAAA,EACnC,OAAAC,IAAQ;AAAA,EACR,UAAAC;AAAA,EACA,aAAAC,IAAc;AAAA,EACd,WAAAC,IAAY;AACd,GAAsB;AACpB,SACE,gBAAAC,EAAC,OAAA,EAAI,WAAW,CAAC,YAAYD,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GAC9D,UAAA;AAAA,IAAA,gBAAAE;AAAA,MAACC;AAAA,MAAA;AAAA,QACC,WAAU;AAAA,QACV,eAAY;AAAA,MAAA;AAAA,IAAA;AAAA,IAEd,gBAAAD;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,OAAAL;AAAA,QACA,UAAU,CAACO,MAAMN,IAAWM,EAAE,OAAO,KAAK;AAAA,QAC1C,aAAAL;AAAA,QACA,WAAU;AAAA,QACV,cAAYA;AAAA,MAAA;AAAA,IAAA;AAAA,IAEbF,IACC,gBAAAK;AAAA,MAAC;AAAA,MAAA;AAAA,QACC,MAAK;AAAA,QACL,SAAS,MAAMJ,IAAW,EAAE;AAAA,QAC5B,WAAU;AAAA,QACV,cAAW;AAAA,QAEX,UAAA,gBAAAI,EAACG,GAAA,EAAU,WAAU,UAAA,CAAU;AAAA,MAAA;AAAA,IAAA,IAE/B;AAAA,EAAA,GACN;AAEJ;"}
|
|
@@ -1,10 +1,16 @@
|
|
|
1
|
+
export interface SelectOption {
|
|
2
|
+
value: string;
|
|
3
|
+
label: string;
|
|
4
|
+
}
|
|
5
|
+
export interface SelectFilterProps {
|
|
6
|
+
value?: string;
|
|
7
|
+
onChange?: (value: string) => void;
|
|
8
|
+
options?: (string | SelectOption)[];
|
|
9
|
+
label?: string;
|
|
10
|
+
placeholder?: string;
|
|
11
|
+
className?: string;
|
|
12
|
+
}
|
|
1
13
|
/**
|
|
2
14
|
* Dropdown select filter.
|
|
3
|
-
*
|
|
4
|
-
* @param {string} value — current selected value
|
|
5
|
-
* @param {Function} onChange — (value) => void
|
|
6
|
-
* @param {Array} options — [{ value, label }] or ["string", ...]
|
|
7
|
-
* @param {string} label — visible label
|
|
8
|
-
* @param {string} placeholder — placeholder when no value selected
|
|
9
15
|
*/
|
|
10
|
-
export default function SelectFilter({ value, onChange, options, label, placeholder, className, }:
|
|
16
|
+
export default function SelectFilter({ value, onChange, options, label, placeholder, className, }: SelectFilterProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { jsxs as n, jsx as t } from "react/jsx-runtime";
|
|
2
|
-
import "react";
|
|
3
2
|
import { ChevronDownIcon as u } from "@heroicons/react/24/outline";
|
|
4
|
-
function
|
|
3
|
+
function f({
|
|
5
4
|
value: r = "all",
|
|
6
5
|
onChange: s,
|
|
7
6
|
options: i = [],
|
|
@@ -39,6 +38,6 @@ function h({
|
|
|
39
38
|
] });
|
|
40
39
|
}
|
|
41
40
|
export {
|
|
42
|
-
|
|
41
|
+
f as default
|
|
43
42
|
};
|
|
44
43
|
//# sourceMappingURL=SelectFilter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"SelectFilter.js","sources":["../../../../src/components/library/filters/SelectFilter.
|
|
1
|
+
{"version":3,"file":"SelectFilter.js","sources":["../../../../src/components/library/filters/SelectFilter.tsx"],"sourcesContent":["import { ChevronDownIcon } from \"@heroicons/react/24/outline\";\n\nexport interface SelectOption {\n value: string;\n label: string;\n}\n\nexport interface SelectFilterProps {\n value?: string;\n onChange?: (value: string) => void;\n options?: (string | SelectOption)[];\n label?: string;\n placeholder?: string;\n className?: string;\n}\n\n/**\n * Dropdown select filter.\n */\nexport default function SelectFilter({\n value = \"all\",\n onChange,\n options = [],\n label,\n placeholder,\n className = \"\",\n}: SelectFilterProps) {\n const normalizedOptions = options.map((opt) =>\n typeof opt === \"string\" ? { value: opt, label: opt } : opt\n );\n\n return (\n <div className={[\"relative inline-flex items-center gap-2\", className].filter(Boolean).join(\" \")}>\n {label ? (\n <span className=\"shrink-0 text-xs font-medium text-slate-500 dark:text-slate-400\">\n {label}\n </span>\n ) : null}\n <div className=\"relative\">\n <select\n value={value}\n onChange={(e) => onChange?.(e.target.value)}\n className=\"h-9 appearance-none rounded-lg border border-slate-200 bg-white py-0 pl-3 pr-8 text-sm font-medium text-slate-700 shadow-sm focus:outline-none focus:ring-2 focus:ring-brand-500 focus:ring-offset-2 dark:border-slate-800 dark:bg-slate-900 dark:text-slate-200 dark:focus:ring-offset-slate-950\"\n aria-label={label ?? placeholder ?? \"Filter\"}\n >\n {placeholder ? (\n <option value=\"all\">{placeholder}</option>\n ) : null}\n {normalizedOptions.map((opt) => (\n <option key={opt.value} value={opt.value}>\n {opt.label}\n </option>\n ))}\n </select>\n <ChevronDownIcon\n className=\"pointer-events-none absolute right-2 top-1/2 h-4 w-4 -translate-y-1/2 text-slate-400 dark:text-slate-500\"\n aria-hidden=\"true\"\n />\n </div>\n </div>\n );\n}\n"],"names":["SelectFilter","value","onChange","options","label","placeholder","className","normalizedOptions","opt","jsxs","jsx","ChevronDownIcon"],"mappings":";;AAmBA,SAAwBA,EAAa;AAAA,EACnC,OAAAC,IAAQ;AAAA,EACR,UAAAC;AAAA,EACA,SAAAC,IAAU,CAAA;AAAA,EACV,OAAAC;AAAA,EACA,aAAAC;AAAA,EACA,WAAAC,IAAY;AACd,GAAsB;AACpB,QAAMC,IAAoBJ,EAAQ;AAAA,IAAI,CAACK,MACrC,OAAOA,KAAQ,WAAW,EAAE,OAAOA,GAAK,OAAOA,MAAQA;AAAA,EAAA;AAGzD,SACE,gBAAAC,EAAC,OAAA,EAAI,WAAW,CAAC,2CAA2CH,CAAS,EAAE,OAAO,OAAO,EAAE,KAAK,GAAG,GAC5F,UAAA;AAAA,IAAAF,IACC,gBAAAM,EAAC,QAAA,EAAK,WAAU,mEACb,aACH,IACE;AAAA,IACJ,gBAAAD,EAAC,OAAA,EAAI,WAAU,YACb,UAAA;AAAA,MAAA,gBAAAA;AAAA,QAAC;AAAA,QAAA;AAAA,UACC,OAAAR;AAAA,UACA,UAAU,CAAC,MAAMC,IAAW,EAAE,OAAO,KAAK;AAAA,UAC1C,WAAU;AAAA,UACV,cAAYE,KAASC,KAAe;AAAA,UAEnC,UAAA;AAAA,YAAAA,IACC,gBAAAK,EAAC,UAAA,EAAO,OAAM,OAAO,aAAY,IAC/B;AAAA,YACHH,EAAkB,IAAI,CAACC,MACtB,gBAAAE,EAAC,UAAA,EAAuB,OAAOF,EAAI,OAChC,UAAAA,EAAI,MAAA,GADMA,EAAI,KAEjB,CACD;AAAA,UAAA;AAAA,QAAA;AAAA,MAAA;AAAA,MAEH,gBAAAE;AAAA,QAACC;AAAA,QAAA;AAAA,UACC,WAAU;AAAA,UACV,eAAY;AAAA,QAAA;AAAA,MAAA;AAAA,IACd,EAAA,CACF;AAAA,EAAA,GACF;AAEJ;"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
+
export interface ToggleFilterProps {
|
|
2
|
+
value?: boolean;
|
|
3
|
+
onChange?: (value: boolean) => void;
|
|
4
|
+
label?: string;
|
|
5
|
+
className?: string;
|
|
6
|
+
}
|
|
1
7
|
/**
|
|
2
8
|
* Toggle switch filter.
|
|
3
|
-
*
|
|
4
|
-
* @param {boolean} value — current on/off state
|
|
5
|
-
* @param {Function} onChange — (boolean) => void
|
|
6
|
-
* @param {string} label — visible label
|
|
7
9
|
*/
|
|
8
|
-
export default function ToggleFilter({ value, onChange, label, className, }:
|
|
10
|
+
export default function ToggleFilter({ value, onChange, label, className, }: ToggleFilterProps): import("react/jsx-runtime").JSX.Element;
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { jsxs as o, jsx as n } from "react/jsx-runtime";
|
|
2
|
-
|
|
3
|
-
function l({
|
|
2
|
+
function a({
|
|
4
3
|
value: e = !1,
|
|
5
4
|
onChange: r,
|
|
6
5
|
label: t,
|
|
@@ -43,6 +42,6 @@ function l({
|
|
|
43
42
|
);
|
|
44
43
|
}
|
|
45
44
|
export {
|
|
46
|
-
|
|
45
|
+
a as default
|
|
47
46
|
};
|
|
48
47
|
//# sourceMappingURL=ToggleFilter.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ToggleFilter.js","sources":["../../../../src/components/library/filters/ToggleFilter.
|
|
1
|
+
{"version":3,"file":"ToggleFilter.js","sources":["../../../../src/components/library/filters/ToggleFilter.tsx"],"sourcesContent":["export interface ToggleFilterProps {\n value?: boolean;\n onChange?: (value: boolean) => void;\n label?: string;\n className?: string;\n}\n\n/**\n * Toggle switch filter.\n */\nexport default function ToggleFilter({\n value = false,\n onChange,\n label,\n className = \"\",\n}: ToggleFilterProps) {\n return (\n <label\n className={[\n \"inline-flex cursor-pointer items-center gap-2\",\n className,\n ]\n .filter(Boolean)\n .join(\" \")}\n >\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={value}\n onClick={() => onChange?.(!value)}\n className={[\n \"relative inline-flex h-5 w-9 shrink-0 rounded-full border-2 border-transparent transition-colors focus:outline-none focus:ring-2 focus:ring-brand-500 focus:ring-offset-2 dark:focus:ring-offset-slate-950\",\n value\n ? \"bg-brand-500\"\n : \"bg-slate-200 dark:bg-slate-700\",\n ].join(\" \")}\n >\n <span\n aria-hidden=\"true\"\n className={[\n \"pointer-events-none inline-block h-4 w-4 rounded-full bg-white shadow ring-0 transition-transform\",\n value ? \"translate-x-4\" : \"translate-x-0\",\n ].join(\" \")}\n />\n </button>\n {label ? (\n <span className=\"text-sm font-medium text-slate-700 dark:text-slate-200\">\n {label}\n </span>\n ) : null}\n </label>\n );\n}\n"],"names":["ToggleFilter","value","onChange","label","className","jsxs","jsx"],"mappings":";AAUA,SAAwBA,EAAa;AAAA,EACnC,OAAAC,IAAQ;AAAA,EACR,UAAAC;AAAA,EACA,OAAAC;AAAA,EACA,WAAAC,IAAY;AACd,GAAsB;AACpB,SACE,gBAAAC;AAAA,IAAC;AAAA,IAAA;AAAA,MACC,WAAW;AAAA,QACT;AAAA,QACAD;AAAA,MAAA,EAEC,OAAO,OAAO,EACd,KAAK,GAAG;AAAA,MAEX,UAAA;AAAA,QAAA,gBAAAE;AAAA,UAAC;AAAA,UAAA;AAAA,YACC,MAAK;AAAA,YACL,MAAK;AAAA,YACL,gBAAcL;AAAA,YACd,SAAS,MAAMC,IAAW,CAACD,CAAK;AAAA,YAChC,WAAW;AAAA,cACT;AAAA,cACAA,IACI,iBACA;AAAA,YAAA,EACJ,KAAK,GAAG;AAAA,YAEV,UAAA,gBAAAK;AAAA,cAAC;AAAA,cAAA;AAAA,gBACC,eAAY;AAAA,gBACZ,WAAW;AAAA,kBACT;AAAA,kBACAL,IAAQ,kBAAkB;AAAA,gBAAA,EAC1B,KAAK,GAAG;AAAA,cAAA;AAAA,YAAA;AAAA,UACZ;AAAA,QAAA;AAAA,QAEDE,IACC,gBAAAG,EAAC,QAAA,EAAK,WAAU,0DACb,aACH,IACE;AAAA,MAAA;AAAA,IAAA;AAAA,EAAA;AAGV;"}
|
|
@@ -1,12 +1,14 @@
|
|
|
1
|
+
import type { FormField as FormFieldType } from "./FormRenderer";
|
|
2
|
+
export interface FormFieldProps {
|
|
3
|
+
field: FormFieldType & Record<string, unknown>;
|
|
4
|
+
value: unknown;
|
|
5
|
+
error?: string;
|
|
6
|
+
touched?: boolean;
|
|
7
|
+
onChange: (value: unknown) => void;
|
|
8
|
+
onBlur: () => void;
|
|
9
|
+
}
|
|
1
10
|
/**
|
|
2
11
|
* Renders a single form field with label, description, error message,
|
|
3
12
|
* and the appropriate input type.
|
|
4
13
|
*/
|
|
5
|
-
export default function FormField({ field, value, error, touched, onChange, onBlur }:
|
|
6
|
-
field: any;
|
|
7
|
-
value: any;
|
|
8
|
-
error: any;
|
|
9
|
-
touched: any;
|
|
10
|
-
onChange: any;
|
|
11
|
-
onBlur: any;
|
|
12
|
-
}): import("react/jsx-runtime").JSX.Element | null;
|
|
14
|
+
export default function FormField({ field, value, error, touched, onChange, onBlur }: FormFieldProps): import("react/jsx-runtime").JSX.Element | null;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { jsxs as c, jsx as r } from "react/jsx-runtime";
|
|
2
|
-
import "react";
|
|
3
2
|
import { ChevronDownIcon as m } from "@heroicons/react/24/outline";
|
|
4
3
|
const p = "h-10 w-full rounded-lg border border-slate-200 bg-white px-3 text-sm text-slate-900 shadow-sm placeholder:text-slate-400 focus:outline-none focus:ring-2 focus:ring-brand-500 focus:ring-offset-2 dark:border-slate-800 dark:bg-slate-900 dark:text-slate-50 dark:placeholder:text-slate-500 dark:focus:ring-offset-slate-950", x = "border-red-300 focus:ring-red-500 dark:border-red-700 dark:focus:ring-red-500";
|
|
5
4
|
function i(...e) {
|
|
@@ -229,7 +228,7 @@ const E = {
|
|
|
229
228
|
checkboxGroup: F,
|
|
230
229
|
toggle: C
|
|
231
230
|
};
|
|
232
|
-
function
|
|
231
|
+
function L({ field: e, value: n, error: s, touched: a, onChange: d, onBlur: t }) {
|
|
233
232
|
const o = E[e.type];
|
|
234
233
|
if (!o) return null;
|
|
235
234
|
const l = s && a, b = e.type === "checkbox";
|
|
@@ -243,7 +242,7 @@ function O({ field: e, value: n, error: s, touched: a, onChange: d, onBlur: t })
|
|
|
243
242
|
value: n,
|
|
244
243
|
onChange: d,
|
|
245
244
|
onBlur: t,
|
|
246
|
-
error: l
|
|
245
|
+
error: !!l
|
|
247
246
|
}
|
|
248
247
|
),
|
|
249
248
|
e.type === "toggle" && e.description ? /* @__PURE__ */ r(g, { description: e.description }) : null,
|
|
@@ -251,6 +250,6 @@ function O({ field: e, value: n, error: s, touched: a, onChange: d, onBlur: t })
|
|
|
251
250
|
] });
|
|
252
251
|
}
|
|
253
252
|
export {
|
|
254
|
-
|
|
253
|
+
L as default
|
|
255
254
|
};
|
|
256
255
|
//# sourceMappingURL=FormField.js.map
|