pxengine 0.1.120 → 0.1.121

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.mjs CHANGED
@@ -15748,6 +15748,8 @@ import { useCallback as useCallback4, useEffect as useEffect7, useRef as useRef8
15748
15748
 
15749
15749
  // src/lib/shared-poll.ts
15750
15750
  import { useEffect as useEffect6, useRef as useRef7 } from "react";
15751
+ var MAX_RETAINED = 50;
15752
+ var RETAIN_TTL_MS = 30 * 60 * 1e3;
15751
15753
  var entries = /* @__PURE__ */ new Map();
15752
15754
  function clearTimer(entry) {
15753
15755
  if (entry.timer !== null) {
@@ -15757,6 +15759,32 @@ function clearTimer(entry) {
15757
15759
  entry.controller?.abort();
15758
15760
  entry.controller = null;
15759
15761
  }
15762
+ function isIdle(entry) {
15763
+ return entry.dataListeners.size === 0 && entry.errorListeners.size === 0;
15764
+ }
15765
+ function pruneRetained(keepKey) {
15766
+ const now = Date.now();
15767
+ const idle = [];
15768
+ for (const [key, entry] of entries) {
15769
+ if (!isIdle(entry)) continue;
15770
+ if (entry.retainedAt != null && now - entry.retainedAt > RETAIN_TTL_MS) {
15771
+ entries.delete(key);
15772
+ continue;
15773
+ }
15774
+ idle.push([key, entry]);
15775
+ }
15776
+ if (idle.length <= MAX_RETAINED) return;
15777
+ idle.sort(
15778
+ (a, b) => (a[1].retainedAt ?? 0) - (b[1].retainedAt ?? 0)
15779
+ );
15780
+ let excess = idle.length - MAX_RETAINED;
15781
+ for (const [key] of idle) {
15782
+ if (excess <= 0) break;
15783
+ if (key === keepKey) continue;
15784
+ entries.delete(key);
15785
+ excess -= 1;
15786
+ }
15787
+ }
15760
15788
  async function runPoll(key) {
15761
15789
  const entry = entries.get(key);
15762
15790
  if (!entry || entry.inFlight || entry.stopped) return;
@@ -15807,11 +15835,13 @@ function subscribeSharedPoll(config, onData, onError) {
15807
15835
  lastData: void 0,
15808
15836
  hasData: false,
15809
15837
  stopped: false,
15810
- inFlight: false
15838
+ inFlight: false,
15839
+ retainedAt: null
15811
15840
  };
15812
15841
  entries.set(key, entry);
15813
15842
  }
15814
15843
  const activeEntry = entry;
15844
+ activeEntry.retainedAt = null;
15815
15845
  activeEntry.dataListeners.add(onData);
15816
15846
  if (onError) activeEntry.errorListeners.add(onError);
15817
15847
  if (activeEntry.hasData && activeEntry.lastData !== void 0) {
@@ -15829,6 +15859,11 @@ function subscribeSharedPoll(config, onData, onError) {
15829
15859
  if (onError) activeEntry.errorListeners.delete(onError);
15830
15860
  if (activeEntry.dataListeners.size === 0 && activeEntry.errorListeners.size === 0) {
15831
15861
  clearTimer(activeEntry);
15862
+ if (activeEntry.hasData) {
15863
+ activeEntry.retainedAt = Date.now();
15864
+ pruneRetained(key);
15865
+ return;
15866
+ }
15832
15867
  entries.delete(key);
15833
15868
  }
15834
15869
  };
@@ -15839,6 +15874,16 @@ function stopSharedPoll(key) {
15839
15874
  entry.stopped = true;
15840
15875
  clearTimer(entry);
15841
15876
  }
15877
+ function getSharedPollLastData(key) {
15878
+ if (!key) return void 0;
15879
+ const entry = entries.get(key);
15880
+ if (!entry || !entry.hasData) return void 0;
15881
+ return entry.lastData;
15882
+ }
15883
+ function isSharedPollStopped(key) {
15884
+ if (!key) return false;
15885
+ return entries.get(key)?.stopped === true;
15886
+ }
15842
15887
  function useSharedPoll(config, onData, onError) {
15843
15888
  const fetcherRef = useRef7(config.fetcher);
15844
15889
  fetcherRef.current = config.fetcher;
@@ -22820,6 +22865,15 @@ var formatTime = (seconds) => {
22820
22865
  const minutes = Math.floor(seconds / 60);
22821
22866
  return minutes >= 1 ? `${minutes} min remaining...` : `${seconds} sec remaining...`;
22822
22867
  };
22868
+ function isTerminalStatus(status) {
22869
+ return status === "completed" || status === "complete" || status === "failed";
22870
+ }
22871
+ function versionPollKey(sessionId, version, validated) {
22872
+ return `creator:versions:${sessionId}:${version ?? "latest"}:${validated ? 1 : 0}`;
22873
+ }
22874
+ function statusPollKey(sessionId, version) {
22875
+ return `creator:status:${sessionId}:${version}`;
22876
+ }
22823
22877
  function useCreatorWidgetPolling({
22824
22878
  sessionId,
22825
22879
  currentVersion,
@@ -22834,17 +22888,53 @@ function useCreatorWidgetPolling({
22834
22888
  () => ({ ...DEFAULT_POLLING_CONFIG, ...pollingConfig }),
22835
22889
  [pollingConfig]
22836
22890
  );
22837
- const [versionData, setVersionData] = useState21(null);
22838
- const [totalVersions, setTotalVersions] = useState21(0);
22891
+ const hydrated = useMemo11(() => {
22892
+ if (!sessionId) {
22893
+ return {
22894
+ versionData: null,
22895
+ statusPayload: void 0,
22896
+ activeVersion: currentVersion
22897
+ };
22898
+ }
22899
+ const versionHint = currentVersion;
22900
+ const cachedVersion = getSharedPollLastData(
22901
+ versionPollKey(sessionId, versionHint, true)
22902
+ ) ?? getSharedPollLastData(
22903
+ versionPollKey(sessionId, versionHint, false)
22904
+ );
22905
+ const activeVersion2 = versionHint ?? cachedVersion?.currentVersion ?? void 0;
22906
+ const statusPayload = activeVersion2 != null ? getSharedPollLastData(
22907
+ statusPollKey(sessionId, activeVersion2)
22908
+ ) : void 0;
22909
+ return { versionData: cachedVersion ?? null, statusPayload, activeVersion: activeVersion2 };
22910
+ }, [sessionId, currentVersion]);
22911
+ const hydratedStatus = hydrated.statusPayload?.status?.status;
22912
+ const hydratedTerminal = isTerminalStatus(hydratedStatus);
22913
+ const [versionData, setVersionData] = useState21(
22914
+ hydrated.versionData
22915
+ );
22916
+ const [totalVersions, setTotalVersions] = useState21(
22917
+ hydrated.versionData?.totalVersions || 0
22918
+ );
22839
22919
  const [selectedVersion, setSelectedVersion] = useState21();
22840
- const [isLoadingVersion, setIsLoadingVersion] = useState21(false);
22841
- const [isValidationComplete, setIsValidationComplete] = useState21(false);
22842
- const [versionStatus, setVersionStatus] = useState21("checking");
22843
- const [statusDetails, setStatusDetails] = useState21();
22920
+ const [isLoadingVersion, setIsLoadingVersion] = useState21(!hydrated.versionData);
22921
+ const [isValidationComplete, setIsValidationComplete] = useState21(
22922
+ hydratedTerminal && hydratedStatus !== "failed"
22923
+ );
22924
+ const [versionStatus, setVersionStatus] = useState21(
22925
+ hydratedStatus || (hydrated.versionData ? "in-progress" : "checking")
22926
+ );
22927
+ const [statusDetails, setStatusDetails] = useState21(
22928
+ hydrated.statusPayload?.status
22929
+ );
22844
22930
  const [timeDisplay, setTimeDisplay] = useState21("");
22845
- const [loadingStatus, setLoadingStatus] = useState21(true);
22931
+ const [loadingStatus, setLoadingStatus] = useState21(
22932
+ !(hydrated.versionData && hydratedTerminal)
22933
+ );
22846
22934
  const remainingTimeRef = useRef13(0);
22847
22935
  const countdownRef = useRef13(null);
22936
+ const versionDataRef = useRef13(versionData);
22937
+ versionDataRef.current = versionData;
22848
22938
  const requestedVersion = selectedVersion ?? currentVersion ?? versionData?.currentVersion;
22849
22939
  const updateStatus = useCallback8(
22850
22940
  (status) => {
@@ -22853,13 +22943,13 @@ function useCreatorWidgetPolling({
22853
22943
  },
22854
22944
  [onStatusChange]
22855
22945
  );
22856
- const versionKey = sessionId ? `creator:versions:${sessionId}:${requestedVersion ?? "latest"}:${isValidationComplete ? 1 : 0}` : null;
22946
+ const versionKey = sessionId ? versionPollKey(sessionId, requestedVersion, isValidationComplete) : null;
22857
22947
  useSharedPoll(
22858
22948
  {
22859
22949
  key: versionKey,
22860
22950
  intervalMs: config.pollInterval,
22861
22951
  fetcher: async () => {
22862
- if (!versionData) setIsLoadingVersion(true);
22952
+ if (!versionDataRef.current) setIsLoadingVersion(true);
22863
22953
  return fetchVersions({
22864
22954
  sessionId,
22865
22955
  version: requestedVersion,
@@ -22883,10 +22973,10 @@ function useCreatorWidgetPolling({
22883
22973
  }
22884
22974
  );
22885
22975
  const activeVersion = selectedVersion ?? requestedVersion;
22886
- const statusKey = sessionId && activeVersion != null ? `creator:status:${sessionId}:${activeVersion}` : null;
22976
+ const statusKey = sessionId && activeVersion != null ? statusPollKey(sessionId, activeVersion) : null;
22887
22977
  const errorCountRef = useRef13(0);
22888
22978
  const deadlineRef = useRef13(0);
22889
- const doneRef = useRef13(false);
22979
+ const doneRef = useRef13(hydratedTerminal);
22890
22980
  const stopCountdown = useCallback8(() => {
22891
22981
  if (countdownRef.current) {
22892
22982
  clearInterval(countdownRef.current);
@@ -22896,13 +22986,28 @@ function useCreatorWidgetPolling({
22896
22986
  }, []);
22897
22987
  useEffect15(() => {
22898
22988
  if (statusKey == null) return;
22989
+ const cached = getSharedPollLastData(statusKey);
22990
+ const cachedStatus = cached?.status?.status;
22991
+ if (isTerminalStatus(cachedStatus) && isSharedPollStopped(statusKey)) {
22992
+ setStatusDetails(cached?.status);
22993
+ setVersionStatus(cachedStatus);
22994
+ onStatusChange?.(cachedStatus);
22995
+ if (cachedStatus === "completed" || cachedStatus === "complete") {
22996
+ setIsValidationComplete(true);
22997
+ }
22998
+ setLoadingStatus(false);
22999
+ doneRef.current = true;
23000
+ errorCountRef.current = 0;
23001
+ stopCountdown();
23002
+ return;
23003
+ }
22899
23004
  setLoadingStatus(true);
22900
23005
  setStatusDetails(void 0);
22901
23006
  setVersionStatus("checking");
22902
23007
  errorCountRef.current = 0;
22903
23008
  doneRef.current = false;
22904
23009
  deadlineRef.current = Date.now() + config.maxDuration;
22905
- const creatorLength2 = versionData?.length || 0;
23010
+ const creatorLength2 = versionDataRef.current?.length || 0;
22906
23011
  remainingTimeRef.current = creatorLength2 > 0 ? creatorLength2 * config.secondsPerCreator : 60;
22907
23012
  setTimeDisplay(formatTime(remainingTimeRef.current));
22908
23013
  countdownRef.current = setInterval(() => {
@@ -22924,7 +23029,7 @@ function useCreatorWidgetPolling({
22924
23029
  shouldContinue: (data) => {
22925
23030
  if (Date.now() >= deadlineRef.current) return false;
22926
23031
  const s = data?.status?.status;
22927
- return !(s === "completed" || s === "complete" || s === "failed");
23032
+ return !isTerminalStatus(s);
22928
23033
  }
22929
23034
  },
22930
23035
  (data) => {
@@ -23069,7 +23174,186 @@ function CreatorWidgetInner({
23069
23174
  var CreatorWidget = memo(CreatorWidgetInner);
23070
23175
 
23071
23176
  // src/molecules/analytics/AnalyticsChart.tsx
23072
- import { useEffect as useEffect16, useRef as useRef14, useState as useState23 } from "react";
23177
+ import { useEffect as useEffect16, useMemo as useMemo12, useRef as useRef14, useState as useState23 } from "react";
23178
+
23179
+ // src/molecules/analytics/buildOptions.ts
23180
+ function deepMerge(base, override) {
23181
+ const out = Array.isArray(base) ? [...base] : { ...base };
23182
+ for (const key of Object.keys(override)) {
23183
+ const o = override[key];
23184
+ const b = out[key];
23185
+ if (o && typeof o === "object" && !Array.isArray(o) && b && typeof b === "object" && !Array.isArray(b)) {
23186
+ out[key] = deepMerge(b, o);
23187
+ } else if (o !== void 0) {
23188
+ out[key] = o;
23189
+ }
23190
+ }
23191
+ return out;
23192
+ }
23193
+ function highchartsType(type) {
23194
+ if (type === "donut") return "pie";
23195
+ return type;
23196
+ }
23197
+ function buildAxis(axis, fallbackCategories) {
23198
+ const cfg = {};
23199
+ if (!axis) {
23200
+ if (fallbackCategories) cfg.categories = fallbackCategories;
23201
+ return cfg;
23202
+ }
23203
+ if (axis.title) cfg.title = { text: axis.title };
23204
+ if (axis.type) cfg.type = axis.type;
23205
+ if (axis.categories || fallbackCategories) cfg.categories = axis.categories ?? fallbackCategories;
23206
+ if (axis.format) cfg.labels = { format: axis.format };
23207
+ if (typeof axis.min === "number") cfg.min = axis.min;
23208
+ if (typeof axis.max === "number") cfg.max = axis.max;
23209
+ if (axis.opposite) cfg.opposite = true;
23210
+ return cfg;
23211
+ }
23212
+ function resolveStacking(stacked) {
23213
+ if (stacked === true || stacked === "normal") return "normal";
23214
+ if (stacked === "percent") return "percent";
23215
+ return void 0;
23216
+ }
23217
+ function buildChartOptions(config, palette) {
23218
+ const hcType = highchartsType(config.type);
23219
+ const isCircular = config.type === "pie" || config.type === "donut";
23220
+ const seriesColors = config.colors ?? palette.series;
23221
+ const safeSeries = Array.isArray(config.series) ? config.series : [];
23222
+ const options = {
23223
+ chart: { type: hcType, ...config.height && { height: config.height } },
23224
+ title: { text: config.title ?? void 0 },
23225
+ subtitle: { text: config.subtitle ?? void 0 },
23226
+ series: safeSeries.map((s, i) => ({
23227
+ name: s.name,
23228
+ data: s.data,
23229
+ ...s.type && { type: highchartsType(s.type) },
23230
+ ...s.stack && { stack: s.stack },
23231
+ ...typeof s.yAxis === "number" && { yAxis: s.yAxis },
23232
+ color: s.color ?? seriesColors[i % seriesColors.length]
23233
+ })),
23234
+ legend: { enabled: config.legend ?? (safeSeries.length > 1 || isCircular) }
23235
+ };
23236
+ if (config.colors) options.colors = config.colors;
23237
+ if (!isCircular && config.type !== "funnel") {
23238
+ options.xAxis = buildAxis(config.xAxis, config.categories);
23239
+ const yAxes = Array.isArray(config.yAxis) ? config.yAxis : [config.yAxis];
23240
+ options.yAxis = yAxes.map((a) => buildAxis(a));
23241
+ if (options.yAxis.length === 1) options.yAxis = options.yAxis[0];
23242
+ }
23243
+ if (config.tooltip) {
23244
+ options.tooltip = {
23245
+ ...config.tooltip.shared !== void 0 && { shared: config.tooltip.shared },
23246
+ ...config.tooltip.valuePrefix && { valuePrefix: config.tooltip.valuePrefix },
23247
+ ...config.tooltip.valueSuffix && { valueSuffix: config.tooltip.valueSuffix },
23248
+ ...config.tooltip.pointFormat && { pointFormat: config.tooltip.pointFormat }
23249
+ };
23250
+ }
23251
+ const stacking = resolveStacking(config.stacked);
23252
+ const dataLabels = config.dataLabels === true ? { enabled: true } : config.dataLabels && typeof config.dataLabels === "object" ? { enabled: true, ...config.dataLabels } : void 0;
23253
+ const plotOptions = {};
23254
+ if (stacking || dataLabels) {
23255
+ plotOptions.series = {
23256
+ ...stacking && { stacking },
23257
+ ...dataLabels && { dataLabels }
23258
+ };
23259
+ }
23260
+ if (config.type === "donut") {
23261
+ plotOptions.pie = {
23262
+ innerSize: "55%",
23263
+ dataLabels: dataLabels ?? {
23264
+ enabled: true,
23265
+ format: "<b>{point.name}</b>: {point.percentage:.1f}%"
23266
+ }
23267
+ };
23268
+ } else if (config.type === "pie") {
23269
+ plotOptions.pie = {
23270
+ dataLabels: dataLabels ?? {
23271
+ enabled: true,
23272
+ format: "<b>{point.name}</b>: {point.percentage:.1f}%"
23273
+ }
23274
+ };
23275
+ } else if (config.type === "funnel") {
23276
+ plotOptions.funnel = {
23277
+ neckWidth: "30%",
23278
+ neckHeight: "25%",
23279
+ dataLabels: dataLabels ?? { enabled: true, format: "<b>{point.name}</b> ({point.y:,.0f})" }
23280
+ };
23281
+ }
23282
+ if (Object.keys(plotOptions).length) options.plotOptions = plotOptions;
23283
+ return options;
23284
+ }
23285
+
23286
+ // src/molecules/analytics/highchartsTheme.ts
23287
+ var PXENGINE_SERIES_COLORS = [
23288
+ "#6366f1",
23289
+ // indigo
23290
+ "#10b981",
23291
+ // emerald
23292
+ "#f59e0b",
23293
+ // amber
23294
+ "#ec4899",
23295
+ // pink
23296
+ "#8b5cf6",
23297
+ // violet
23298
+ "#06b6d4",
23299
+ // cyan
23300
+ "#f43f5e",
23301
+ // rose
23302
+ "#84cc16",
23303
+ // lime
23304
+ "#3b82f6",
23305
+ // blue
23306
+ "#f97316"
23307
+ // orange
23308
+ ];
23309
+ var DARK_PALETTE = {
23310
+ text: "#e5e7eb",
23311
+ textMuted: "#9ca3af",
23312
+ grid: "rgba(255,255,255,0.08)",
23313
+ border: "rgba(255,255,255,0.12)",
23314
+ background: "transparent",
23315
+ series: PXENGINE_SERIES_COLORS,
23316
+ tooltipBg: "rgba(17,24,39,0.95)",
23317
+ tooltipText: "#f9fafb"
23318
+ };
23319
+ var LIGHT_PALETTE = {
23320
+ text: "#1f2937",
23321
+ textMuted: "#6b7280",
23322
+ grid: "rgba(0,0,0,0.06)",
23323
+ border: "rgba(0,0,0,0.10)",
23324
+ background: "transparent",
23325
+ series: PXENGINE_SERIES_COLORS,
23326
+ tooltipBg: "rgba(255,255,255,0.98)",
23327
+ tooltipText: "#111827"
23328
+ };
23329
+ function resolveColorMode(mode = "auto") {
23330
+ if (mode === "light" || mode === "dark") return mode;
23331
+ if (typeof document !== "undefined") {
23332
+ if (document.documentElement.classList.contains("dark")) return "dark";
23333
+ if (typeof window !== "undefined" && window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
23334
+ return "dark";
23335
+ }
23336
+ return "light";
23337
+ }
23338
+ return "dark";
23339
+ }
23340
+ function buildChartPalette(theme, mode = "auto") {
23341
+ const base = resolveColorMode(mode) === "dark" ? DARK_PALETTE : LIGHT_PALETTE;
23342
+ if (!theme) return base;
23343
+ const series = theme.accent ? [theme.accent, ...base.series.filter((c) => c.toLowerCase() !== theme.accent.toLowerCase())] : base.series;
23344
+ return {
23345
+ ...base,
23346
+ ...theme.text && { text: theme.text },
23347
+ ...theme.textMuted && { textMuted: theme.textMuted },
23348
+ ...theme.border && { border: theme.border, grid: theme.border },
23349
+ ...theme.surface && { tooltipBg: theme.surface },
23350
+ ...theme.text && { tooltipText: theme.text },
23351
+ ...theme.fontFamily && { fontFamily: theme.fontFamily },
23352
+ series
23353
+ };
23354
+ }
23355
+
23356
+ // src/molecules/analytics/AnalyticsChart.tsx
23073
23357
  import { jsx as jsx179, jsxs as jsxs137 } from "react/jsx-runtime";
23074
23358
  function getCSSVar(name) {
23075
23359
  if (typeof document === "undefined") return "";
@@ -23106,6 +23390,30 @@ function stripNulls(val) {
23106
23390
  }
23107
23391
  return val;
23108
23392
  }
23393
+ function resolveDeclarativeConfig(props) {
23394
+ if (props.chartConfig) {
23395
+ return {
23396
+ ...props.chartConfig,
23397
+ ...props.height != null && !props.chartConfig.height ? { height: props.height } : {}
23398
+ };
23399
+ }
23400
+ if (!props.chartType) return null;
23401
+ return {
23402
+ type: props.chartType,
23403
+ title: props.title,
23404
+ subtitle: props.subtitle,
23405
+ series: props.series ?? [],
23406
+ categories: props.categories,
23407
+ xAxis: props.xAxis,
23408
+ yAxis: props.yAxis,
23409
+ colors: props.colors,
23410
+ stacked: props.stacked,
23411
+ legend: props.legend,
23412
+ tooltip: props.tooltip,
23413
+ dataLabels: props.dataLabels,
23414
+ height: props.height
23415
+ };
23416
+ }
23109
23417
  var hcSingleton = null;
23110
23418
  var hcLoadPromise = null;
23111
23419
  function loadHighcharts() {
@@ -23174,9 +23482,25 @@ function buildTheme(height) {
23174
23482
  }
23175
23483
  function AnalyticsChart({
23176
23484
  config: configProp,
23485
+ chartConfig,
23486
+ chartType,
23487
+ series,
23488
+ categories,
23489
+ xAxis,
23490
+ yAxis,
23491
+ colors,
23492
+ stacked,
23493
+ legend,
23494
+ tooltip,
23495
+ dataLabels,
23496
+ extraOptions,
23177
23497
  chartId,
23178
23498
  apiBase = "",
23179
23499
  authToken,
23500
+ title,
23501
+ subtitle,
23502
+ theme,
23503
+ mode = "auto",
23180
23504
  height = 400,
23181
23505
  className,
23182
23506
  loading: loadingProp,
@@ -23188,11 +23512,51 @@ function AnalyticsChart({
23188
23512
  const [fetchError, setFetchError] = useState23(null);
23189
23513
  const containerRef = useRef14(null);
23190
23514
  const chartRef = useRef14(null);
23515
+ const declarative = useMemo12(
23516
+ () => resolveDeclarativeConfig({
23517
+ chartConfig,
23518
+ chartType,
23519
+ title,
23520
+ subtitle,
23521
+ series,
23522
+ categories,
23523
+ xAxis,
23524
+ yAxis,
23525
+ colors,
23526
+ stacked,
23527
+ legend,
23528
+ tooltip,
23529
+ dataLabels,
23530
+ height
23531
+ }),
23532
+ [
23533
+ chartConfig,
23534
+ chartType,
23535
+ title,
23536
+ subtitle,
23537
+ series,
23538
+ categories,
23539
+ xAxis,
23540
+ yAxis,
23541
+ colors,
23542
+ stacked,
23543
+ legend,
23544
+ tooltip,
23545
+ dataLabels,
23546
+ height
23547
+ ]
23548
+ );
23549
+ const builtConfig = useMemo12(() => {
23550
+ if (!declarative) return null;
23551
+ const palette = buildChartPalette(theme, mode);
23552
+ const options = buildChartOptions(declarative, palette);
23553
+ return extraOptions ? deepMerge(options, extraOptions) : options;
23554
+ }, [declarative, theme, mode, extraOptions]);
23191
23555
  useEffect16(() => {
23192
23556
  setMounted(true);
23193
23557
  }, []);
23194
23558
  useEffect16(() => {
23195
- if (!chartId || configProp) return;
23559
+ if (!chartId || configProp || builtConfig) return;
23196
23560
  let cancelled = false;
23197
23561
  setFetching(true);
23198
23562
  setFetchError(null);
@@ -23211,8 +23575,8 @@ function AnalyticsChart({
23211
23575
  return () => {
23212
23576
  cancelled = true;
23213
23577
  };
23214
- }, [chartId, apiBase, authToken, configProp]);
23215
- const activeConfig = configProp ?? fetchedConfig;
23578
+ }, [chartId, apiBase, authToken, configProp, builtConfig]);
23579
+ const activeConfig = configProp ?? builtConfig ?? fetchedConfig;
23216
23580
  useEffect16(() => {
23217
23581
  if (!mounted || !activeConfig || !containerRef.current) return;
23218
23582
  const container = containerRef.current;
@@ -23726,7 +24090,7 @@ function EmptyContent({ className, ...props }) {
23726
24090
  }
23727
24091
 
23728
24092
  // src/components/ui/field.tsx
23729
- import { useMemo as useMemo12 } from "react";
24093
+ import { useMemo as useMemo13 } from "react";
23730
24094
  import { cva as cva10 } from "class-variance-authority";
23731
24095
  import { jsx as jsx182, jsxs as jsxs138 } from "react/jsx-runtime";
23732
24096
  function FieldSet({ className, ...props }) {
@@ -23909,7 +24273,7 @@ function FieldError({
23909
24273
  errors,
23910
24274
  ...props
23911
24275
  }) {
23912
- const content = useMemo12(() => {
24276
+ const content = useMemo13(() => {
23913
24277
  if (children) {
23914
24278
  return children;
23915
24279
  }