@juv/codego-react-ui 1.1.7 → 3.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/dist/index.cjs CHANGED
@@ -5050,6 +5050,45 @@ function addTerrain(map) {
5050
5050
  });
5051
5051
  }
5052
5052
  }
5053
+ var OSRM_PROFILE2 = { drive: "driving", walk: "foot" };
5054
+ async function fetchOsrmRoute2(points, routeType) {
5055
+ const profile = OSRM_PROFILE2[routeType];
5056
+ const coords = points.map((p) => `${p.lng},${p.lat}`).join(";");
5057
+ const res = await fetch(`https://router.project-osrm.org/route/v1/${profile}/${coords}?overview=full&geometries=geojson`);
5058
+ if (!res.ok) throw new Error("OSRM failed");
5059
+ const data = await res.json();
5060
+ if (data.code !== "Ok" || !data.routes?.length) throw new Error("No route");
5061
+ const route = data.routes[0];
5062
+ return {
5063
+ coords: route.geometry.coordinates,
5064
+ // already [lng, lat] for MapLibre
5065
+ distance: route.distance,
5066
+ duration: route.duration
5067
+ };
5068
+ }
5069
+ function fmtDistance2(m) {
5070
+ return m >= 1e3 ? `${(m / 1e3).toFixed(1)} km` : `${Math.round(m)} m`;
5071
+ }
5072
+ function fmtDuration2(s) {
5073
+ const h = Math.floor(s / 3600), m = Math.floor(s % 3600 / 60);
5074
+ return h > 0 ? `${h}h ${m}min` : `${m} min`;
5075
+ }
5076
+ function makeClusterHTML(variant, count, color) {
5077
+ if (variant === "bubble") {
5078
+ const size = count > 99 ? 52 : count > 9 ? 44 : 36;
5079
+ return `<div style="width:${size}px;height:${size}px;border-radius:50%;background:${color};color:#fff;font-weight:700;font-size:${count > 99 ? 11 : 13}px;font-family:sans-serif;display:flex;align-items:center;justify-content:center;border:3px solid white;box-shadow:0 2px 8px rgba(0,0,0,.3);">${count}</div>`;
5080
+ }
5081
+ if (variant === "donut") {
5082
+ const r = 20, stroke = 5, circ = 2 * Math.PI * r;
5083
+ const dash = Math.min(count / 50, 1) * circ;
5084
+ return `<svg width="54" height="54" viewBox="0 0 54 54"><circle cx="27" cy="27" r="${r}" fill="none" stroke="${color}33" stroke-width="${stroke}"/><circle cx="27" cy="27" r="${r}" fill="none" stroke="${color}" stroke-width="${stroke}" stroke-dasharray="${dash} ${circ}" stroke-dashoffset="${circ / 4}" stroke-linecap="round"/><circle cx="27" cy="27" r="${r - stroke - 2}" fill="${color}22"/><text x="27" y="27" text-anchor="middle" dominant-baseline="middle" font-size="12" font-weight="700" fill="${color}" font-family="sans-serif">${count}</text></svg>`;
5085
+ }
5086
+ const w = count > 99 ? 52 : 40;
5087
+ return `<div style="min-width:${w}px;height:28px;border-radius:14px;background:${color};color:#fff;font-weight:700;font-size:12px;font-family:sans-serif;display:flex;align-items:center;justify-content:center;padding:0 8px;border:2px solid white;box-shadow:0 2px 8px rgba(0,0,0,.25);">${count}</div>`;
5088
+ }
5089
+ function makeEndpointHTML(color, label) {
5090
+ return `<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 28 28"><circle cx="14" cy="14" r="12" fill="${color}" stroke="white" stroke-width="2.5"/><text x="14" y="14" text-anchor="middle" dominant-baseline="middle" font-size="12" font-weight="700" fill="white" font-family="sans-serif">${label}</text></svg>`;
5091
+ }
5053
5092
  function MapLibreMap({
5054
5093
  style: styleProp = "street",
5055
5094
  center = [0, 20],
@@ -5064,6 +5103,9 @@ function MapLibreMap({
5064
5103
  maxBearing = 180,
5065
5104
  flyTo,
5066
5105
  markers = [],
5106
+ routes = [],
5107
+ cluster = false,
5108
+ clusterVariant = "default",
5067
5109
  height = 480,
5068
5110
  showControls = true,
5069
5111
  showStyleSwitcher = true,
@@ -5074,7 +5116,9 @@ function MapLibreMap({
5074
5116
  const containerRef = React22.useRef(null);
5075
5117
  const mapRef = React22.useRef(null);
5076
5118
  const markersRef = React22.useRef([]);
5119
+ const routeMarkersRef = React22.useRef([]);
5077
5120
  const flyingRef = React22.useRef(false);
5121
+ const [routeLoading, setRouteLoading] = React22.useState(false);
5078
5122
  const [activeStyle, setActiveStyle] = React22.useState(styleProp);
5079
5123
  const [ready, setReady] = React22.useState(false);
5080
5124
  const [showCamera, setShowCamera] = React22.useState(false);
@@ -5162,6 +5206,109 @@ function MapLibreMap({
5162
5206
  if (ftBearing !== void 0) setBearing(clampBearing(ftBearing));
5163
5207
  });
5164
5208
  }, [flyTo]);
5209
+ React22.useEffect(() => {
5210
+ const map = mapRef.current;
5211
+ if (!map || !ready || routes.length === 0) return;
5212
+ function cleanRoutes() {
5213
+ routeMarkersRef.current.forEach((m) => m.remove());
5214
+ routeMarkersRef.current = [];
5215
+ const style = map.getStyle();
5216
+ (style.layers ?? []).forEach((l) => {
5217
+ if (l.id.startsWith("route-")) try {
5218
+ map.removeLayer(l.id);
5219
+ } catch {
5220
+ }
5221
+ });
5222
+ Object.keys(style.sources ?? {}).forEach((s) => {
5223
+ if (s.startsWith("route-")) try {
5224
+ map.removeSource(s);
5225
+ } catch {
5226
+ }
5227
+ });
5228
+ }
5229
+ cleanRoutes();
5230
+ setRouteLoading(true);
5231
+ Promise.all(
5232
+ routes.map(async (r, i) => {
5233
+ const points = [r.start, ...r.waypoints ?? [], r.end];
5234
+ try {
5235
+ const result = await fetchOsrmRoute2(points, r.routeType ?? "drive");
5236
+ return { route: r, idx: i, ...result, error: false };
5237
+ } catch {
5238
+ return { route: r, idx: i, coords: points.map((p) => [p.lng, p.lat]), distance: 0, duration: 0, error: true };
5239
+ }
5240
+ })
5241
+ ).then((results) => {
5242
+ setRouteLoading(false);
5243
+ if (!mapRef.current) return;
5244
+ const m = mapRef.current;
5245
+ const allCoords = [];
5246
+ results.forEach(({ route, idx, coords, distance, duration }) => {
5247
+ const color = route.color ?? (route.routeType === "walk" ? "#22c55e" : "#6366f1");
5248
+ const srcId = `route-${idx}`;
5249
+ const geojson = {
5250
+ type: "Feature",
5251
+ properties: {},
5252
+ geometry: { type: "LineString", coordinates: coords }
5253
+ };
5254
+ m.addSource(srcId, { type: "geojson", data: geojson });
5255
+ m.addLayer({
5256
+ id: `${srcId}-outline`,
5257
+ type: "line",
5258
+ source: srcId,
5259
+ layout: { "line-cap": "round", "line-join": "round" },
5260
+ paint: { "line-color": "#ffffff", "line-width": (route.weight ?? 5) + 4, "line-opacity": 0.3 }
5261
+ });
5262
+ m.addLayer({
5263
+ id: `${srcId}-line`,
5264
+ type: "line",
5265
+ source: srcId,
5266
+ layout: { "line-cap": "round", "line-join": "round" },
5267
+ paint: { "line-color": color, "line-width": route.weight ?? 5, "line-opacity": 0.9 }
5268
+ });
5269
+ allCoords.push(...coords);
5270
+ const makeEndpointMarker = (lngLat, label, markerColor, popupHtml) => {
5271
+ const el = document.createElement("div");
5272
+ el.innerHTML = makeEndpointHTML(markerColor, label);
5273
+ el.style.cssText = "width:28px;height:28px";
5274
+ const popup = new import_maplibre_gl.default.Popup({ offset: [0, -16], closeButton: false }).setHTML(popupHtml);
5275
+ const marker = new import_maplibre_gl.default.Marker({ element: el, anchor: "center" }).setLngLat(lngLat).setPopup(popup).addTo(m);
5276
+ routeMarkersRef.current.push(marker);
5277
+ };
5278
+ const infoHtml = distance > 0 ? `<p style="font-size:11px;color:#888;margin:2px 0 0">${fmtDistance2(distance)} \xB7 ${fmtDuration2(duration)} \xB7 ${route.routeType === "walk" ? "\u{1F6B6} Walk" : "\u{1F697} Drive"}</p>` : "";
5279
+ makeEndpointMarker(
5280
+ [route.start.lng, route.start.lat],
5281
+ "A",
5282
+ color,
5283
+ `<div style="padding:2px;min-width:120px"><p style="font-weight:700;font-size:13px;margin:0">${route.label ? `${route.label} \u2014 Start` : "Start"}</p>${infoHtml}</div>`
5284
+ );
5285
+ makeEndpointMarker(
5286
+ [route.end.lng, route.end.lat],
5287
+ "B",
5288
+ "#ef4444",
5289
+ `<div style="padding:2px;min-width:120px"><p style="font-weight:700;font-size:13px;margin:0">${route.label ? `${route.label} \u2014 End` : "End"}</p>${infoHtml}</div>`
5290
+ );
5291
+ if (distance > 0 && coords.length > 1) {
5292
+ const mid = coords[Math.floor(coords.length / 2)];
5293
+ const text = `${fmtDistance2(distance)} \xB7 ${fmtDuration2(duration)}`;
5294
+ const estW = text.length * 7 + 16;
5295
+ const el = document.createElement("div");
5296
+ el.innerHTML = `<div style="display:inline-flex;align-items:center;justify-content:center;background:${color};color:white;font-size:11px;font-weight:600;font-family:sans-serif;padding:3px 8px;border-radius:12px;border:2px solid white;box-shadow:0 2px 6px rgba(0,0,0,.25);white-space:nowrap;">${text}</div>`;
5297
+ el.style.cssText = `width:${estW}px;height:22px;pointer-events:none`;
5298
+ const badge = new import_maplibre_gl.default.Marker({ element: el, anchor: "center" }).setLngLat(mid).addTo(m);
5299
+ routeMarkersRef.current.push(badge);
5300
+ }
5301
+ });
5302
+ if (allCoords.length > 1) {
5303
+ const lngs = allCoords.map((c) => c[0]), lats = allCoords.map((c) => c[1]);
5304
+ m.fitBounds(
5305
+ [[Math.min(...lngs), Math.min(...lats)], [Math.max(...lngs), Math.max(...lats)]],
5306
+ { padding: 60, duration: 800 }
5307
+ );
5308
+ }
5309
+ });
5310
+ return cleanRoutes;
5311
+ }, [routes, ready]);
5165
5312
  function switchStyle(s) {
5166
5313
  const map = mapRef.current;
5167
5314
  if (!map) return;
@@ -5169,6 +5316,8 @@ function MapLibreMap({
5169
5316
  setReady(false);
5170
5317
  markersRef.current.forEach((m) => m.remove());
5171
5318
  markersRef.current = [];
5319
+ routeMarkersRef.current.forEach((m) => m.remove());
5320
+ routeMarkersRef.current = [];
5172
5321
  map.setStyle(s === "satellite" ? SATELLITE_STYLE : STYLE_URLS[s]);
5173
5322
  map.once("style.load", () => {
5174
5323
  if (s === "globe") {
@@ -5200,32 +5349,107 @@ function MapLibreMap({
5200
5349
  setReady(true);
5201
5350
  });
5202
5351
  }
5352
+ const [mapZoom, setMapZoom] = React22.useState(zoom);
5353
+ React22.useEffect(() => {
5354
+ const map = mapRef.current;
5355
+ if (!map) return;
5356
+ const h2 = () => setMapZoom(map.getZoom());
5357
+ map.on("zoomend", h2);
5358
+ return () => {
5359
+ map.off("zoomend", h2);
5360
+ };
5361
+ }, [ready]);
5203
5362
  React22.useEffect(() => {
5204
5363
  const map = mapRef.current;
5205
5364
  if (!map || !ready) return;
5206
5365
  markersRef.current.forEach((m) => m.remove());
5207
5366
  markersRef.current = [];
5208
- markers.forEach((m) => {
5209
- const color = resolveColor2(m.color);
5210
- const el = document.createElement("div");
5211
- el.innerHTML = makePinHTML(color, m.icon, m.image);
5212
- el.style.cssText = m.image ? "width:40px;height:50px" : "width:32px;height:42px";
5213
- const popup = new import_maplibre_gl.default.Popup({ offset: m.image ? [0, -52] : [0, -44], closeButton: false });
5214
- if (m.popup) {
5215
- if (typeof m.popup === "string") popup.setHTML(m.popup);
5216
- else popup.setDOMContent(m.popup);
5217
- } else if (m.label) {
5218
- popup.setHTML(`<span style="font-size:13px;font-weight:600">${m.label}</span>`);
5219
- }
5220
- const marker = new import_maplibre_gl.default.Marker({ element: el, anchor: "bottom" }).setLngLat([m.lng, m.lat]);
5221
- if (m.popup || m.label) marker.setPopup(popup);
5222
- el.addEventListener("click", () => onMarkerClick?.(m));
5223
- marker.addTo(map);
5224
- markersRef.current.push(marker);
5225
- });
5226
- }, [markers, ready, onMarkerClick]);
5367
+ if (cluster && markers.length > 0) {
5368
+ const GRID = 80;
5369
+ const used = /* @__PURE__ */ new Set();
5370
+ const groups = [];
5371
+ markers.forEach((m, i) => {
5372
+ if (used.has(i)) return;
5373
+ const pt = map.project([m.lng, m.lat]);
5374
+ const group = [m];
5375
+ used.add(i);
5376
+ markers.forEach((m2, j) => {
5377
+ if (used.has(j)) return;
5378
+ const pt2 = map.project([m2.lng, m2.lat]);
5379
+ if (Math.abs(pt.x - pt2.x) < GRID && Math.abs(pt.y - pt2.y) < GRID) {
5380
+ group.push(m2);
5381
+ used.add(j);
5382
+ }
5383
+ });
5384
+ const lat = group.reduce((s, x) => s + x.lat, 0) / group.length;
5385
+ const lng = group.reduce((s, x) => s + x.lng, 0) / group.length;
5386
+ groups.push({ center: { lng, lat }, items: group });
5387
+ });
5388
+ groups.forEach((g, gi) => {
5389
+ if (g.items.length === 1) {
5390
+ const m = g.items[0];
5391
+ const color = resolveColor2(m.color);
5392
+ const el = document.createElement("div");
5393
+ el.innerHTML = makePinHTML(color, m.icon, m.image);
5394
+ el.style.cssText = m.image ? "width:40px;height:50px" : "width:32px;height:42px";
5395
+ const popup = new import_maplibre_gl.default.Popup({ offset: m.image ? [0, -52] : [0, -44], closeButton: false });
5396
+ if (m.popup) {
5397
+ typeof m.popup === "string" ? popup.setHTML(m.popup) : popup.setDOMContent(m.popup);
5398
+ } else if (m.label) popup.setHTML(`<span style="font-size:13px;font-weight:600">${m.label}</span>`);
5399
+ const marker = new import_maplibre_gl.default.Marker({ element: el, anchor: "bottom" }).setLngLat([m.lng, m.lat]);
5400
+ if (m.popup || m.label) marker.setPopup(popup);
5401
+ el.addEventListener("click", () => onMarkerClick?.(m));
5402
+ marker.addTo(map);
5403
+ markersRef.current.push(marker);
5404
+ } else {
5405
+ const color = resolveColor2(g.items[0].color);
5406
+ const el = document.createElement("div");
5407
+ el.innerHTML = makeClusterHTML(clusterVariant, g.items.length, color);
5408
+ el.style.cssText = "cursor:pointer";
5409
+ const listItems = g.items.map(
5410
+ (m) => `<div data-id="${m.id}" style="font-size:12px;padding:2px 0;cursor:pointer;">${m.label ?? `Marker ${m.id}`}</div>`
5411
+ ).join("");
5412
+ const popup = new import_maplibre_gl.default.Popup({ offset: [0, -8], closeButton: false }).setHTML(`<div style="max-height:160px;overflow-y:auto;padding:2px">${listItems}</div>`);
5413
+ el.addEventListener("click", () => {
5414
+ map.flyTo({ center: [g.center.lng, g.center.lat], zoom: map.getZoom() + 2, duration: 400 });
5415
+ });
5416
+ const marker = new import_maplibre_gl.default.Marker({ element: el, anchor: "center" }).setLngLat([g.center.lng, g.center.lat]).setPopup(popup).addTo(map);
5417
+ markersRef.current.push(marker);
5418
+ marker.getPopup().on("open", () => {
5419
+ g.items.forEach((m) => {
5420
+ const node = document.querySelector(`[data-id="${m.id}"]`);
5421
+ node?.addEventListener("click", () => onMarkerClick?.(m));
5422
+ });
5423
+ });
5424
+ }
5425
+ });
5426
+ } else {
5427
+ markers.forEach((m) => {
5428
+ const color = resolveColor2(m.color);
5429
+ const el = document.createElement("div");
5430
+ el.innerHTML = makePinHTML(color, m.icon, m.image);
5431
+ el.style.cssText = m.image ? "width:40px;height:50px" : "width:32px;height:42px";
5432
+ const popup = new import_maplibre_gl.default.Popup({ offset: m.image ? [0, -52] : [0, -44], closeButton: false });
5433
+ if (m.popup) {
5434
+ if (typeof m.popup === "string") popup.setHTML(m.popup);
5435
+ else popup.setDOMContent(m.popup);
5436
+ } else if (m.label) {
5437
+ popup.setHTML(`<span style="font-size:13px;font-weight:600">${m.label}</span>`);
5438
+ }
5439
+ const marker = new import_maplibre_gl.default.Marker({ element: el, anchor: "bottom" }).setLngLat([m.lng, m.lat]);
5440
+ if (m.popup || m.label) marker.setPopup(popup);
5441
+ el.addEventListener("click", () => onMarkerClick?.(m));
5442
+ marker.addTo(map);
5443
+ markersRef.current.push(marker);
5444
+ });
5445
+ }
5446
+ }, [markers, ready, onMarkerClick, cluster, clusterVariant, mapZoom]);
5227
5447
  const cameraOpen = showCameraControls || showCamera;
5228
5448
  return /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: cn("relative w-full overflow-hidden rounded-2xl border border-border", className), style: { height: h }, children: [
5449
+ routeLoading && /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { className: "absolute inset-0 z-[1000] flex items-center justify-center pointer-events-none", children: /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center gap-2 bg-card/90 backdrop-blur-sm border border-border rounded-xl px-4 py-2 shadow-lg text-sm font-medium", children: [
5450
+ /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("span", { className: "h-4 w-4 rounded-full border-2 border-primary border-t-transparent animate-spin" }),
5451
+ "Calculating route\u2026"
5452
+ ] }) }),
5229
5453
  /* @__PURE__ */ (0, import_jsx_runtime27.jsx)("div", { ref: containerRef, style: { width: "100%", height: "100%" } }),
5230
5454
  cameraOpen && /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "absolute top-4 left-4 z-10 bg-card/90 backdrop-blur-sm border border-border rounded-2xl p-3 shadow-xl space-y-3 w-52", children: [
5231
5455
  /* @__PURE__ */ (0, import_jsx_runtime27.jsxs)("div", { className: "flex items-center justify-between", children: [
@@ -5560,6 +5784,7 @@ function Select({
5560
5784
  const [isSearching, setIsSearching] = React25.useState(false);
5561
5785
  const containerRef = React25.useRef(null);
5562
5786
  const triggerRef = React25.useRef(null);
5787
+ const portalRef = React25.useRef(null);
5563
5788
  const [dropStyle, setDropStyle] = React25.useState({});
5564
5789
  const getKey = React25.useCallback((opt) => String(Object.keys(opt)[0]), []);
5565
5790
  const getLabel = React25.useCallback((opt) => Object.values(opt)[0], []);
@@ -5590,9 +5815,9 @@ function Select({
5590
5815
  };
5591
5816
  React25.useEffect(() => {
5592
5817
  const handler = (e) => {
5593
- if (containerRef.current && !containerRef.current.contains(e.target)) {
5594
- setIsOpen(false);
5595
- }
5818
+ const target = e.target;
5819
+ if (containerRef.current?.contains(target) || portalRef.current?.contains(target)) return;
5820
+ setIsOpen(false);
5596
5821
  };
5597
5822
  document.addEventListener("mousedown", handler);
5598
5823
  return () => document.removeEventListener("mousedown", handler);
@@ -5735,6 +5960,7 @@ function Select({
5735
5960
  isOpen && /* @__PURE__ */ (0, import_jsx_runtime30.jsx)(FloatingPortal, { children: /* @__PURE__ */ (0, import_jsx_runtime30.jsxs)(
5736
5961
  "div",
5737
5962
  {
5963
+ ref: portalRef,
5738
5964
  className: "max-h-60 overflow-auto rounded-md border border-white/10 bg-background/80 backdrop-blur-xl text-popover-foreground shadow-lg animate-in fade-in-80",
5739
5965
  style: dropStyle,
5740
5966
  children: [
@@ -6699,67 +6925,386 @@ var import_react = require("react");
6699
6925
 
6700
6926
  // src/components/conf/settingConfig.json
6701
6927
  var settingConfig_default = {
6702
- theme: "dark",
6703
- fontSize: "16px",
6704
- fontFamily: '"Space Grotesk", "Inter", sans-serif',
6705
- colors: {
6706
- primary: "#8b5cf6",
6707
- primaryHover: "#7c3aed",
6708
- secondary: "#171717",
6709
- secondaryHover: "#262626",
6710
- info: "#3b82f6",
6711
- infoHover: "#2563eb",
6712
- warning: "#f59e0b",
6713
- warningHover: "#d97706",
6714
- danger: "#ef4444",
6715
- dangerHover: "#dc2626"
6716
- }
6928
+ defaults: {
6929
+ theme: "light",
6930
+ fontSize: "16px",
6931
+ fontFamily: '"Space Grotesk", "Inter", sans-serif',
6932
+ colors: {
6933
+ primary: "#5CF6E2",
6934
+ primaryHover: "#73F3E2",
6935
+ secondary: "#171717",
6936
+ secondaryHover: "#262626",
6937
+ info: "#3b82f6",
6938
+ infoHover: "#2563eb",
6939
+ warning: "#f59e0b",
6940
+ warningHover: "#d97706",
6941
+ danger: "#ef4444",
6942
+ dangerHover: "#dc2626"
6943
+ }
6944
+ },
6945
+ themeOptions: [
6946
+ { light: "Light" },
6947
+ { dark: "Dark" },
6948
+ { system: "System" }
6949
+ ],
6950
+ fontSizes: [
6951
+ { "14px": "Small (14px)" },
6952
+ { "16px": "Medium (16px)" },
6953
+ { "18px": "Large (18px)" },
6954
+ { "20px": "Extra Large (20px)" }
6955
+ ],
6956
+ fontFamilies: [
6957
+ { '"Space Grotesk", "Inter", sans-serif': "Space Grotesk" },
6958
+ { '"Inter", sans-serif': "Inter" },
6959
+ { '"JetBrains Mono", monospace': "JetBrains Mono" },
6960
+ { "system-ui, sans-serif": "System UI" }
6961
+ ],
6962
+ colorPairs: [
6963
+ { base: "primary", hover: "primaryHover", label: "Primary" },
6964
+ { base: "secondary", hover: "secondaryHover", label: "Secondary" },
6965
+ { base: "info", hover: "infoHover", label: "Info" },
6966
+ { base: "warning", hover: "warningHover", label: "Warning" },
6967
+ { base: "danger", hover: "dangerHover", label: "Danger" }
6968
+ ],
6969
+ colorPalette: [
6970
+ {
6971
+ base: "#6366F1",
6972
+ hover: "#4F46E5",
6973
+ info: "#F59E0B",
6974
+ infoHover: "#D97706"
6975
+ },
6976
+ {
6977
+ base: "#818CF8",
6978
+ hover: "#6366F1",
6979
+ info: "#FBBF24",
6980
+ infoHover: "#F59E0B"
6981
+ },
6982
+ {
6983
+ base: "#4F46E5",
6984
+ hover: "#4338CA",
6985
+ info: "#F59E0B",
6986
+ infoHover: "#D97706"
6987
+ },
6988
+ {
6989
+ base: "#3730A3",
6990
+ hover: "#312E81",
6991
+ info: "#D97706",
6992
+ infoHover: "#B45309"
6993
+ },
6994
+ {
6995
+ base: "#7C3AED",
6996
+ hover: "#6D28D9",
6997
+ info: "#F97316",
6998
+ infoHover: "#EA580C"
6999
+ },
7000
+ {
7001
+ base: "#A78BFA",
7002
+ hover: "#8B5CF6",
7003
+ info: "#FB923C",
7004
+ infoHover: "#F97316"
7005
+ },
7006
+ {
7007
+ base: "#8B5CF6",
7008
+ hover: "#7C3AED",
7009
+ info: "#F97316",
7010
+ infoHover: "#EA580C"
7011
+ },
7012
+ {
7013
+ base: "#6D28D9",
7014
+ hover: "#5B21B6",
7015
+ info: "#EA580C",
7016
+ infoHover: "#C2410C"
7017
+ },
7018
+ {
7019
+ base: "#0EA5E9",
7020
+ hover: "#0284C7",
7021
+ info: "#F97316",
7022
+ infoHover: "#EA580C"
7023
+ },
7024
+ {
7025
+ base: "#38BDF8",
7026
+ hover: "#0EA5E9",
7027
+ info: "#FB923C",
7028
+ infoHover: "#F97316"
7029
+ },
7030
+ {
7031
+ base: "#3B82F6",
7032
+ hover: "#2563EB",
7033
+ info: "#F59E0B",
7034
+ infoHover: "#D97706"
7035
+ },
7036
+ {
7037
+ base: "#1D4ED8",
7038
+ hover: "#1E40AF",
7039
+ info: "#D97706",
7040
+ infoHover: "#B45309"
7041
+ },
7042
+ {
7043
+ base: "#06B6D4",
7044
+ hover: "#0891B2",
7045
+ info: "#A855F7",
7046
+ infoHover: "#9333EA"
7047
+ },
7048
+ {
7049
+ base: "#22D3EE",
7050
+ hover: "#06B6D4",
7051
+ info: "#C084FC",
7052
+ infoHover: "#A855F7"
7053
+ },
7054
+ {
7055
+ base: "#14B8A6",
7056
+ hover: "#0F766E",
7057
+ info: "#8B5CF6",
7058
+ infoHover: "#7C3AED"
7059
+ },
7060
+ {
7061
+ base: "#0D9488",
7062
+ hover: "#0F766E",
7063
+ info: "#7C3AED",
7064
+ infoHover: "#6D28D9"
7065
+ },
7066
+ {
7067
+ base: "#10B981",
7068
+ hover: "#059669",
7069
+ info: "#8B5CF6",
7070
+ infoHover: "#7C3AED"
7071
+ },
7072
+ {
7073
+ base: "#34D399",
7074
+ hover: "#10B981",
7075
+ info: "#A855F7",
7076
+ infoHover: "#9333EA"
7077
+ },
7078
+ {
7079
+ base: "#22C55E",
7080
+ hover: "#16A34A",
7081
+ info: "#7C3AED",
7082
+ infoHover: "#6D28D9"
7083
+ },
7084
+ {
7085
+ base: "#16A34A",
7086
+ hover: "#15803D",
7087
+ info: "#6D28D9",
7088
+ infoHover: "#5B21B6"
7089
+ },
7090
+ {
7091
+ base: "#84CC16",
7092
+ hover: "#65A30D",
7093
+ info: "#6366F1",
7094
+ infoHover: "#4F46E5"
7095
+ },
7096
+ {
7097
+ base: "#A3E635",
7098
+ hover: "#84CC16",
7099
+ info: "#818CF8",
7100
+ infoHover: "#6366F1"
7101
+ },
7102
+ {
7103
+ base: "#65A30D",
7104
+ hover: "#4D7C0F",
7105
+ info: "#4F46E5",
7106
+ infoHover: "#4338CA"
7107
+ },
7108
+ {
7109
+ base: "#4D7C0F",
7110
+ hover: "#3F6212",
7111
+ info: "#3730A3",
7112
+ infoHover: "#312E81"
7113
+ },
7114
+ {
7115
+ base: "#EAB308",
7116
+ hover: "#CA8A04",
7117
+ info: "#3B82F6",
7118
+ infoHover: "#2563EB"
7119
+ },
7120
+ {
7121
+ base: "#FACC15",
7122
+ hover: "#EAB308",
7123
+ info: "#60A5FA",
7124
+ infoHover: "#3B82F6"
7125
+ },
7126
+ {
7127
+ base: "#F59E0B",
7128
+ hover: "#D97706",
7129
+ info: "#2563EB",
7130
+ infoHover: "#1D4ED8"
7131
+ },
7132
+ {
7133
+ base: "#D97706",
7134
+ hover: "#B45309",
7135
+ info: "#1D4ED8",
7136
+ infoHover: "#1E40AF"
7137
+ },
7138
+ {
7139
+ base: "#F97316",
7140
+ hover: "#EA580C",
7141
+ info: "#0EA5E9",
7142
+ infoHover: "#0284C7"
7143
+ },
7144
+ {
7145
+ base: "#FB923C",
7146
+ hover: "#F97316",
7147
+ info: "#38BDF8",
7148
+ infoHover: "#0EA5E9"
7149
+ },
7150
+ {
7151
+ base: "#EA580C",
7152
+ hover: "#C2410C",
7153
+ info: "#0284C7",
7154
+ infoHover: "#0369A1"
7155
+ },
7156
+ {
7157
+ base: "#C2410C",
7158
+ hover: "#9A3412",
7159
+ info: "#0369A1",
7160
+ infoHover: "#075985"
7161
+ },
7162
+ {
7163
+ base: "#EF4444",
7164
+ hover: "#DC2626",
7165
+ info: "#0EA5E9",
7166
+ infoHover: "#0284C7"
7167
+ },
7168
+ {
7169
+ base: "#F87171",
7170
+ hover: "#EF4444",
7171
+ info: "#38BDF8",
7172
+ infoHover: "#0EA5E9"
7173
+ },
7174
+ {
7175
+ base: "#DC2626",
7176
+ hover: "#B91C1C",
7177
+ info: "#0284C7",
7178
+ infoHover: "#0369A1"
7179
+ },
7180
+ {
7181
+ base: "#B91C1C",
7182
+ hover: "#991B1B",
7183
+ info: "#0369A1",
7184
+ infoHover: "#075985"
7185
+ },
7186
+ {
7187
+ base: "#F43F5E",
7188
+ hover: "#E11D48",
7189
+ info: "#0EA5E9",
7190
+ infoHover: "#0284C7"
7191
+ },
7192
+ {
7193
+ base: "#FB7185",
7194
+ hover: "#F43F5E",
7195
+ info: "#38BDF8",
7196
+ infoHover: "#0EA5E9"
7197
+ },
7198
+ {
7199
+ base: "#E11D48",
7200
+ hover: "#BE123C",
7201
+ info: "#0284C7",
7202
+ infoHover: "#0369A1"
7203
+ },
7204
+ {
7205
+ base: "#BE123C",
7206
+ hover: "#9F1239",
7207
+ info: "#0369A1",
7208
+ infoHover: "#075985"
7209
+ },
7210
+ {
7211
+ base: "#EC4899",
7212
+ hover: "#DB2777",
7213
+ info: "#06B6D4",
7214
+ infoHover: "#0891B2"
7215
+ },
7216
+ {
7217
+ base: "#F472B6",
7218
+ hover: "#EC4899",
7219
+ info: "#22D3EE",
7220
+ infoHover: "#06B6D4"
7221
+ },
7222
+ {
7223
+ base: "#DB2777",
7224
+ hover: "#BE185D",
7225
+ info: "#0891B2",
7226
+ infoHover: "#0E7490"
7227
+ },
7228
+ {
7229
+ base: "#BE185D",
7230
+ hover: "#9D174D",
7231
+ info: "#0E7490",
7232
+ infoHover: "#155E75"
7233
+ },
7234
+ {
7235
+ base: "#D946EF",
7236
+ hover: "#C026D3",
7237
+ info: "#F59E0B",
7238
+ infoHover: "#D97706"
7239
+ },
7240
+ {
7241
+ base: "#E879F9",
7242
+ hover: "#D946EF",
7243
+ info: "#FBBF24",
7244
+ infoHover: "#F59E0B"
7245
+ },
7246
+ {
7247
+ base: "#C026D3",
7248
+ hover: "#A21CAF",
7249
+ info: "#D97706",
7250
+ infoHover: "#B45309"
7251
+ },
7252
+ {
7253
+ base: "#A21CAF",
7254
+ hover: "#86198F",
7255
+ info: "#B45309",
7256
+ infoHover: "#92400E"
7257
+ }
7258
+ ]
6717
7259
  };
6718
7260
 
6719
7261
  // src/components/theme-provider.tsx
6720
7262
  var import_jsx_runtime36 = require("react/jsx-runtime");
6721
- var configDefaults = {
6722
- theme: settingConfig_default.theme,
6723
- fontSize: settingConfig_default.fontSize,
6724
- fontFamily: settingConfig_default.fontFamily,
6725
- colors: settingConfig_default.colors
7263
+ var FACTORY_DEFAULTS = {
7264
+ theme: settingConfig_default.defaults.theme,
7265
+ fontSize: settingConfig_default.defaults.fontSize,
7266
+ fontFamily: settingConfig_default.defaults.fontFamily,
7267
+ colors: settingConfig_default.defaults.colors
6726
7268
  };
7269
+ function loadJSON(key, fallback) {
7270
+ try {
7271
+ const raw = localStorage.getItem(key);
7272
+ if (raw) return { ...fallback, ...JSON.parse(raw) };
7273
+ } catch {
7274
+ }
7275
+ return fallback;
7276
+ }
7277
+ function saveJSON(key, value) {
7278
+ try {
7279
+ localStorage.setItem(key, JSON.stringify(value));
7280
+ } catch {
7281
+ }
7282
+ }
6727
7283
  var initialState = {
6728
- ...configDefaults,
7284
+ ...FACTORY_DEFAULTS,
6729
7285
  setTheme: () => null,
6730
7286
  setColors: () => null,
6731
7287
  setFontSize: () => null,
6732
7288
  setFontFamily: () => null,
7289
+ saveConfig: () => null,
6733
7290
  resetSettings: () => null
6734
7291
  };
6735
7292
  var ThemeProviderContext = (0, import_react.createContext)(initialState);
6736
- var COLOR_PALETTE = [
6737
- { base: "#6366f1", hover: "#4f46e5" },
6738
- { base: "#8b5cf6", hover: "#7c3aed" },
6739
- { base: "#3b82f6", hover: "#2563eb" },
6740
- { base: "#10b981", hover: "#059669" },
6741
- { base: "#22c55e", hover: "#16a34a" },
6742
- { base: "#eab308", hover: "#ca8a04" },
6743
- { base: "#f59e0b", hover: "#d97706" },
6744
- { base: "#f97316", hover: "#ea580c" },
6745
- { base: "#ef4444", hover: "#dc2626" },
6746
- { base: "#ec4899", hover: "#db2777" }
6747
- ];
7293
+ var COLOR_PALETTE = settingConfig_default.colorPalette;
6748
7294
  function ThemeProvider({
6749
7295
  children,
6750
7296
  storageKey = "codego-ui-theme-settings",
7297
+ savedConfigKey = "codego-ui-saved-config",
6751
7298
  ...props
6752
7299
  }) {
6753
- const [settings, setSettings] = (0, import_react.useState)(() => {
6754
- try {
6755
- const stored = localStorage.getItem(storageKey);
6756
- if (stored) return { ...configDefaults, ...JSON.parse(stored) };
6757
- } catch {
6758
- }
6759
- return configDefaults;
6760
- });
7300
+ const [savedConfig, setSavedConfig] = (0, import_react.useState)(
7301
+ () => loadJSON(savedConfigKey, FACTORY_DEFAULTS)
7302
+ );
7303
+ const [settings, setSettings] = (0, import_react.useState)(
7304
+ () => loadJSON(storageKey, savedConfig)
7305
+ );
6761
7306
  (0, import_react.useEffect)(() => {
6762
- localStorage.setItem(storageKey, JSON.stringify(settings));
7307
+ saveJSON(storageKey, settings);
6763
7308
  }, [settings, storageKey]);
6764
7309
  (0, import_react.useEffect)(() => {
6765
7310
  const root = window.document.documentElement;
@@ -6785,7 +7330,13 @@ function ThemeProvider({
6785
7330
  setColors: (colors) => setSettings((s) => ({ ...s, colors: { ...s.colors, ...colors } })),
6786
7331
  setFontSize: (fontSize) => setSettings((s) => ({ ...s, fontSize })),
6787
7332
  setFontFamily: (fontFamily) => setSettings((s) => ({ ...s, fontFamily })),
6788
- resetSettings: () => setSettings(configDefaults)
7333
+ // Save current live settings as the new persisted defaults
7334
+ saveConfig: () => {
7335
+ setSavedConfig(settings);
7336
+ saveJSON(savedConfigKey, settings);
7337
+ },
7338
+ // Reset live settings back to saved defaults
7339
+ resetSettings: () => setSettings(savedConfig)
6789
7340
  };
6790
7341
  return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ThemeProviderContext.Provider, { ...props, value, children });
6791
7342
  }
@@ -7676,6 +8227,7 @@ function SectionBlock({
7676
8227
  }
7677
8228
 
7678
8229
  // src/components/ui/PanelSettings.tsx
8230
+ var React39 = __toESM(require("react"), 1);
7679
8231
  var import_lucide_react25 = require("lucide-react");
7680
8232
 
7681
8233
  // src/components/ui/tabs.tsx
@@ -7762,30 +8314,10 @@ function Tabs({
7762
8314
 
7763
8315
  // src/components/ui/PanelSettings.tsx
7764
8316
  var import_jsx_runtime48 = require("react/jsx-runtime");
7765
- var FONT_SIZES = [
7766
- { value: "14px", label: "Small (14px)" },
7767
- { value: "16px", label: "Medium (16px)" },
7768
- { value: "18px", label: "Large (18px)" },
7769
- { value: "20px", label: "Extra Large (20px)" }
7770
- ];
7771
- var FONT_FAMILIES = [
7772
- { value: '"Space Grotesk", "Inter", sans-serif', label: "Space Grotesk" },
7773
- { value: '"Inter", sans-serif', label: "Inter" },
7774
- { value: '"JetBrains Mono", monospace', label: "JetBrains Mono" },
7775
- { value: "system-ui, sans-serif", label: "System UI" }
7776
- ];
7777
- var THEME_OPTIONS = [
7778
- { value: "light", label: "Light" },
7779
- { value: "dark", label: "Dark" },
7780
- { value: "system", label: "System" }
7781
- ];
7782
- var COLOR_PAIRS = [
7783
- { base: "primary", hover: "primaryHover", label: "Primary" },
7784
- { base: "secondary", hover: "secondaryHover", label: "Secondary" },
7785
- { base: "info", hover: "infoHover", label: "Info" },
7786
- { base: "warning", hover: "warningHover", label: "Warning" },
7787
- { base: "danger", hover: "dangerHover", label: "Danger" }
7788
- ];
8317
+ var THEME_OPTIONS = settingConfig_default.themeOptions;
8318
+ var FONT_SIZES = settingConfig_default.fontSizes;
8319
+ var FONT_FAMILIES = settingConfig_default.fontFamilies;
8320
+ var COLOR_PAIRS = settingConfig_default.colorPairs;
7789
8321
  function SettingRow({ label, description, children }) {
7790
8322
  return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex items-start justify-between gap-4 py-3 border-b border-border/60 last:border-0", children: [
7791
8323
  /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "min-w-0", children: [
@@ -7833,8 +8365,8 @@ function ColorsPanel({ onColorsChange }) {
7833
8365
  type: "button",
7834
8366
  title: c.base,
7835
8367
  onClick: () => {
7836
- setColors({ primary: c.base, primaryHover: c.hover });
7837
- onColorsChange?.({ primary: c.base, primaryHover: c.hover });
8368
+ setColors({ primary: c.base, primaryHover: c.hover, info: c.info, infoHover: c.infoHover });
8369
+ onColorsChange?.({ primary: c.base, primaryHover: c.hover, info: c.info, infoHover: c.infoHover });
7838
8370
  },
7839
8371
  className: cn(
7840
8372
  "h-7 w-full rounded-md border border-white/10 transition-transform hover:scale-110 focus:outline-none focus:ring-2 focus:ring-ring",
@@ -7910,10 +8442,18 @@ function PanelSettings({
7910
8442
  onColorsChange,
7911
8443
  onFontSizeChange,
7912
8444
  onFontFamilyChange,
8445
+ onSave,
7913
8446
  onReset,
7914
8447
  className
7915
8448
  }) {
7916
- const { resetSettings } = useTheme();
8449
+ const { saveConfig, resetSettings } = useTheme();
8450
+ const [saved, setSaved] = React39.useState(false);
8451
+ const handleSave = () => {
8452
+ saveConfig();
8453
+ onSave?.();
8454
+ setSaved(true);
8455
+ setTimeout(() => setSaved(false), 2e3);
8456
+ };
7917
8457
  const handleReset = () => {
7918
8458
  resetSettings();
7919
8459
  onReset?.();
@@ -7937,10 +8477,16 @@ function PanelSettings({
7937
8477
  ];
7938
8478
  return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: cn("flex flex-col gap-4", className), children: [
7939
8479
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(Tabs, { items: tabs, defaultValue: defaultTab, variant: "pill" }),
7940
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)("div", { className: "flex justify-end pt-1", children: /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(Button, { variant: "outline", size: "sm", onClick: handleReset, children: [
7941
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_lucide_react25.RotateCcw, { className: "h-3.5 w-3.5 mr-1.5" }),
7942
- "Reset to Defaults"
7943
- ] }) })
8480
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "flex justify-end gap-2 pt-1", children: [
8481
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(Button, { variant: "outline", size: "sm", onClick: handleReset, children: [
8482
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_lucide_react25.RotateCcw, { className: "h-3.5 w-3.5 mr-1.5" }),
8483
+ "Reset"
8484
+ ] }),
8485
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)(Button, { size: "sm", onClick: handleSave, children: [
8486
+ /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_lucide_react25.Save, { className: "h-3.5 w-3.5 mr-1.5" }),
8487
+ saved ? "Saved!" : "Save"
8488
+ ] })
8489
+ ] })
7944
8490
  ] });
7945
8491
  }
7946
8492
 
@@ -7960,7 +8506,7 @@ function Skeleton({
7960
8506
  }
7961
8507
 
7962
8508
  // src/components/ui/slider.tsx
7963
- var React39 = __toESM(require("react"), 1);
8509
+ var React40 = __toESM(require("react"), 1);
7964
8510
  var import_jsx_runtime50 = require("react/jsx-runtime");
7965
8511
  function pct(val, min, max) {
7966
8512
  return (val - min) / (max - min) * 100;
@@ -7980,8 +8526,8 @@ function Slider({
7980
8526
  showValue = false,
7981
8527
  className
7982
8528
  }) {
7983
- const [internal, setInternal] = React39.useState(defaultValue);
7984
- const [hovering, setHovering] = React39.useState(false);
8529
+ const [internal, setInternal] = React40.useState(defaultValue);
8530
+ const [hovering, setHovering] = React40.useState(false);
7985
8531
  const val = controlled ?? internal;
7986
8532
  function handleChange(e) {
7987
8533
  const v = Number(e.target.value);
@@ -8058,8 +8604,8 @@ function RangeSlider({
8058
8604
  showValue = false,
8059
8605
  className
8060
8606
  }) {
8061
- const [internal, setInternal] = React39.useState(defaultValue);
8062
- const [active, setActive] = React39.useState(null);
8607
+ const [internal, setInternal] = React40.useState(defaultValue);
8608
+ const [active, setActive] = React40.useState(null);
8063
8609
  const val = controlled ?? internal;
8064
8610
  function handleChange(idx, e) {
8065
8611
  const v = Number(e.target.value);
@@ -8082,7 +8628,7 @@ function RangeSlider({
8082
8628
  /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "absolute w-full h-1.5 rounded-full bg-muted", children: /* @__PURE__ */ (0, import_jsx_runtime50.jsx)("div", { className: "absolute h-full rounded-full bg-primary", style: { left: `${p0}%`, width: `${p1 - p0}%` } }) }),
8083
8629
  [0, 1].map((idx) => {
8084
8630
  const p = idx === 0 ? p0 : p1;
8085
- return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(React39.Fragment, { children: [
8631
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(React40.Fragment, { children: [
8086
8632
  showTooltip && active === idx && !disabled && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
8087
8633
  "div",
8088
8634
  {
@@ -8193,7 +8739,7 @@ function StatCard({
8193
8739
  }
8194
8740
 
8195
8741
  // src/components/ui/stepper.tsx
8196
- var React40 = __toESM(require("react"), 1);
8742
+ var React41 = __toESM(require("react"), 1);
8197
8743
  var import_lucide_react27 = require("lucide-react");
8198
8744
  var import_jsx_runtime52 = require("react/jsx-runtime");
8199
8745
  function getStatus(idx, current) {
@@ -8216,7 +8762,7 @@ function Stepper({
8216
8762
  clickable = false,
8217
8763
  className
8218
8764
  }) {
8219
- const [internal, setInternal] = React40.useState(defaultCurrent);
8765
+ const [internal, setInternal] = React41.useState(defaultCurrent);
8220
8766
  const current = controlled ?? internal;
8221
8767
  function go(idx) {
8222
8768
  if (!clickable) return;
@@ -8231,7 +8777,7 @@ function Stepper({
8231
8777
  ), children: steps.map((step, i) => {
8232
8778
  const status = getStatus(i, current);
8233
8779
  const isLast = i === steps.length - 1;
8234
- return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(React40.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: cn(
8780
+ return /* @__PURE__ */ (0, import_jsx_runtime52.jsx)(React41.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime52.jsxs)("div", { className: cn(
8235
8781
  "flex",
8236
8782
  isHorizontal ? "flex-col items-center flex-1" : "flex-row gap-4"
8237
8783
  ), children: [
@@ -8275,7 +8821,7 @@ function Stepper({
8275
8821
  }
8276
8822
 
8277
8823
  // src/components/ui/table.tsx
8278
- var React41 = __toESM(require("react"), 1);
8824
+ var React42 = __toESM(require("react"), 1);
8279
8825
  var import_lucide_react28 = require("lucide-react");
8280
8826
  var import_jsx_runtime53 = require("react/jsx-runtime");
8281
8827
  var BADGE_COLORS = {
@@ -8300,11 +8846,11 @@ function Table({
8300
8846
  idKey = "id",
8301
8847
  className
8302
8848
  }) {
8303
- const [search, setSearch] = React41.useState("");
8304
- const [currentPage, setCurrentPage] = React41.useState(1);
8305
- const [selectedIds, setSelectedIds] = React41.useState([]);
8306
- const [sortKey, setSortKey] = React41.useState(null);
8307
- const [sortDir, setSortDir] = React41.useState(null);
8849
+ const [search, setSearch] = React42.useState("");
8850
+ const [currentPage, setCurrentPage] = React42.useState(1);
8851
+ const [selectedIds, setSelectedIds] = React42.useState([]);
8852
+ const [sortKey, setSortKey] = React42.useState(null);
8853
+ const [sortDir, setSortDir] = React42.useState(null);
8308
8854
  const handleSort = (key) => {
8309
8855
  if (sortKey !== key) {
8310
8856
  setSortKey(key);
@@ -8318,7 +8864,7 @@ function Table({
8318
8864
  setSortKey(null);
8319
8865
  setSortDir(null);
8320
8866
  };
8321
- const filteredData = React41.useMemo(() => {
8867
+ const filteredData = React42.useMemo(() => {
8322
8868
  let d = search ? data.filter(
8323
8869
  (item) => Object.values(item).some(
8324
8870
  (val) => val && typeof val === "string" && val.toLowerCase().includes(search.toLowerCase())
@@ -8336,18 +8882,18 @@ function Table({
8336
8882
  }, [data, search, sortKey, sortDir]);
8337
8883
  const totalPages = Math.max(1, Math.ceil(filteredData.length / itemsPerPage));
8338
8884
  const safePage = Math.min(currentPage, totalPages);
8339
- const paginatedData = React41.useMemo(() => {
8885
+ const paginatedData = React42.useMemo(() => {
8340
8886
  if (!pagination) return filteredData;
8341
8887
  const start = (safePage - 1) * itemsPerPage;
8342
8888
  return filteredData.slice(start, start + itemsPerPage);
8343
8889
  }, [filteredData, pagination, safePage, itemsPerPage]);
8344
- React41.useEffect(() => {
8890
+ React42.useEffect(() => {
8345
8891
  setCurrentPage(1);
8346
8892
  }, [search]);
8347
8893
  const handleSelectAll = (checked) => setSelectedIds(checked ? paginatedData.map((item) => String(item[idKey])) : []);
8348
8894
  const handleSelect = (id, checked) => setSelectedIds((prev) => checked ? [...prev, id] : prev.filter((i) => i !== id));
8349
8895
  const allSelected = paginatedData.length > 0 && selectedIds.length === paginatedData.length;
8350
- const pagePills = React41.useMemo(() => {
8896
+ const pagePills = React42.useMemo(() => {
8351
8897
  if (totalPages <= 5) return Array.from({ length: totalPages }, (_, i) => i + 1);
8352
8898
  if (safePage <= 3) return [1, 2, 3, 4, 5];
8353
8899
  if (safePage >= totalPages - 2) return [totalPages - 4, totalPages - 3, totalPages - 2, totalPages - 1, totalPages];
@@ -8576,7 +9122,7 @@ function Table({
8576
9122
  }
8577
9123
 
8578
9124
  // src/components/ui/tag-input.tsx
8579
- var React42 = __toESM(require("react"), 1);
9125
+ var React43 = __toESM(require("react"), 1);
8580
9126
  var import_jsx_runtime54 = require("react/jsx-runtime");
8581
9127
  function TagInput({
8582
9128
  value: controlled,
@@ -8588,9 +9134,9 @@ function TagInput({
8588
9134
  disabled = false,
8589
9135
  className
8590
9136
  }) {
8591
- const [internal, setInternal] = React42.useState(defaultValue);
8592
- const [input, setInput] = React42.useState("");
8593
- const inputRef = React42.useRef(null);
9137
+ const [internal, setInternal] = React43.useState(defaultValue);
9138
+ const [input, setInput] = React43.useState("");
9139
+ const inputRef = React43.useRef(null);
8594
9140
  const tags = controlled ?? internal;
8595
9141
  function addTag(raw) {
8596
9142
  const tag = raw.trim();
@@ -8695,9 +9241,9 @@ function Timeline({ items, align = "left", className }) {
8695
9241
  }
8696
9242
 
8697
9243
  // src/components/ui/toggle-switch.tsx
8698
- var React43 = __toESM(require("react"), 1);
9244
+ var React44 = __toESM(require("react"), 1);
8699
9245
  var import_jsx_runtime56 = require("react/jsx-runtime");
8700
- var ToggleSwitch = React43.forwardRef(
9246
+ var ToggleSwitch = React44.forwardRef(
8701
9247
  ({
8702
9248
  className,
8703
9249
  inline = false,
@@ -8715,10 +9261,10 @@ var ToggleSwitch = React43.forwardRef(
8715
9261
  disabled,
8716
9262
  ...props
8717
9263
  }, ref) => {
8718
- const toggleId = id ?? React43.useId();
9264
+ const toggleId = id ?? React44.useId();
8719
9265
  const trackW = width ? typeof width === "number" ? `${width}px` : width : "2.75rem";
8720
9266
  const trackH = height ? typeof height === "number" ? `${height}px` : height : "1.5rem";
8721
- const [internalChecked, setInternalChecked] = React43.useState(defaultChecked ?? false);
9267
+ const [internalChecked, setInternalChecked] = React44.useState(defaultChecked ?? false);
8722
9268
  const isControlled = checked !== void 0;
8723
9269
  const isOn = accepted ? true : declined ? false : isControlled ? checked : internalChecked;
8724
9270
  const stateColor = accepted ? acceptedColor ?? "#22c55e" : declined ? declinedColor ?? "#ef4444" : isOn ? void 0 : void 0;
@@ -8788,7 +9334,7 @@ var ToggleSwitch = React43.forwardRef(
8788
9334
  ToggleSwitch.displayName = "ToggleSwitch";
8789
9335
 
8790
9336
  // src/components/ui/tree-view.tsx
8791
- var React44 = __toESM(require("react"), 1);
9337
+ var React45 = __toESM(require("react"), 1);
8792
9338
  var import_lucide_react30 = require("lucide-react");
8793
9339
  var import_jsx_runtime57 = require("react/jsx-runtime");
8794
9340
  function TreeNodeItem({ node, depth, selected, expanded, onToggleExpand, onSelect, multiple }) {
@@ -8842,8 +9388,8 @@ function TreeView({
8842
9388
  className
8843
9389
  }) {
8844
9390
  const init = defaultSelected ? Array.isArray(defaultSelected) ? defaultSelected : [defaultSelected] : [];
8845
- const [internal, setInternal] = React44.useState(init);
8846
- const [expanded, setExpanded] = React44.useState(defaultExpanded);
9391
+ const [internal, setInternal] = React45.useState(init);
9392
+ const [expanded, setExpanded] = React45.useState(defaultExpanded);
8847
9393
  const selected = controlled ? Array.isArray(controlled) ? controlled : [controlled] : internal;
8848
9394
  function handleSelect(id) {
8849
9395
  let next;
@@ -8874,7 +9420,7 @@ function TreeView({
8874
9420
  }
8875
9421
 
8876
9422
  // src/components/ui/widget.tsx
8877
- var React45 = __toESM(require("react"), 1);
9423
+ var React46 = __toESM(require("react"), 1);
8878
9424
  var import_jsx_runtime58 = require("react/jsx-runtime");
8879
9425
  var iconColorMap = {
8880
9426
  primary: "bg-primary/10 text-primary",
@@ -8903,8 +9449,8 @@ var variantMap = {
8903
9449
  outline: "bg-transparent border-2"
8904
9450
  };
8905
9451
  function useCountUp(target, enabled, duration = 1e3) {
8906
- const [display, setDisplay] = React45.useState(enabled ? 0 : target);
8907
- React45.useEffect(() => {
9452
+ const [display, setDisplay] = React46.useState(enabled ? 0 : target);
9453
+ React46.useEffect(() => {
8908
9454
  if (!enabled) {
8909
9455
  setDisplay(target);
8910
9456
  return;
@@ -9017,7 +9563,7 @@ function Widget({
9017
9563
  }
9018
9564
 
9019
9565
  // src/components/ui/wizard.tsx
9020
- var React46 = __toESM(require("react"), 1);
9566
+ var React47 = __toESM(require("react"), 1);
9021
9567
  var import_lucide_react31 = require("lucide-react");
9022
9568
  var import_jsx_runtime59 = require("react/jsx-runtime");
9023
9569
  var SIZE_MAP = {
@@ -9041,7 +9587,7 @@ function HeaderDefault({
9041
9587
  return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: "flex items-start w-full", children: steps.map((step, i) => {
9042
9588
  const status = stepStatus(i, current);
9043
9589
  const isLast = i === steps.length - 1;
9044
- return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(React46.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "flex flex-col items-center flex-1 min-w-0", children: [
9590
+ return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(React47.Fragment, { children: /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "flex flex-col items-center flex-1 min-w-0", children: [
9045
9591
  /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "flex items-center w-full", children: [
9046
9592
  i > 0 && /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: cn("flex-1 h-0.5 transition-colors", i <= current ? "bg-primary" : "bg-border") }),
9047
9593
  /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
@@ -9269,7 +9815,7 @@ function WizardPanel({
9269
9815
  const isFirst = current === 0;
9270
9816
  const isLast = current === steps.length - 1;
9271
9817
  const isSidebar = variant === "sidebar";
9272
- const [validationError, setValidationError] = React46.useState(null);
9818
+ const [validationError, setValidationError] = React47.useState(null);
9273
9819
  const handleNext = () => {
9274
9820
  const validate = steps[current]?.validate;
9275
9821
  if (validate) {
@@ -9373,7 +9919,7 @@ function Wizard({
9373
9919
  className,
9374
9920
  contentClassName
9375
9921
  }) {
9376
- const [internalStep, setInternalStep] = React46.useState(defaultStep);
9922
+ const [internalStep, setInternalStep] = React47.useState(defaultStep);
9377
9923
  const current = controlledStep ?? internalStep;
9378
9924
  const go = (idx) => {
9379
9925
  const clamped = Math.max(0, Math.min(steps.length - 1, idx));
@@ -9388,7 +9934,7 @@ function Wizard({
9388
9934
  }
9389
9935
  go(current + 1);
9390
9936
  };
9391
- React46.useEffect(() => {
9937
+ React47.useEffect(() => {
9392
9938
  if (layout !== "modal" || !isOpen || unchange) return;
9393
9939
  const handler = (e) => {
9394
9940
  if (e.key === "Escape") onClose?.();