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.cjs CHANGED
@@ -16080,6 +16080,8 @@ var import_react79 = require("react");
16080
16080
 
16081
16081
  // src/lib/shared-poll.ts
16082
16082
  var import_react78 = require("react");
16083
+ var MAX_RETAINED = 50;
16084
+ var RETAIN_TTL_MS = 30 * 60 * 1e3;
16083
16085
  var entries = /* @__PURE__ */ new Map();
16084
16086
  function clearTimer(entry) {
16085
16087
  if (entry.timer !== null) {
@@ -16089,6 +16091,32 @@ function clearTimer(entry) {
16089
16091
  entry.controller?.abort();
16090
16092
  entry.controller = null;
16091
16093
  }
16094
+ function isIdle(entry) {
16095
+ return entry.dataListeners.size === 0 && entry.errorListeners.size === 0;
16096
+ }
16097
+ function pruneRetained(keepKey) {
16098
+ const now = Date.now();
16099
+ const idle = [];
16100
+ for (const [key, entry] of entries) {
16101
+ if (!isIdle(entry)) continue;
16102
+ if (entry.retainedAt != null && now - entry.retainedAt > RETAIN_TTL_MS) {
16103
+ entries.delete(key);
16104
+ continue;
16105
+ }
16106
+ idle.push([key, entry]);
16107
+ }
16108
+ if (idle.length <= MAX_RETAINED) return;
16109
+ idle.sort(
16110
+ (a, b) => (a[1].retainedAt ?? 0) - (b[1].retainedAt ?? 0)
16111
+ );
16112
+ let excess = idle.length - MAX_RETAINED;
16113
+ for (const [key] of idle) {
16114
+ if (excess <= 0) break;
16115
+ if (key === keepKey) continue;
16116
+ entries.delete(key);
16117
+ excess -= 1;
16118
+ }
16119
+ }
16092
16120
  async function runPoll(key) {
16093
16121
  const entry = entries.get(key);
16094
16122
  if (!entry || entry.inFlight || entry.stopped) return;
@@ -16139,11 +16167,13 @@ function subscribeSharedPoll(config, onData, onError) {
16139
16167
  lastData: void 0,
16140
16168
  hasData: false,
16141
16169
  stopped: false,
16142
- inFlight: false
16170
+ inFlight: false,
16171
+ retainedAt: null
16143
16172
  };
16144
16173
  entries.set(key, entry);
16145
16174
  }
16146
16175
  const activeEntry = entry;
16176
+ activeEntry.retainedAt = null;
16147
16177
  activeEntry.dataListeners.add(onData);
16148
16178
  if (onError) activeEntry.errorListeners.add(onError);
16149
16179
  if (activeEntry.hasData && activeEntry.lastData !== void 0) {
@@ -16161,6 +16191,11 @@ function subscribeSharedPoll(config, onData, onError) {
16161
16191
  if (onError) activeEntry.errorListeners.delete(onError);
16162
16192
  if (activeEntry.dataListeners.size === 0 && activeEntry.errorListeners.size === 0) {
16163
16193
  clearTimer(activeEntry);
16194
+ if (activeEntry.hasData) {
16195
+ activeEntry.retainedAt = Date.now();
16196
+ pruneRetained(key);
16197
+ return;
16198
+ }
16164
16199
  entries.delete(key);
16165
16200
  }
16166
16201
  };
@@ -16171,6 +16206,16 @@ function stopSharedPoll(key) {
16171
16206
  entry.stopped = true;
16172
16207
  clearTimer(entry);
16173
16208
  }
16209
+ function getSharedPollLastData(key) {
16210
+ if (!key) return void 0;
16211
+ const entry = entries.get(key);
16212
+ if (!entry || !entry.hasData) return void 0;
16213
+ return entry.lastData;
16214
+ }
16215
+ function isSharedPollStopped(key) {
16216
+ if (!key) return false;
16217
+ return entries.get(key)?.stopped === true;
16218
+ }
16174
16219
  function useSharedPoll(config, onData, onError) {
16175
16220
  const fetcherRef = (0, import_react78.useRef)(config.fetcher);
16176
16221
  fetcherRef.current = config.fetcher;
@@ -23152,6 +23197,15 @@ var formatTime = (seconds) => {
23152
23197
  const minutes = Math.floor(seconds / 60);
23153
23198
  return minutes >= 1 ? `${minutes} min remaining...` : `${seconds} sec remaining...`;
23154
23199
  };
23200
+ function isTerminalStatus(status) {
23201
+ return status === "completed" || status === "complete" || status === "failed";
23202
+ }
23203
+ function versionPollKey(sessionId, version, validated) {
23204
+ return `creator:versions:${sessionId}:${version ?? "latest"}:${validated ? 1 : 0}`;
23205
+ }
23206
+ function statusPollKey(sessionId, version) {
23207
+ return `creator:status:${sessionId}:${version}`;
23208
+ }
23155
23209
  function useCreatorWidgetPolling({
23156
23210
  sessionId,
23157
23211
  currentVersion,
@@ -23166,17 +23220,53 @@ function useCreatorWidgetPolling({
23166
23220
  () => ({ ...DEFAULT_POLLING_CONFIG, ...pollingConfig }),
23167
23221
  [pollingConfig]
23168
23222
  );
23169
- const [versionData, setVersionData] = (0, import_react94.useState)(null);
23170
- const [totalVersions, setTotalVersions] = (0, import_react94.useState)(0);
23223
+ const hydrated = (0, import_react94.useMemo)(() => {
23224
+ if (!sessionId) {
23225
+ return {
23226
+ versionData: null,
23227
+ statusPayload: void 0,
23228
+ activeVersion: currentVersion
23229
+ };
23230
+ }
23231
+ const versionHint = currentVersion;
23232
+ const cachedVersion = getSharedPollLastData(
23233
+ versionPollKey(sessionId, versionHint, true)
23234
+ ) ?? getSharedPollLastData(
23235
+ versionPollKey(sessionId, versionHint, false)
23236
+ );
23237
+ const activeVersion2 = versionHint ?? cachedVersion?.currentVersion ?? void 0;
23238
+ const statusPayload = activeVersion2 != null ? getSharedPollLastData(
23239
+ statusPollKey(sessionId, activeVersion2)
23240
+ ) : void 0;
23241
+ return { versionData: cachedVersion ?? null, statusPayload, activeVersion: activeVersion2 };
23242
+ }, [sessionId, currentVersion]);
23243
+ const hydratedStatus = hydrated.statusPayload?.status?.status;
23244
+ const hydratedTerminal = isTerminalStatus(hydratedStatus);
23245
+ const [versionData, setVersionData] = (0, import_react94.useState)(
23246
+ hydrated.versionData
23247
+ );
23248
+ const [totalVersions, setTotalVersions] = (0, import_react94.useState)(
23249
+ hydrated.versionData?.totalVersions || 0
23250
+ );
23171
23251
  const [selectedVersion, setSelectedVersion] = (0, import_react94.useState)();
23172
- const [isLoadingVersion, setIsLoadingVersion] = (0, import_react94.useState)(false);
23173
- const [isValidationComplete, setIsValidationComplete] = (0, import_react94.useState)(false);
23174
- const [versionStatus, setVersionStatus] = (0, import_react94.useState)("checking");
23175
- const [statusDetails, setStatusDetails] = (0, import_react94.useState)();
23252
+ const [isLoadingVersion, setIsLoadingVersion] = (0, import_react94.useState)(!hydrated.versionData);
23253
+ const [isValidationComplete, setIsValidationComplete] = (0, import_react94.useState)(
23254
+ hydratedTerminal && hydratedStatus !== "failed"
23255
+ );
23256
+ const [versionStatus, setVersionStatus] = (0, import_react94.useState)(
23257
+ hydratedStatus || (hydrated.versionData ? "in-progress" : "checking")
23258
+ );
23259
+ const [statusDetails, setStatusDetails] = (0, import_react94.useState)(
23260
+ hydrated.statusPayload?.status
23261
+ );
23176
23262
  const [timeDisplay, setTimeDisplay] = (0, import_react94.useState)("");
23177
- const [loadingStatus, setLoadingStatus] = (0, import_react94.useState)(true);
23263
+ const [loadingStatus, setLoadingStatus] = (0, import_react94.useState)(
23264
+ !(hydrated.versionData && hydratedTerminal)
23265
+ );
23178
23266
  const remainingTimeRef = (0, import_react94.useRef)(0);
23179
23267
  const countdownRef = (0, import_react94.useRef)(null);
23268
+ const versionDataRef = (0, import_react94.useRef)(versionData);
23269
+ versionDataRef.current = versionData;
23180
23270
  const requestedVersion = selectedVersion ?? currentVersion ?? versionData?.currentVersion;
23181
23271
  const updateStatus = (0, import_react94.useCallback)(
23182
23272
  (status) => {
@@ -23185,13 +23275,13 @@ function useCreatorWidgetPolling({
23185
23275
  },
23186
23276
  [onStatusChange]
23187
23277
  );
23188
- const versionKey = sessionId ? `creator:versions:${sessionId}:${requestedVersion ?? "latest"}:${isValidationComplete ? 1 : 0}` : null;
23278
+ const versionKey = sessionId ? versionPollKey(sessionId, requestedVersion, isValidationComplete) : null;
23189
23279
  useSharedPoll(
23190
23280
  {
23191
23281
  key: versionKey,
23192
23282
  intervalMs: config.pollInterval,
23193
23283
  fetcher: async () => {
23194
- if (!versionData) setIsLoadingVersion(true);
23284
+ if (!versionDataRef.current) setIsLoadingVersion(true);
23195
23285
  return fetchVersions({
23196
23286
  sessionId,
23197
23287
  version: requestedVersion,
@@ -23215,10 +23305,10 @@ function useCreatorWidgetPolling({
23215
23305
  }
23216
23306
  );
23217
23307
  const activeVersion = selectedVersion ?? requestedVersion;
23218
- const statusKey = sessionId && activeVersion != null ? `creator:status:${sessionId}:${activeVersion}` : null;
23308
+ const statusKey = sessionId && activeVersion != null ? statusPollKey(sessionId, activeVersion) : null;
23219
23309
  const errorCountRef = (0, import_react94.useRef)(0);
23220
23310
  const deadlineRef = (0, import_react94.useRef)(0);
23221
- const doneRef = (0, import_react94.useRef)(false);
23311
+ const doneRef = (0, import_react94.useRef)(hydratedTerminal);
23222
23312
  const stopCountdown = (0, import_react94.useCallback)(() => {
23223
23313
  if (countdownRef.current) {
23224
23314
  clearInterval(countdownRef.current);
@@ -23228,13 +23318,28 @@ function useCreatorWidgetPolling({
23228
23318
  }, []);
23229
23319
  (0, import_react94.useEffect)(() => {
23230
23320
  if (statusKey == null) return;
23321
+ const cached = getSharedPollLastData(statusKey);
23322
+ const cachedStatus = cached?.status?.status;
23323
+ if (isTerminalStatus(cachedStatus) && isSharedPollStopped(statusKey)) {
23324
+ setStatusDetails(cached?.status);
23325
+ setVersionStatus(cachedStatus);
23326
+ onStatusChange?.(cachedStatus);
23327
+ if (cachedStatus === "completed" || cachedStatus === "complete") {
23328
+ setIsValidationComplete(true);
23329
+ }
23330
+ setLoadingStatus(false);
23331
+ doneRef.current = true;
23332
+ errorCountRef.current = 0;
23333
+ stopCountdown();
23334
+ return;
23335
+ }
23231
23336
  setLoadingStatus(true);
23232
23337
  setStatusDetails(void 0);
23233
23338
  setVersionStatus("checking");
23234
23339
  errorCountRef.current = 0;
23235
23340
  doneRef.current = false;
23236
23341
  deadlineRef.current = Date.now() + config.maxDuration;
23237
- const creatorLength2 = versionData?.length || 0;
23342
+ const creatorLength2 = versionDataRef.current?.length || 0;
23238
23343
  remainingTimeRef.current = creatorLength2 > 0 ? creatorLength2 * config.secondsPerCreator : 60;
23239
23344
  setTimeDisplay(formatTime(remainingTimeRef.current));
23240
23345
  countdownRef.current = setInterval(() => {
@@ -23256,7 +23361,7 @@ function useCreatorWidgetPolling({
23256
23361
  shouldContinue: (data) => {
23257
23362
  if (Date.now() >= deadlineRef.current) return false;
23258
23363
  const s = data?.status?.status;
23259
- return !(s === "completed" || s === "complete" || s === "failed");
23364
+ return !isTerminalStatus(s);
23260
23365
  }
23261
23366
  },
23262
23367
  (data) => {
@@ -23402,6 +23507,185 @@ var CreatorWidget = (0, import_react95.memo)(CreatorWidgetInner);
23402
23507
 
23403
23508
  // src/molecules/analytics/AnalyticsChart.tsx
23404
23509
  var import_react96 = require("react");
23510
+
23511
+ // src/molecules/analytics/buildOptions.ts
23512
+ function deepMerge(base, override) {
23513
+ const out = Array.isArray(base) ? [...base] : { ...base };
23514
+ for (const key of Object.keys(override)) {
23515
+ const o = override[key];
23516
+ const b = out[key];
23517
+ if (o && typeof o === "object" && !Array.isArray(o) && b && typeof b === "object" && !Array.isArray(b)) {
23518
+ out[key] = deepMerge(b, o);
23519
+ } else if (o !== void 0) {
23520
+ out[key] = o;
23521
+ }
23522
+ }
23523
+ return out;
23524
+ }
23525
+ function highchartsType(type) {
23526
+ if (type === "donut") return "pie";
23527
+ return type;
23528
+ }
23529
+ function buildAxis(axis, fallbackCategories) {
23530
+ const cfg = {};
23531
+ if (!axis) {
23532
+ if (fallbackCategories) cfg.categories = fallbackCategories;
23533
+ return cfg;
23534
+ }
23535
+ if (axis.title) cfg.title = { text: axis.title };
23536
+ if (axis.type) cfg.type = axis.type;
23537
+ if (axis.categories || fallbackCategories) cfg.categories = axis.categories ?? fallbackCategories;
23538
+ if (axis.format) cfg.labels = { format: axis.format };
23539
+ if (typeof axis.min === "number") cfg.min = axis.min;
23540
+ if (typeof axis.max === "number") cfg.max = axis.max;
23541
+ if (axis.opposite) cfg.opposite = true;
23542
+ return cfg;
23543
+ }
23544
+ function resolveStacking(stacked) {
23545
+ if (stacked === true || stacked === "normal") return "normal";
23546
+ if (stacked === "percent") return "percent";
23547
+ return void 0;
23548
+ }
23549
+ function buildChartOptions(config, palette) {
23550
+ const hcType = highchartsType(config.type);
23551
+ const isCircular = config.type === "pie" || config.type === "donut";
23552
+ const seriesColors = config.colors ?? palette.series;
23553
+ const safeSeries = Array.isArray(config.series) ? config.series : [];
23554
+ const options = {
23555
+ chart: { type: hcType, ...config.height && { height: config.height } },
23556
+ title: { text: config.title ?? void 0 },
23557
+ subtitle: { text: config.subtitle ?? void 0 },
23558
+ series: safeSeries.map((s, i) => ({
23559
+ name: s.name,
23560
+ data: s.data,
23561
+ ...s.type && { type: highchartsType(s.type) },
23562
+ ...s.stack && { stack: s.stack },
23563
+ ...typeof s.yAxis === "number" && { yAxis: s.yAxis },
23564
+ color: s.color ?? seriesColors[i % seriesColors.length]
23565
+ })),
23566
+ legend: { enabled: config.legend ?? (safeSeries.length > 1 || isCircular) }
23567
+ };
23568
+ if (config.colors) options.colors = config.colors;
23569
+ if (!isCircular && config.type !== "funnel") {
23570
+ options.xAxis = buildAxis(config.xAxis, config.categories);
23571
+ const yAxes = Array.isArray(config.yAxis) ? config.yAxis : [config.yAxis];
23572
+ options.yAxis = yAxes.map((a) => buildAxis(a));
23573
+ if (options.yAxis.length === 1) options.yAxis = options.yAxis[0];
23574
+ }
23575
+ if (config.tooltip) {
23576
+ options.tooltip = {
23577
+ ...config.tooltip.shared !== void 0 && { shared: config.tooltip.shared },
23578
+ ...config.tooltip.valuePrefix && { valuePrefix: config.tooltip.valuePrefix },
23579
+ ...config.tooltip.valueSuffix && { valueSuffix: config.tooltip.valueSuffix },
23580
+ ...config.tooltip.pointFormat && { pointFormat: config.tooltip.pointFormat }
23581
+ };
23582
+ }
23583
+ const stacking = resolveStacking(config.stacked);
23584
+ const dataLabels = config.dataLabels === true ? { enabled: true } : config.dataLabels && typeof config.dataLabels === "object" ? { enabled: true, ...config.dataLabels } : void 0;
23585
+ const plotOptions = {};
23586
+ if (stacking || dataLabels) {
23587
+ plotOptions.series = {
23588
+ ...stacking && { stacking },
23589
+ ...dataLabels && { dataLabels }
23590
+ };
23591
+ }
23592
+ if (config.type === "donut") {
23593
+ plotOptions.pie = {
23594
+ innerSize: "55%",
23595
+ dataLabels: dataLabels ?? {
23596
+ enabled: true,
23597
+ format: "<b>{point.name}</b>: {point.percentage:.1f}%"
23598
+ }
23599
+ };
23600
+ } else if (config.type === "pie") {
23601
+ plotOptions.pie = {
23602
+ dataLabels: dataLabels ?? {
23603
+ enabled: true,
23604
+ format: "<b>{point.name}</b>: {point.percentage:.1f}%"
23605
+ }
23606
+ };
23607
+ } else if (config.type === "funnel") {
23608
+ plotOptions.funnel = {
23609
+ neckWidth: "30%",
23610
+ neckHeight: "25%",
23611
+ dataLabels: dataLabels ?? { enabled: true, format: "<b>{point.name}</b> ({point.y:,.0f})" }
23612
+ };
23613
+ }
23614
+ if (Object.keys(plotOptions).length) options.plotOptions = plotOptions;
23615
+ return options;
23616
+ }
23617
+
23618
+ // src/molecules/analytics/highchartsTheme.ts
23619
+ var PXENGINE_SERIES_COLORS = [
23620
+ "#6366f1",
23621
+ // indigo
23622
+ "#10b981",
23623
+ // emerald
23624
+ "#f59e0b",
23625
+ // amber
23626
+ "#ec4899",
23627
+ // pink
23628
+ "#8b5cf6",
23629
+ // violet
23630
+ "#06b6d4",
23631
+ // cyan
23632
+ "#f43f5e",
23633
+ // rose
23634
+ "#84cc16",
23635
+ // lime
23636
+ "#3b82f6",
23637
+ // blue
23638
+ "#f97316"
23639
+ // orange
23640
+ ];
23641
+ var DARK_PALETTE = {
23642
+ text: "#e5e7eb",
23643
+ textMuted: "#9ca3af",
23644
+ grid: "rgba(255,255,255,0.08)",
23645
+ border: "rgba(255,255,255,0.12)",
23646
+ background: "transparent",
23647
+ series: PXENGINE_SERIES_COLORS,
23648
+ tooltipBg: "rgba(17,24,39,0.95)",
23649
+ tooltipText: "#f9fafb"
23650
+ };
23651
+ var LIGHT_PALETTE = {
23652
+ text: "#1f2937",
23653
+ textMuted: "#6b7280",
23654
+ grid: "rgba(0,0,0,0.06)",
23655
+ border: "rgba(0,0,0,0.10)",
23656
+ background: "transparent",
23657
+ series: PXENGINE_SERIES_COLORS,
23658
+ tooltipBg: "rgba(255,255,255,0.98)",
23659
+ tooltipText: "#111827"
23660
+ };
23661
+ function resolveColorMode(mode = "auto") {
23662
+ if (mode === "light" || mode === "dark") return mode;
23663
+ if (typeof document !== "undefined") {
23664
+ if (document.documentElement.classList.contains("dark")) return "dark";
23665
+ if (typeof window !== "undefined" && window.matchMedia && window.matchMedia("(prefers-color-scheme: dark)").matches) {
23666
+ return "dark";
23667
+ }
23668
+ return "light";
23669
+ }
23670
+ return "dark";
23671
+ }
23672
+ function buildChartPalette(theme, mode = "auto") {
23673
+ const base = resolveColorMode(mode) === "dark" ? DARK_PALETTE : LIGHT_PALETTE;
23674
+ if (!theme) return base;
23675
+ const series = theme.accent ? [theme.accent, ...base.series.filter((c) => c.toLowerCase() !== theme.accent.toLowerCase())] : base.series;
23676
+ return {
23677
+ ...base,
23678
+ ...theme.text && { text: theme.text },
23679
+ ...theme.textMuted && { textMuted: theme.textMuted },
23680
+ ...theme.border && { border: theme.border, grid: theme.border },
23681
+ ...theme.surface && { tooltipBg: theme.surface },
23682
+ ...theme.text && { tooltipText: theme.text },
23683
+ ...theme.fontFamily && { fontFamily: theme.fontFamily },
23684
+ series
23685
+ };
23686
+ }
23687
+
23688
+ // src/molecules/analytics/AnalyticsChart.tsx
23405
23689
  var import_jsx_runtime179 = require("react/jsx-runtime");
23406
23690
  function getCSSVar(name) {
23407
23691
  if (typeof document === "undefined") return "";
@@ -23438,6 +23722,30 @@ function stripNulls(val) {
23438
23722
  }
23439
23723
  return val;
23440
23724
  }
23725
+ function resolveDeclarativeConfig(props) {
23726
+ if (props.chartConfig) {
23727
+ return {
23728
+ ...props.chartConfig,
23729
+ ...props.height != null && !props.chartConfig.height ? { height: props.height } : {}
23730
+ };
23731
+ }
23732
+ if (!props.chartType) return null;
23733
+ return {
23734
+ type: props.chartType,
23735
+ title: props.title,
23736
+ subtitle: props.subtitle,
23737
+ series: props.series ?? [],
23738
+ categories: props.categories,
23739
+ xAxis: props.xAxis,
23740
+ yAxis: props.yAxis,
23741
+ colors: props.colors,
23742
+ stacked: props.stacked,
23743
+ legend: props.legend,
23744
+ tooltip: props.tooltip,
23745
+ dataLabels: props.dataLabels,
23746
+ height: props.height
23747
+ };
23748
+ }
23441
23749
  var hcSingleton = null;
23442
23750
  var hcLoadPromise = null;
23443
23751
  function loadHighcharts() {
@@ -23506,9 +23814,25 @@ function buildTheme(height) {
23506
23814
  }
23507
23815
  function AnalyticsChart({
23508
23816
  config: configProp,
23817
+ chartConfig,
23818
+ chartType,
23819
+ series,
23820
+ categories,
23821
+ xAxis,
23822
+ yAxis,
23823
+ colors,
23824
+ stacked,
23825
+ legend,
23826
+ tooltip,
23827
+ dataLabels,
23828
+ extraOptions,
23509
23829
  chartId,
23510
23830
  apiBase = "",
23511
23831
  authToken,
23832
+ title,
23833
+ subtitle,
23834
+ theme,
23835
+ mode = "auto",
23512
23836
  height = 400,
23513
23837
  className,
23514
23838
  loading: loadingProp,
@@ -23520,11 +23844,51 @@ function AnalyticsChart({
23520
23844
  const [fetchError, setFetchError] = (0, import_react96.useState)(null);
23521
23845
  const containerRef = (0, import_react96.useRef)(null);
23522
23846
  const chartRef = (0, import_react96.useRef)(null);
23847
+ const declarative = (0, import_react96.useMemo)(
23848
+ () => resolveDeclarativeConfig({
23849
+ chartConfig,
23850
+ chartType,
23851
+ title,
23852
+ subtitle,
23853
+ series,
23854
+ categories,
23855
+ xAxis,
23856
+ yAxis,
23857
+ colors,
23858
+ stacked,
23859
+ legend,
23860
+ tooltip,
23861
+ dataLabels,
23862
+ height
23863
+ }),
23864
+ [
23865
+ chartConfig,
23866
+ chartType,
23867
+ title,
23868
+ subtitle,
23869
+ series,
23870
+ categories,
23871
+ xAxis,
23872
+ yAxis,
23873
+ colors,
23874
+ stacked,
23875
+ legend,
23876
+ tooltip,
23877
+ dataLabels,
23878
+ height
23879
+ ]
23880
+ );
23881
+ const builtConfig = (0, import_react96.useMemo)(() => {
23882
+ if (!declarative) return null;
23883
+ const palette = buildChartPalette(theme, mode);
23884
+ const options = buildChartOptions(declarative, palette);
23885
+ return extraOptions ? deepMerge(options, extraOptions) : options;
23886
+ }, [declarative, theme, mode, extraOptions]);
23523
23887
  (0, import_react96.useEffect)(() => {
23524
23888
  setMounted(true);
23525
23889
  }, []);
23526
23890
  (0, import_react96.useEffect)(() => {
23527
- if (!chartId || configProp) return;
23891
+ if (!chartId || configProp || builtConfig) return;
23528
23892
  let cancelled = false;
23529
23893
  setFetching(true);
23530
23894
  setFetchError(null);
@@ -23543,8 +23907,8 @@ function AnalyticsChart({
23543
23907
  return () => {
23544
23908
  cancelled = true;
23545
23909
  };
23546
- }, [chartId, apiBase, authToken, configProp]);
23547
- const activeConfig = configProp ?? fetchedConfig;
23910
+ }, [chartId, apiBase, authToken, configProp, builtConfig]);
23911
+ const activeConfig = configProp ?? builtConfig ?? fetchedConfig;
23548
23912
  (0, import_react96.useEffect)(() => {
23549
23913
  if (!mounted || !activeConfig || !containerRef.current) return;
23550
23914
  const container = containerRef.current;