@juv/codego-react-ui 2.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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: [
@@ -6701,67 +6925,386 @@ var import_react = require("react");
6701
6925
 
6702
6926
  // src/components/conf/settingConfig.json
6703
6927
  var settingConfig_default = {
6704
- theme: "dark",
6705
- fontSize: "16px",
6706
- fontFamily: '"Space Grotesk", "Inter", sans-serif',
6707
- colors: {
6708
- primary: "#8b5cf6",
6709
- primaryHover: "#7c3aed",
6710
- secondary: "#171717",
6711
- secondaryHover: "#262626",
6712
- info: "#3b82f6",
6713
- infoHover: "#2563eb",
6714
- warning: "#f59e0b",
6715
- warningHover: "#d97706",
6716
- danger: "#ef4444",
6717
- dangerHover: "#dc2626"
6718
- }
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
+ ]
6719
7259
  };
6720
7260
 
6721
7261
  // src/components/theme-provider.tsx
6722
7262
  var import_jsx_runtime36 = require("react/jsx-runtime");
6723
- var configDefaults = {
6724
- theme: settingConfig_default.theme,
6725
- fontSize: settingConfig_default.fontSize,
6726
- fontFamily: settingConfig_default.fontFamily,
6727
- 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
6728
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
+ }
6729
7283
  var initialState = {
6730
- ...configDefaults,
7284
+ ...FACTORY_DEFAULTS,
6731
7285
  setTheme: () => null,
6732
7286
  setColors: () => null,
6733
7287
  setFontSize: () => null,
6734
7288
  setFontFamily: () => null,
7289
+ saveConfig: () => null,
6735
7290
  resetSettings: () => null
6736
7291
  };
6737
7292
  var ThemeProviderContext = (0, import_react.createContext)(initialState);
6738
- var COLOR_PALETTE = [
6739
- { base: "#6366f1", hover: "#4f46e5" },
6740
- { base: "#8b5cf6", hover: "#7c3aed" },
6741
- { base: "#3b82f6", hover: "#2563eb" },
6742
- { base: "#10b981", hover: "#059669" },
6743
- { base: "#22c55e", hover: "#16a34a" },
6744
- { base: "#eab308", hover: "#ca8a04" },
6745
- { base: "#f59e0b", hover: "#d97706" },
6746
- { base: "#f97316", hover: "#ea580c" },
6747
- { base: "#ef4444", hover: "#dc2626" },
6748
- { base: "#ec4899", hover: "#db2777" }
6749
- ];
7293
+ var COLOR_PALETTE = settingConfig_default.colorPalette;
6750
7294
  function ThemeProvider({
6751
7295
  children,
6752
7296
  storageKey = "codego-ui-theme-settings",
7297
+ savedConfigKey = "codego-ui-saved-config",
6753
7298
  ...props
6754
7299
  }) {
6755
- const [settings, setSettings] = (0, import_react.useState)(() => {
6756
- try {
6757
- const stored = localStorage.getItem(storageKey);
6758
- if (stored) return { ...configDefaults, ...JSON.parse(stored) };
6759
- } catch {
6760
- }
6761
- return configDefaults;
6762
- });
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
+ );
6763
7306
  (0, import_react.useEffect)(() => {
6764
- localStorage.setItem(storageKey, JSON.stringify(settings));
7307
+ saveJSON(storageKey, settings);
6765
7308
  }, [settings, storageKey]);
6766
7309
  (0, import_react.useEffect)(() => {
6767
7310
  const root = window.document.documentElement;
@@ -6787,7 +7330,13 @@ function ThemeProvider({
6787
7330
  setColors: (colors) => setSettings((s) => ({ ...s, colors: { ...s.colors, ...colors } })),
6788
7331
  setFontSize: (fontSize) => setSettings((s) => ({ ...s, fontSize })),
6789
7332
  setFontFamily: (fontFamily) => setSettings((s) => ({ ...s, fontFamily })),
6790
- 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)
6791
7340
  };
6792
7341
  return /* @__PURE__ */ (0, import_jsx_runtime36.jsx)(ThemeProviderContext.Provider, { ...props, value, children });
6793
7342
  }
@@ -7678,6 +8227,7 @@ function SectionBlock({
7678
8227
  }
7679
8228
 
7680
8229
  // src/components/ui/PanelSettings.tsx
8230
+ var React39 = __toESM(require("react"), 1);
7681
8231
  var import_lucide_react25 = require("lucide-react");
7682
8232
 
7683
8233
  // src/components/ui/tabs.tsx
@@ -7764,30 +8314,10 @@ function Tabs({
7764
8314
 
7765
8315
  // src/components/ui/PanelSettings.tsx
7766
8316
  var import_jsx_runtime48 = require("react/jsx-runtime");
7767
- var FONT_SIZES = [
7768
- { value: "14px", label: "Small (14px)" },
7769
- { value: "16px", label: "Medium (16px)" },
7770
- { value: "18px", label: "Large (18px)" },
7771
- { value: "20px", label: "Extra Large (20px)" }
7772
- ];
7773
- var FONT_FAMILIES = [
7774
- { value: '"Space Grotesk", "Inter", sans-serif', label: "Space Grotesk" },
7775
- { value: '"Inter", sans-serif', label: "Inter" },
7776
- { value: '"JetBrains Mono", monospace', label: "JetBrains Mono" },
7777
- { value: "system-ui, sans-serif", label: "System UI" }
7778
- ];
7779
- var THEME_OPTIONS = [
7780
- { value: "light", label: "Light" },
7781
- { value: "dark", label: "Dark" },
7782
- { value: "system", label: "System" }
7783
- ];
7784
- var COLOR_PAIRS = [
7785
- { base: "primary", hover: "primaryHover", label: "Primary" },
7786
- { base: "secondary", hover: "secondaryHover", label: "Secondary" },
7787
- { base: "info", hover: "infoHover", label: "Info" },
7788
- { base: "warning", hover: "warningHover", label: "Warning" },
7789
- { base: "danger", hover: "dangerHover", label: "Danger" }
7790
- ];
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;
7791
8321
  function SettingRow({ label, description, children }) {
7792
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: [
7793
8323
  /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: "min-w-0", children: [
@@ -7835,8 +8365,8 @@ function ColorsPanel({ onColorsChange }) {
7835
8365
  type: "button",
7836
8366
  title: c.base,
7837
8367
  onClick: () => {
7838
- setColors({ primary: c.base, primaryHover: c.hover });
7839
- 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 });
7840
8370
  },
7841
8371
  className: cn(
7842
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",
@@ -7912,10 +8442,18 @@ function PanelSettings({
7912
8442
  onColorsChange,
7913
8443
  onFontSizeChange,
7914
8444
  onFontFamilyChange,
8445
+ onSave,
7915
8446
  onReset,
7916
8447
  className
7917
8448
  }) {
7918
- 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
+ };
7919
8457
  const handleReset = () => {
7920
8458
  resetSettings();
7921
8459
  onReset?.();
@@ -7939,10 +8477,16 @@ function PanelSettings({
7939
8477
  ];
7940
8478
  return /* @__PURE__ */ (0, import_jsx_runtime48.jsxs)("div", { className: cn("flex flex-col gap-4", className), children: [
7941
8479
  /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(Tabs, { items: tabs, defaultValue: defaultTab, variant: "pill" }),
7942
- /* @__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: [
7943
- /* @__PURE__ */ (0, import_jsx_runtime48.jsx)(import_lucide_react25.RotateCcw, { className: "h-3.5 w-3.5 mr-1.5" }),
7944
- "Reset to Defaults"
7945
- ] }) })
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
+ ] })
7946
8490
  ] });
7947
8491
  }
7948
8492
 
@@ -7962,7 +8506,7 @@ function Skeleton({
7962
8506
  }
7963
8507
 
7964
8508
  // src/components/ui/slider.tsx
7965
- var React39 = __toESM(require("react"), 1);
8509
+ var React40 = __toESM(require("react"), 1);
7966
8510
  var import_jsx_runtime50 = require("react/jsx-runtime");
7967
8511
  function pct(val, min, max) {
7968
8512
  return (val - min) / (max - min) * 100;
@@ -7982,8 +8526,8 @@ function Slider({
7982
8526
  showValue = false,
7983
8527
  className
7984
8528
  }) {
7985
- const [internal, setInternal] = React39.useState(defaultValue);
7986
- const [hovering, setHovering] = React39.useState(false);
8529
+ const [internal, setInternal] = React40.useState(defaultValue);
8530
+ const [hovering, setHovering] = React40.useState(false);
7987
8531
  const val = controlled ?? internal;
7988
8532
  function handleChange(e) {
7989
8533
  const v = Number(e.target.value);
@@ -8060,8 +8604,8 @@ function RangeSlider({
8060
8604
  showValue = false,
8061
8605
  className
8062
8606
  }) {
8063
- const [internal, setInternal] = React39.useState(defaultValue);
8064
- const [active, setActive] = React39.useState(null);
8607
+ const [internal, setInternal] = React40.useState(defaultValue);
8608
+ const [active, setActive] = React40.useState(null);
8065
8609
  const val = controlled ?? internal;
8066
8610
  function handleChange(idx, e) {
8067
8611
  const v = Number(e.target.value);
@@ -8084,7 +8628,7 @@ function RangeSlider({
8084
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}%` } }) }),
8085
8629
  [0, 1].map((idx) => {
8086
8630
  const p = idx === 0 ? p0 : p1;
8087
- return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(React39.Fragment, { children: [
8631
+ return /* @__PURE__ */ (0, import_jsx_runtime50.jsxs)(React40.Fragment, { children: [
8088
8632
  showTooltip && active === idx && !disabled && /* @__PURE__ */ (0, import_jsx_runtime50.jsx)(
8089
8633
  "div",
8090
8634
  {
@@ -8195,7 +8739,7 @@ function StatCard({
8195
8739
  }
8196
8740
 
8197
8741
  // src/components/ui/stepper.tsx
8198
- var React40 = __toESM(require("react"), 1);
8742
+ var React41 = __toESM(require("react"), 1);
8199
8743
  var import_lucide_react27 = require("lucide-react");
8200
8744
  var import_jsx_runtime52 = require("react/jsx-runtime");
8201
8745
  function getStatus(idx, current) {
@@ -8218,7 +8762,7 @@ function Stepper({
8218
8762
  clickable = false,
8219
8763
  className
8220
8764
  }) {
8221
- const [internal, setInternal] = React40.useState(defaultCurrent);
8765
+ const [internal, setInternal] = React41.useState(defaultCurrent);
8222
8766
  const current = controlled ?? internal;
8223
8767
  function go(idx) {
8224
8768
  if (!clickable) return;
@@ -8233,7 +8777,7 @@ function Stepper({
8233
8777
  ), children: steps.map((step, i) => {
8234
8778
  const status = getStatus(i, current);
8235
8779
  const isLast = i === steps.length - 1;
8236
- 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(
8237
8781
  "flex",
8238
8782
  isHorizontal ? "flex-col items-center flex-1" : "flex-row gap-4"
8239
8783
  ), children: [
@@ -8277,7 +8821,7 @@ function Stepper({
8277
8821
  }
8278
8822
 
8279
8823
  // src/components/ui/table.tsx
8280
- var React41 = __toESM(require("react"), 1);
8824
+ var React42 = __toESM(require("react"), 1);
8281
8825
  var import_lucide_react28 = require("lucide-react");
8282
8826
  var import_jsx_runtime53 = require("react/jsx-runtime");
8283
8827
  var BADGE_COLORS = {
@@ -8302,11 +8846,11 @@ function Table({
8302
8846
  idKey = "id",
8303
8847
  className
8304
8848
  }) {
8305
- const [search, setSearch] = React41.useState("");
8306
- const [currentPage, setCurrentPage] = React41.useState(1);
8307
- const [selectedIds, setSelectedIds] = React41.useState([]);
8308
- const [sortKey, setSortKey] = React41.useState(null);
8309
- 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);
8310
8854
  const handleSort = (key) => {
8311
8855
  if (sortKey !== key) {
8312
8856
  setSortKey(key);
@@ -8320,7 +8864,7 @@ function Table({
8320
8864
  setSortKey(null);
8321
8865
  setSortDir(null);
8322
8866
  };
8323
- const filteredData = React41.useMemo(() => {
8867
+ const filteredData = React42.useMemo(() => {
8324
8868
  let d = search ? data.filter(
8325
8869
  (item) => Object.values(item).some(
8326
8870
  (val) => val && typeof val === "string" && val.toLowerCase().includes(search.toLowerCase())
@@ -8338,18 +8882,18 @@ function Table({
8338
8882
  }, [data, search, sortKey, sortDir]);
8339
8883
  const totalPages = Math.max(1, Math.ceil(filteredData.length / itemsPerPage));
8340
8884
  const safePage = Math.min(currentPage, totalPages);
8341
- const paginatedData = React41.useMemo(() => {
8885
+ const paginatedData = React42.useMemo(() => {
8342
8886
  if (!pagination) return filteredData;
8343
8887
  const start = (safePage - 1) * itemsPerPage;
8344
8888
  return filteredData.slice(start, start + itemsPerPage);
8345
8889
  }, [filteredData, pagination, safePage, itemsPerPage]);
8346
- React41.useEffect(() => {
8890
+ React42.useEffect(() => {
8347
8891
  setCurrentPage(1);
8348
8892
  }, [search]);
8349
8893
  const handleSelectAll = (checked) => setSelectedIds(checked ? paginatedData.map((item) => String(item[idKey])) : []);
8350
8894
  const handleSelect = (id, checked) => setSelectedIds((prev) => checked ? [...prev, id] : prev.filter((i) => i !== id));
8351
8895
  const allSelected = paginatedData.length > 0 && selectedIds.length === paginatedData.length;
8352
- const pagePills = React41.useMemo(() => {
8896
+ const pagePills = React42.useMemo(() => {
8353
8897
  if (totalPages <= 5) return Array.from({ length: totalPages }, (_, i) => i + 1);
8354
8898
  if (safePage <= 3) return [1, 2, 3, 4, 5];
8355
8899
  if (safePage >= totalPages - 2) return [totalPages - 4, totalPages - 3, totalPages - 2, totalPages - 1, totalPages];
@@ -8578,7 +9122,7 @@ function Table({
8578
9122
  }
8579
9123
 
8580
9124
  // src/components/ui/tag-input.tsx
8581
- var React42 = __toESM(require("react"), 1);
9125
+ var React43 = __toESM(require("react"), 1);
8582
9126
  var import_jsx_runtime54 = require("react/jsx-runtime");
8583
9127
  function TagInput({
8584
9128
  value: controlled,
@@ -8590,9 +9134,9 @@ function TagInput({
8590
9134
  disabled = false,
8591
9135
  className
8592
9136
  }) {
8593
- const [internal, setInternal] = React42.useState(defaultValue);
8594
- const [input, setInput] = React42.useState("");
8595
- const inputRef = React42.useRef(null);
9137
+ const [internal, setInternal] = React43.useState(defaultValue);
9138
+ const [input, setInput] = React43.useState("");
9139
+ const inputRef = React43.useRef(null);
8596
9140
  const tags = controlled ?? internal;
8597
9141
  function addTag(raw) {
8598
9142
  const tag = raw.trim();
@@ -8697,9 +9241,9 @@ function Timeline({ items, align = "left", className }) {
8697
9241
  }
8698
9242
 
8699
9243
  // src/components/ui/toggle-switch.tsx
8700
- var React43 = __toESM(require("react"), 1);
9244
+ var React44 = __toESM(require("react"), 1);
8701
9245
  var import_jsx_runtime56 = require("react/jsx-runtime");
8702
- var ToggleSwitch = React43.forwardRef(
9246
+ var ToggleSwitch = React44.forwardRef(
8703
9247
  ({
8704
9248
  className,
8705
9249
  inline = false,
@@ -8717,10 +9261,10 @@ var ToggleSwitch = React43.forwardRef(
8717
9261
  disabled,
8718
9262
  ...props
8719
9263
  }, ref) => {
8720
- const toggleId = id ?? React43.useId();
9264
+ const toggleId = id ?? React44.useId();
8721
9265
  const trackW = width ? typeof width === "number" ? `${width}px` : width : "2.75rem";
8722
9266
  const trackH = height ? typeof height === "number" ? `${height}px` : height : "1.5rem";
8723
- const [internalChecked, setInternalChecked] = React43.useState(defaultChecked ?? false);
9267
+ const [internalChecked, setInternalChecked] = React44.useState(defaultChecked ?? false);
8724
9268
  const isControlled = checked !== void 0;
8725
9269
  const isOn = accepted ? true : declined ? false : isControlled ? checked : internalChecked;
8726
9270
  const stateColor = accepted ? acceptedColor ?? "#22c55e" : declined ? declinedColor ?? "#ef4444" : isOn ? void 0 : void 0;
@@ -8790,7 +9334,7 @@ var ToggleSwitch = React43.forwardRef(
8790
9334
  ToggleSwitch.displayName = "ToggleSwitch";
8791
9335
 
8792
9336
  // src/components/ui/tree-view.tsx
8793
- var React44 = __toESM(require("react"), 1);
9337
+ var React45 = __toESM(require("react"), 1);
8794
9338
  var import_lucide_react30 = require("lucide-react");
8795
9339
  var import_jsx_runtime57 = require("react/jsx-runtime");
8796
9340
  function TreeNodeItem({ node, depth, selected, expanded, onToggleExpand, onSelect, multiple }) {
@@ -8844,8 +9388,8 @@ function TreeView({
8844
9388
  className
8845
9389
  }) {
8846
9390
  const init = defaultSelected ? Array.isArray(defaultSelected) ? defaultSelected : [defaultSelected] : [];
8847
- const [internal, setInternal] = React44.useState(init);
8848
- const [expanded, setExpanded] = React44.useState(defaultExpanded);
9391
+ const [internal, setInternal] = React45.useState(init);
9392
+ const [expanded, setExpanded] = React45.useState(defaultExpanded);
8849
9393
  const selected = controlled ? Array.isArray(controlled) ? controlled : [controlled] : internal;
8850
9394
  function handleSelect(id) {
8851
9395
  let next;
@@ -8876,7 +9420,7 @@ function TreeView({
8876
9420
  }
8877
9421
 
8878
9422
  // src/components/ui/widget.tsx
8879
- var React45 = __toESM(require("react"), 1);
9423
+ var React46 = __toESM(require("react"), 1);
8880
9424
  var import_jsx_runtime58 = require("react/jsx-runtime");
8881
9425
  var iconColorMap = {
8882
9426
  primary: "bg-primary/10 text-primary",
@@ -8905,8 +9449,8 @@ var variantMap = {
8905
9449
  outline: "bg-transparent border-2"
8906
9450
  };
8907
9451
  function useCountUp(target, enabled, duration = 1e3) {
8908
- const [display, setDisplay] = React45.useState(enabled ? 0 : target);
8909
- React45.useEffect(() => {
9452
+ const [display, setDisplay] = React46.useState(enabled ? 0 : target);
9453
+ React46.useEffect(() => {
8910
9454
  if (!enabled) {
8911
9455
  setDisplay(target);
8912
9456
  return;
@@ -9019,7 +9563,7 @@ function Widget({
9019
9563
  }
9020
9564
 
9021
9565
  // src/components/ui/wizard.tsx
9022
- var React46 = __toESM(require("react"), 1);
9566
+ var React47 = __toESM(require("react"), 1);
9023
9567
  var import_lucide_react31 = require("lucide-react");
9024
9568
  var import_jsx_runtime59 = require("react/jsx-runtime");
9025
9569
  var SIZE_MAP = {
@@ -9043,7 +9587,7 @@ function HeaderDefault({
9043
9587
  return /* @__PURE__ */ (0, import_jsx_runtime59.jsx)("div", { className: "flex items-start w-full", children: steps.map((step, i) => {
9044
9588
  const status = stepStatus(i, current);
9045
9589
  const isLast = i === steps.length - 1;
9046
- 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: [
9047
9591
  /* @__PURE__ */ (0, import_jsx_runtime59.jsxs)("div", { className: "flex items-center w-full", children: [
9048
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") }),
9049
9593
  /* @__PURE__ */ (0, import_jsx_runtime59.jsx)(
@@ -9271,7 +9815,7 @@ function WizardPanel({
9271
9815
  const isFirst = current === 0;
9272
9816
  const isLast = current === steps.length - 1;
9273
9817
  const isSidebar = variant === "sidebar";
9274
- const [validationError, setValidationError] = React46.useState(null);
9818
+ const [validationError, setValidationError] = React47.useState(null);
9275
9819
  const handleNext = () => {
9276
9820
  const validate = steps[current]?.validate;
9277
9821
  if (validate) {
@@ -9375,7 +9919,7 @@ function Wizard({
9375
9919
  className,
9376
9920
  contentClassName
9377
9921
  }) {
9378
- const [internalStep, setInternalStep] = React46.useState(defaultStep);
9922
+ const [internalStep, setInternalStep] = React47.useState(defaultStep);
9379
9923
  const current = controlledStep ?? internalStep;
9380
9924
  const go = (idx) => {
9381
9925
  const clamped = Math.max(0, Math.min(steps.length - 1, idx));
@@ -9390,7 +9934,7 @@ function Wizard({
9390
9934
  }
9391
9935
  go(current + 1);
9392
9936
  };
9393
- React46.useEffect(() => {
9937
+ React47.useEffect(() => {
9394
9938
  if (layout !== "modal" || !isOpen || unchange) return;
9395
9939
  const handler = (e) => {
9396
9940
  if (e.key === "Escape") onClose?.();