@luxalgo/vela 0.8.0 → 0.8.2

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.
Files changed (49) hide show
  1. package/NOTICE +1 -1
  2. package/README.md +16 -8
  3. package/dist/{DataProvider-BrlxntPN.d.cts → DataProvider-COGDs9Xg.d.cts} +1 -1
  4. package/dist/{DataProvider-DwFIoV4r.d.ts → DataProvider-DpOWZD8F.d.ts} +1 -1
  5. package/dist/{chunk-KA77UTRF.js → chunk-27UTYE7T.js} +25 -2
  6. package/dist/{chunk-EZ5FWVLA.js → chunk-DPAA3SRT.js} +94 -13
  7. package/dist/{chunk-BZQM2XO7.js → chunk-HKNO24GD.js} +13 -1
  8. package/dist/{chunk-2IAETM2I.js → chunk-NLDTVFOI.js} +79 -6
  9. package/dist/{chunk-E3GU6AUI.js → chunk-R2JMNIHY.js} +68 -23
  10. package/dist/{chunk-QBPUT5SU.js → chunk-T3DZIR5Y.js} +211 -54
  11. package/dist/{contributions-tjNExo1o.d.ts → contributions-Cgm9RJYP.d.cts} +38 -11
  12. package/dist/{contributions-CtlptxR8.d.cts → contributions-bWgwyiVi.d.ts} +38 -11
  13. package/dist/index.cjs +317 -62
  14. package/dist/index.d.cts +8 -8
  15. package/dist/index.d.ts +8 -8
  16. package/dist/index.js +4 -4
  17. package/dist/{options-BnEPUuVV.d.ts → options-NAUHiQEC.d.cts} +3 -3
  18. package/dist/{options-BnEPUuVV.d.cts → options-NAUHiQEC.d.ts} +3 -3
  19. package/dist/{plugin-BWxJRKzS.d.cts → plugin-CjjzZX2F.d.cts} +4 -4
  20. package/dist/{plugin-e2WUEtiI.d.ts → plugin-CqxWoDKS.d.ts} +4 -4
  21. package/dist/plugin.cjs +20 -6
  22. package/dist/plugin.d.cts +5 -5
  23. package/dist/plugin.d.ts +5 -5
  24. package/dist/plugin.js +2 -2
  25. package/dist/providers/binance.d.cts +2 -2
  26. package/dist/providers/binance.d.ts +2 -2
  27. package/dist/providers/coinbase.d.cts +2 -2
  28. package/dist/providers/coinbase.d.ts +2 -2
  29. package/dist/providers/hyperliquid.d.cts +2 -2
  30. package/dist/providers/hyperliquid.d.ts +2 -2
  31. package/dist/{side-panel-HF0IAzwf.d.cts → side-panel-wMNfgyZb.d.cts} +13 -0
  32. package/dist/{side-panel-HF0IAzwf.d.ts → side-panel-wMNfgyZb.d.ts} +13 -0
  33. package/dist/{statusline-model-zKXtGIjj.d.ts → statusline-model-Dih6FGWP.d.ts} +3 -3
  34. package/dist/{statusline-model-DFY7tuHj.d.cts → statusline-model-Dpfpq54A.d.cts} +3 -3
  35. package/dist/ui.cjs +115 -5
  36. package/dist/ui.d.cts +28 -2
  37. package/dist/ui.d.ts +28 -2
  38. package/dist/ui.js +3 -3
  39. package/dist/vela.global.js +317 -62
  40. package/dist/vela.global.min.js +61 -68
  41. package/dist/widget.cjs +476 -85
  42. package/dist/widget.d.cts +20 -10
  43. package/dist/widget.d.ts +20 -10
  44. package/dist/widget.js +7 -7
  45. package/dist/workspace.cjs +476 -85
  46. package/dist/workspace.d.cts +6 -6
  47. package/dist/workspace.d.ts +6 -6
  48. package/dist/workspace.js +6 -6
  49. package/package.json +3 -3
@@ -1,6 +1,6 @@
1
- import { deserializeDrawing, chartTypes, rendererLayers, isLineLikeSeries, seriesShownOn, foldBaseModulation, registerChartType, rendererDefaults, getDrawingType, settingsRowVisible, normalizeSettingsRow, Magnifier, TextLabel, Callout, resetDrawingSettings, registerNativeIndicator, chartType, getNativeIndicator, nativeIndicatorDescriptors, nativeInstanceChannel, drawingTypes, settingsRowValueKeys, formatDuration, RegressionChannel, FixedRangeVolumeProfile, DEFAULT_DRAWING_COLOR, SegmentDrawing, ArrowMark, GlyphStamp, RadialFib, FibSpiral, DedekindTessellation, MachFigure, GannSquare, FibRatios, MeasureBox, PositionTool, AnchoredVwap, PatternDrawing, Comment, PriceNote, Signpost, Note, PriceLabel, GANN_SQUARE_ARCS, magnifierTimeframeLabel, lineSegmentIntersection, MAGNIFIER_TIMEFRAME_OPTIONS, GLYPH_OPTIONS, STAMP_SIZE_OPTIONS, LINE_STYLE_OPTIONS, DEDEKIND_CURVATURE_OPTIONS, MACH_NUMBER_OPTIONS, MACH_WAVE_COUNT_OPTIONS, TEXT_SIZE_OPTIONS, createDrawing, inputVisible, seriesInScale, tickerModifierIds, CalloutBase, DIRECTION_OPTIONS, stableSeriesId } from './chunk-EZ5FWVLA.js';
2
- import { themeTokens, Dialog, closeOpenPopovers, closeWidthPopover, fieldSection, buildFieldControl, fieldSeparator, fieldGrid, fieldRow, CALLOUT_STYLE_ID, CALLOUT_CSS, Popover, blendOver, splitColor, CalloutBubble, Menu, TextArea, NumberInput, buildColorPicker, isPopoverOpen, DatePicker, eventDismissedPopover, toggleSelectList, normalizeDateInput, openPopoverTrigger, fieldGridColumns, FIELD_GAP_PX, STATIC_TOKENS } from './chunk-2IAETM2I.js';
3
- import { icon, iconAt, withAlpha, WARNING, ACCENT, NEUTRAL, INFO, BULLISH, BEARISH, isDarkColor, injectStyles, SERIES_LINE, CHIP_PLATE, CROSSHAIR, TRADE_EXIT, TRADE_SHORT, TRADE_LONG, iconMarkup, overlayScrollbarCss, SLATE_DEEP, VALID, INVALID, SLATE, FIELD_FOCUS_CSS, FIELD_FOCUS_RING, svg24, svg24Solid } from './chunk-BZQM2XO7.js';
1
+ import { deserializeDrawing, chartTypes, rendererLayers, isLineLikeSeries, seriesShownOn, foldBaseModulation, registerChartType, rendererDefaults, getDrawingType, settingsRowVisible, normalizeSettingsRow, Magnifier, TextLabel, Callout, resetDrawingSettings, registerNativeIndicator, chartType, getNativeIndicator, nativeIndicatorDescriptors, nativeInstanceChannel, drawingTypes, settingsRowValueKeys, formatDuration, RegressionChannel, FixedRangeVolumeProfile, DEFAULT_DRAWING_COLOR, SegmentDrawing, ArrowMark, GlyphStamp, RadialFib, FibSpiral, DedekindTessellation, MachFigure, GannSquare, FibRatios, MeasureBox, PositionTool, AnchoredVwap, PatternDrawing, Comment, PriceNote, Signpost, Note, PriceLabel, GANN_SQUARE_ARCS, magnifierTimeframeLabel, lineSegmentIntersection, MAGNIFIER_TIMEFRAME_OPTIONS, GLYPH_OPTIONS, STAMP_SIZE_OPTIONS, LINE_STYLE_OPTIONS, DEDEKIND_CURVATURE_OPTIONS, MACH_NUMBER_OPTIONS, MACH_WAVE_COUNT_OPTIONS, TEXT_SIZE_OPTIONS, createDrawing, inputVisible, seriesInScale, tickerModifierIds, CalloutBase, DIRECTION_OPTIONS, FibRetracement, stableSeriesId } from './chunk-DPAA3SRT.js';
2
+ import { themeTokens, Dialog, closeOpenPopovers, closeWidthPopover, fieldSection, buildFieldControl, fieldSeparator, fieldGrid, fieldRow, CALLOUT_STYLE_ID, CALLOUT_CSS, Popover, blendOver, splitColor, CalloutBubble, Menu, TextArea, NumberInput, buildColorPicker, isPopoverOpen, DatePicker, eventDismissedPopover, toggleSelectList, normalizeDateInput, openPopoverTrigger, fieldGridColumns, FIELD_GAP_PX, STATIC_TOKENS } from './chunk-NLDTVFOI.js';
3
+ import { icon, iconAt, withAlpha, WARNING, ACCENT, NEUTRAL, INFO, BULLISH, BEARISH, announceSurface, isDarkColor, injectStyles, SERIES_LINE, CHIP_PLATE, CROSSHAIR, TRADE_EXIT, TRADE_SHORT, TRADE_LONG, iconMarkup, overlayScrollbarCss, SLATE_DEEP, VALID, INVALID, SLATE, FIELD_FOCUS_CSS, FIELD_FOCUS_RING, svg24, svg24Solid } from './chunk-HKNO24GD.js';
4
4
 
5
5
  // src/core/events/EventBus.ts
6
6
  var TypedEventBus = class {
@@ -3013,6 +3013,7 @@ var DrawingToolbar = class {
3013
3013
  );
3014
3014
  }
3015
3015
  }
3016
+ announceSurface(fly, true, "menu", cell);
3016
3017
  }
3017
3018
  openMagnetFlyout() {
3018
3019
  const cell = this.magnetCell;
@@ -3036,6 +3037,7 @@ var DrawingToolbar = class {
3036
3037
  })
3037
3038
  );
3038
3039
  }
3040
+ announceSurface(fly, true, "menu", cell);
3039
3041
  }
3040
3042
  flyoutHeader(text) {
3041
3043
  const t = this.theme;
@@ -3104,9 +3106,11 @@ var DrawingToolbar = class {
3104
3106
  }
3105
3107
  closeFlyout() {
3106
3108
  this.starEls.clear();
3107
- if (this.flyout) {
3108
- this.flyout.remove();
3109
+ const fly = this.flyout;
3110
+ if (fly) {
3109
3111
  this.flyout = null;
3112
+ announceSurface(fly, false, "menu", this.flyoutCell);
3113
+ fly.remove();
3110
3114
  this.flyoutCell?.classList.remove("vela-open");
3111
3115
  this.flyoutCell = null;
3112
3116
  this.flyoutOwnerId = null;
@@ -5791,15 +5795,23 @@ var Batch = class {
5791
5795
  this.seg(x + w, y + h, x, y + h, lineWidth, c);
5792
5796
  this.seg(x, y + h, x, y, lineWidth, c);
5793
5797
  }
5794
- /** Filled circle (triangle fan). */
5798
+ /**
5799
+ * Filled circle (triangle fan), feathered like a line: the rim is padded by {@link AA_PAD} and
5800
+ * edgeDist runs from 0 at the center to the padded radius at the rim, with edgeHalf = r. The
5801
+ * distance grows linearly along each spoke, so the shader's line feather gives a round soft edge.
5802
+ */
5795
5803
  circle(cx, cy, r, c, segments = 16) {
5796
- let px = cx + r;
5804
+ const ext = r + AA_PAD;
5805
+ let px = cx + ext;
5797
5806
  let py = cy;
5807
+ this.ensure(segments * 3);
5798
5808
  for (let i = 1; i <= segments; i += 1) {
5799
5809
  const a = i / segments * Math.PI * 2;
5800
- const nx = cx + Math.cos(a) * r;
5801
- const ny = cy + Math.sin(a) * r;
5802
- this.tri(cx, cy, c, px, py, c, nx, ny, c);
5810
+ const nx = cx + Math.cos(a) * ext;
5811
+ const ny = cy + Math.sin(a) * ext;
5812
+ this.v(cx, cy, c, 0, r);
5813
+ this.v(px, py, c, ext, r);
5814
+ this.v(nx, ny, c, ext, r);
5803
5815
  px = nx;
5804
5816
  py = ny;
5805
5817
  }
@@ -5980,7 +5992,7 @@ var WebGL2Backend = class {
5980
5992
  }
5981
5993
  mount(canvas) {
5982
5994
  this.canvas = canvas;
5983
- this.gl = canvas.getContext("webgl2", { alpha: true, antialias: true, depth: false, stencil: false, premultipliedAlpha: true });
5995
+ this.gl = canvas.getContext("webgl2", { alpha: true, antialias: false, depth: false, stencil: false, premultipliedAlpha: true });
5984
5996
  if (!this.gl) return;
5985
5997
  if (!this.initGL()) {
5986
5998
  this.gl = null;
@@ -7239,6 +7251,12 @@ var InputController = class {
7239
7251
  this.lastTapT = 0;
7240
7252
  this.lastTapX = 0;
7241
7253
  this.lastTapY = 0;
7254
+ // Whether the last two primary presses were claimed by the drawings layer. A double-click
7255
+ // is the last press plus the one before it; a tool-driven click pair must never fall through
7256
+ // to the pane maximize toggle, even when the tool disarmed itself between the two clicks
7257
+ // (a finished placement leaves plain cursor mode for the second click).
7258
+ this.lastPressDrawing = false;
7259
+ this.prevPressDrawing = false;
7242
7260
  this.onTouchContextMenu = (e) => {
7243
7261
  if (this.touches.size === 0) return;
7244
7262
  if (!(e.target instanceof Node) || !this.el?.contains(e.target)) return;
@@ -7293,19 +7311,24 @@ var InputController = class {
7293
7311
  this.moved = false;
7294
7312
  this.startX = x;
7295
7313
  this.startY = y;
7314
+ this.prevPressDrawing = this.lastPressDrawing;
7315
+ this.lastPressDrawing = false;
7296
7316
  if (this.deps.drawingsClaim?.(x, y)) {
7297
7317
  this.region = "drawing";
7318
+ this.lastPressDrawing = true;
7298
7319
  this.deps.drawingsPointerDown?.(x, y, this.snapMode(e), e.shiftKey, e.ctrlKey || e.metaKey);
7299
7320
  this.capture(e.pointerId);
7300
7321
  return;
7301
7322
  }
7302
7323
  if (e.shiftKey && this.regionAt(x, y) === "data" && this.deps.drawingsMeasureStart?.(x, y, this.snapMode(e))) {
7303
7324
  this.region = "drawing";
7325
+ this.lastPressDrawing = true;
7304
7326
  this.capture(e.pointerId);
7305
7327
  return;
7306
7328
  }
7307
7329
  if ((e.ctrlKey || e.metaKey) && this.regionAt(x, y) === "data" && this.deps.drawingsMarqueeStart?.(x, y)) {
7308
7330
  this.region = "drawing";
7331
+ this.lastPressDrawing = true;
7309
7332
  this.capture(e.pointerId);
7310
7333
  return;
7311
7334
  }
@@ -7421,7 +7444,7 @@ var InputController = class {
7421
7444
  this.deps.drawingsPointerUp?.(x, y, this.snapMode(e));
7422
7445
  } else if (tapRelease && this.region === "data") {
7423
7446
  this.deps.onClick(x, y);
7424
- } else if (this.dragging && this.region === "data") {
7447
+ } else if (this.dragging && this.region === "data" && wasTouch) {
7425
7448
  const stale = e.timeStamp - this.lastT > FLING_STALE_MS;
7426
7449
  if (!stale && Math.abs(this.vx) > FLING_MIN_SPEED) {
7427
7450
  const pitch = this.deps.getCoords().pxPerBar();
@@ -7627,6 +7650,7 @@ var InputController = class {
7627
7650
  if (region === "price") this.deps.resetPriceScale(x, y);
7628
7651
  else if (region === "separator") this.deps.resetPaneSize(y);
7629
7652
  else if (region === "time") this.deps.resetView();
7653
+ else if (this.lastPressDrawing || this.prevPressDrawing) return;
7630
7654
  else this.deps.dataDblClick(x, y);
7631
7655
  }
7632
7656
  };
@@ -9828,6 +9852,7 @@ function timeTicks(fromMs, toMs, target = 8, offsetMs = 0) {
9828
9852
  const step = pickStep(span / Math.max(1, target));
9829
9853
  const zFrom = fromMs + offsetMs;
9830
9854
  const zTo = toMs + offsetMs;
9855
+ if (step >= MONTH) return calendarTicks(zFrom, zTo, step >= YEAR ? 12 : step >= 3 * MONTH ? 3 : 1, offsetMs);
9831
9856
  const first = Math.ceil(zFrom / step) * step;
9832
9857
  const out = [];
9833
9858
  for (let zt = first; zt <= zTo; zt += step) {
@@ -9858,6 +9883,18 @@ function timeTicks(fromMs, toMs, target = 8, offsetMs = 0) {
9858
9883
  }
9859
9884
  return out;
9860
9885
  }
9886
+ function calendarTicks(zFrom, zTo, months, offsetMs) {
9887
+ const d0 = new Date(zFrom);
9888
+ let idx = d0.getUTCFullYear() * 12 + d0.getUTCMonth();
9889
+ if (Date.UTC(Math.floor(idx / 12), idx % 12, 1) < zFrom) idx += 1;
9890
+ idx = Math.ceil(idx / months) * months;
9891
+ const out = [];
9892
+ for (let zt = Date.UTC(Math.floor(idx / 12), idx % 12, 1); zt <= zTo; idx += months, zt = Date.UTC(Math.floor(idx / 12), idx % 12, 1)) {
9893
+ const label = months === 12 ? String(Math.floor(idx / 12)) : MONTHS[idx % 12];
9894
+ out.push({ time: zt - offsetMs, label, major: true });
9895
+ }
9896
+ return out;
9897
+ }
9861
9898
 
9862
9899
  // src/renderers/native/chrome/countdown.ts
9863
9900
  function countdownText(barOpen, barMs, now2) {
@@ -13821,6 +13858,12 @@ var DrawingInteraction = class {
13821
13858
  activeDragId() {
13822
13859
  return this.state.kind === "pressed" && this.state.moved ? this.state.id : null;
13823
13860
  }
13861
+ /** The store drawings a live drag is moving — the pressed one and its riders — or none
13862
+ * before the drag passes the slop. A Ctrl-drag moves copies, so its sources stay put. */
13863
+ movingIds() {
13864
+ if (this.state.kind !== "pressed" || !this.state.moved || this.state.clones) return /* @__PURE__ */ new Set();
13865
+ return /* @__PURE__ */ new Set([this.state.id, ...this.state.riders.map((r) => r.id)]);
13866
+ }
13824
13867
  /** The drawing under a press that has not been released yet (drag or click undecided), or null. */
13825
13868
  pressedId() {
13826
13869
  return this.state.kind === "pressed" ? this.state.id : null;
@@ -14479,6 +14522,17 @@ var DrawingSettingsDialog = class {
14479
14522
  }
14480
14523
  }));
14481
14524
  }
14525
+ if (drawing instanceof FibRetracement) {
14526
+ const fib = drawing;
14527
+ grid.appendChild(fieldRow({
14528
+ label: "Reverse",
14529
+ bool: true,
14530
+ toggle: {
14531
+ checked: fib.reverse,
14532
+ onChange: (v) => actions.patch({ reverse: v })
14533
+ }
14534
+ }));
14535
+ }
14482
14536
  levels.forEach((lv, i) => {
14483
14537
  const row = document.createElement("div");
14484
14538
  row.className = "vela-field-span";
@@ -15632,6 +15686,8 @@ var UserDrawingController = class {
15632
15686
  this.drawings = [];
15633
15687
  /** Ids painted on an interleave layer this frame — the top canvas paints only their handles. */
15634
15688
  this.sliced = /* @__PURE__ */ new Set();
15689
+ /** Interleaved drawings mid-drag: painted on the top canvas, left out of their slice. */
15690
+ this.lifted = /* @__PURE__ */ new Set();
15635
15691
  /** Cached slice canvases, keyed `paneId|beforeZ`, reused across frames to avoid churn. */
15636
15692
  this.sliceCache = /* @__PURE__ */ new Map();
15637
15693
  /** Series boundaries per pane as of the last `prepareSlices` — lets a repaint between data
@@ -15719,7 +15775,7 @@ var UserDrawingController = class {
15719
15775
  selectedIds: () => this.selectedIds,
15720
15776
  emit: (i) => this.emit(i),
15721
15777
  changed: () => {
15722
- this.invalidateSlices();
15778
+ this.syncLift();
15723
15779
  this.render();
15724
15780
  },
15725
15781
  openSettings: (id, x, y) => this.openSettingsById(id, x, y),
@@ -16345,6 +16401,20 @@ var UserDrawingController = class {
16345
16401
  /** A drawing that paints inside the series stack changed (content, not hover): its pixels
16346
16402
  * live in the backend composite, so this layer alone can't show the change — ask for a
16347
16403
  * data frame, which re-runs `prepareSlices` before the backend composites. */
16404
+ /** A drawing being dragged leaves its interleave slice for the top canvas, so each pointer
16405
+ * move repaints one 2D layer instead of re-rasterizing and re-uploading a plot-sized slice
16406
+ * texture through the data frame. The slices rebuild once as the drag starts and once as it
16407
+ * ends (release, cancel), when the lifted set changes. */
16408
+ syncLift() {
16409
+ const moving = this.interaction.movingIds();
16410
+ let same = moving.size === this.lifted.size;
16411
+ if (same) {
16412
+ for (const id of moving) if (!this.lifted.has(id)) same = false;
16413
+ }
16414
+ if (same) return;
16415
+ this.lifted = new Set(moving);
16416
+ this.invalidateSlices();
16417
+ }
16348
16418
  invalidateSlices() {
16349
16419
  if (this.sliced.size > 0 || this.drawings.some((d) => this.isInterleaved(d))) this.deps.requestDataPaint();
16350
16420
  }
@@ -16363,7 +16433,7 @@ var UserDrawingController = class {
16363
16433
  const theme = this.deps.theme();
16364
16434
  const buckets = /* @__PURE__ */ new Map();
16365
16435
  for (const d of this.drawings) {
16366
- if (!d.visible) continue;
16436
+ if (!d.visible || this.lifted.has(d.id)) continue;
16367
16437
  const beforeZ = sliceKeyFor(d.zIndex, this.lastBounds.get(d.paneId) ?? []);
16368
16438
  if (beforeZ === null) continue;
16369
16439
  const key = `${d.paneId}|${beforeZ}`;
@@ -16415,8 +16485,9 @@ var UserDrawingController = class {
16415
16485
  mutedLabel: edited instanceof TextLabel ? edited.id : null
16416
16486
  };
16417
16487
  this.painter.seriesLook = this.deps.seriesLook();
16418
- this.painter.paintAll(ctx, this.drawings.filter((d) => !this.isInterleaved(d)), proj, this.deps.theme(), targets);
16419
- this.painter.paintHighlights(ctx, this.drawings.filter((d) => this.isInterleaved(d)), proj, handleIdsFor(targets));
16488
+ const onTop = (d) => !this.isInterleaved(d) || this.lifted.has(d.id);
16489
+ this.painter.paintAll(ctx, this.drawings.filter(onTop), proj, this.deps.theme(), targets);
16490
+ this.painter.paintHighlights(ctx, this.drawings.filter((d) => !onTop(d)), proj, handleIdsFor(targets));
16420
16491
  const clones = this.interaction.dragClones();
16421
16492
  if (clones) this.painter.paintAll(ctx, clones, proj, this.deps.theme(), { selected: new Set(clones.map((c) => c.id)) });
16422
16493
  this.layoutTextEditor();
@@ -17667,23 +17738,21 @@ function stackLayers(entries, candleZ) {
17667
17738
  return { below, above };
17668
17739
  }
17669
17740
 
17670
- // src/renderers/native/chrome/luxalgo-logos.ts
17671
- var LUXALGO_SYMBOL_SVG = '<svg viewBox="0 0 45 40" aria-hidden="true"><g fill="currentColor"><path d="m40.25 38 4.58-7.998L28.802 2l-16.03 28 9.16-.001 6.87-12z"/><path d="M34.525 32.002 9.33 31.997 27.655 0h-9.158L.18 31.993 4.759 40h34.347z"/></g></svg>';
17672
- var LUXALGO_WORDMARK_SVG = '<svg viewBox="0 0 964 252" aria-hidden="true"><path fill="currentColor" fill-rule="evenodd" d="M 614 94.500 L 614 189 633.500 189 L 653 189 653 94.500 L 653 0 633.500 0 L 614 0 614 94.500 M 0 97.500 L 0 189 63.023 189 L 126.045 189 125.773 170.750 L 125.500 152.500 84.250 152.239 L 43 151.978 43 78.989 L 43 6 21.500 6 L 0 6 0 97.500 M 450.387 96.451 C 421.871 146.253, 398.306 186.994, 398.020 186.987 C 397.423 186.972, 362 124.724, 362 123.691 C 362 123.316, 370.100 108.818, 380 91.472 C 389.900 74.127, 398 59.500, 398 58.968 C 398 58.380, 391.007 58, 380.210 58 L 362.420 58 348.060 83.138 C 334.400 107.052, 333.637 108.160, 332.399 105.888 C 331.682 104.575, 325.287 93.375, 318.187 81 L 305.277 58.500 287.139 58.227 C 277.162 58.078, 269 58.186, 269 58.469 C 269 58.751, 277.154 73.274, 287.120 90.741 C 297.086 108.209, 305.261 122.983, 305.287 123.574 C 305.312 124.164, 297.318 138.789, 287.522 156.074 C 277.725 173.358, 269.524 187.838, 269.296 188.250 C 269.068 188.662, 276.977 189, 286.870 189 L 304.859 189 319.163 163.959 C 331.321 142.674, 333.647 139.165, 334.670 140.563 C 335.331 141.468, 341.864 152.737, 349.186 165.606 L 362.500 189.003 402.442 188.752 L 442.384 188.500 472.080 136.695 C 488.413 108.203, 501.939 84.729, 502.138 84.531 C 502.337 84.333, 516 107.757, 532.500 136.583 L 562.500 188.994 584.750 188.997 C 596.987 188.999, 607 188.854, 607 188.675 C 607 188.319, 503.014 6.686, 502.532 6.201 C 502.369 6.037, 478.904 46.649, 450.387 96.451 M 717.500 55.017 C 697.175 57.389, 680.641 68.752, 672.036 86.264 C 665.866 98.818, 663.840 108.024, 663.840 123.500 C 663.840 133.409, 664.328 138.355, 665.892 144.300 C 672.076 167.810, 689.191 184.757, 711.529 189.489 C 730.549 193.518, 747.264 189.540, 761.282 177.648 C 764.944 174.542, 768.178 172, 768.470 172 C 769.345 172, 769.030 185.018, 767.979 192.285 C 765.618 208.613, 755.148 218.672, 738.473 220.632 C 732.586 221.324, 723.136 219.599, 717.709 216.843 C 712.693 214.295, 706.636 207.946, 703.972 202.443 C 702.789 199.999, 701.749 198, 701.661 198.001 C 700.201 198.007, 665.596 205.071, 665.230 205.437 C 664.326 206.341, 669.156 218.313, 672.607 223.721 C 682.146 238.672, 700.008 248.257, 723.500 251.033 C 758.132 255.124, 788.930 241.875, 800.287 218 C 806.923 204.047, 807 203.001, 807 126.542 L 807 58 788.500 58 L 770 58 770 66.500 C 770 71.175, 769.641 75, 769.203 75 C 768.765 75, 766.627 73.142, 764.453 70.872 C 752.805 58.708, 735.614 52.903, 717.500 55.017 M 878.500 55.031 C 850.107 59.412, 830.755 75.064, 822.285 100.500 C 819.905 107.644, 819.614 110.051, 819.565 123 C 819.501 139.581, 820.786 145.825, 826.763 158 C 832.104 168.880, 842.842 179.424, 854.077 184.822 C 867.651 191.343, 873.132 192.462, 891.500 192.462 C 909.868 192.462, 915.349 191.343, 928.923 184.822 C 944.653 177.265, 956.667 162.306, 961.710 144 C 963.074 139.048, 963.481 134.047, 963.418 123 C 963.346 110.140, 963.038 107.595, 960.694 100.500 C 953.325 78.193, 936.695 62.854, 913.500 56.969 C 904.262 54.625, 887.240 53.682, 878.500 55.031 M 134.015 102.750 C 134.027 139.250, 134.310 148.689, 135.549 153.947 C 141.139 177.663, 159.815 193, 183.105 193 C 196.453 193, 210.163 186.171, 217.936 175.650 C 219.826 173.093, 221.738 171, 222.186 171 C 222.634 171, 223 175.050, 223 180 L 223 189 242.507 189 L 262.014 189 261.757 123.750 L 261.500 58.500 242.500 58.500 L 223.500 58.500 223 99.500 C 222.513 139.406, 222.441 140.610, 220.289 144.634 C 209.729 164.377, 183.014 164.880, 174.299 145.500 C 172.677 141.895, 172.469 137.382, 172.190 99.750 L 171.880 58 152.940 58 L 134 58 134.015 102.750 M 729.932 87.998 C 719.311 89.821, 710.155 97.164, 705.141 107.880 C 702.851 112.772, 702.510 114.798, 702.505 123.521 C 702.500 132.834, 702.732 134.014, 705.787 140.218 C 709.761 148.290, 715.989 154.097, 723.853 157.063 C 731.409 159.912, 744.359 159.466, 750.795 156.136 C 767.289 147.601, 774.103 127.713, 767.019 108.780 C 761.433 93.851, 746.051 85.232, 729.932 87.998 M 883.972 88.348 C 865.749 92.310, 854.873 109.966, 858.119 130.316 C 860.933 147.963, 872.346 158.830, 889.084 159.799 C 900.714 160.472, 906.867 158.234, 914.650 150.497 C 919.856 145.323, 921.123 143.340, 922.900 137.587 C 925.412 129.456, 925.655 118.570, 923.489 111.275 C 918.479 94.405, 901.478 84.541, 883.972 88.348"/></svg>';
17741
+ // src/renderers/native/chrome/vela-logos.ts
17742
+ var VELA_MARK_SVG = '<svg viewBox="0 -142 161.66 148" aria-hidden="true"><g fill="currentColor"><path d="M0 -140L32.91 -140L77.52 -62.73L61.06 -34.24Z"/><path d="M161.66 -140L128.75 -140L84.14 -62.73L100.59 -34.24Z"/><path d="M80.83 -52.04L95.85 -26.02L80.83 0L65.81 -26.02Z"/></g></svg>';
17743
+ var VELA_LETTERS_SVG = '<svg viewBox="161.66 -142 310.57 148" aria-hidden="true"><g fill="currentColor"><path d="M226.3 1.17Q200.81 1.17 186.12 -12.99Q171.42 -27.15 171.42 -51.17Q171.42 -75.2 185.87 -89.6Q200.33 -104 224.25 -104Q247.4 -104 261.7 -90.58Q276.01 -77.15 276.3 -54.59Q276.3 -49.9 275.42 -45.02H200.81V-43.55Q201.2 -32.62 207.75 -26.42Q214.29 -20.21 225.03 -20.21Q233.72 -20.21 239.34 -23.93Q244.95 -27.64 246.81 -34.77H274.64Q272.1 -19.14 259.16 -8.98Q246.22 1.17 226.3 1.17ZM201.5 -63.38H247.88Q246.42 -72.75 240.27 -77.88Q234.12 -83.01 224.45 -83.01Q215.17 -83.01 208.92 -77.73Q202.67 -72.46 201.5 -63.38ZM287.54 0V-140.04H315.76V0ZM429.34 -23.83H432.56V0H418.11Q407.76 0 403.36 -4.44Q398.97 -8.89 399.16 -16.8Q387.83 1.17 365.57 1.17Q348.48 1.17 337.88 -6.74Q327.29 -14.65 327.29 -29Q327.29 -45.41 339.45 -54.3Q351.6 -63.18 374.55 -63.18H394.96V-68.16Q394.96 -75.2 390.08 -79.3Q385.2 -83.4 376.51 -83.4Q368.3 -83.4 363.03 -79.98Q357.76 -76.56 356.88 -70.8H329.73Q331.19 -85.84 344.08 -94.92Q356.97 -104 377.29 -104Q399.06 -104 410.88 -94.43Q422.7 -84.86 422.7 -66.6V-30.18Q422.7 -26.37 424.26 -25.1Q425.82 -23.83 429.34 -23.83ZM394.96 -42.38V-44.43H374.36Q365.47 -44.43 360.59 -40.92Q355.7 -37.4 355.7 -30.96Q355.7 -25.59 359.81 -22.41Q363.91 -19.24 370.94 -19.24Q381.97 -19.24 388.37 -25.54Q394.77 -31.84 394.96 -42.38Z"/><path fill-opacity="0.55" d="M437.44 -124.28H441.96V-113.41H445.34V-124.28H449.87V-127.4H437.44ZM451.43 -113.41H454.7V-123.29L458.97 -113.41H461.62L465.99 -123.29V-113.41H469.21V-127.4H464.53L460.42 -117.68L456.16 -127.4H451.43Z"/></g></svg>';
17673
17744
 
17674
17745
  // src/renderers/native/chrome/AttributionMark.ts
17675
- var ATTRIBUTION_URL = "https://luxalgo.com/vela";
17746
+ var ATTRIBUTION_URL = "https://velacharts.dev/?utm_source=vela&utm_medium=attribution";
17676
17747
  var STYLE_ID5 = "vela-attribution-styles";
17677
17748
  var CSS = `
17678
17749
  .vela-attribution {
17679
17750
  text-decoration: none;
17680
17751
  display: flex;
17681
17752
  align-items: center;
17682
- /* Gutter, wordmark size and offset below are the brand lockup's own ratios,
17683
- measured off the official horizontal logo: gutter 0.157, wordmark height
17684
- 0.966, and wordmark 0.109 LOWER than the symbol \u2014 box-centering the two
17685
- reads wrong because the symbol's ink hangs low and the wordmark descends. */
17686
- gap: 4px;
17753
+ /* No gutter: the V is the wordmark's first letter, and the letters' viewBox starts
17754
+ where the V's ends, so the kit's own letter spacing comes with them. */
17755
+ gap: 0;
17687
17756
  }
17688
17757
  .vela-attribution .vela-attr-symbol {
17689
17758
  flex: none;
@@ -17691,7 +17760,7 @@ var CSS = `
17691
17760
  line-height: 0;
17692
17761
  }
17693
17762
  .vela-attribution .vela-attr-symbol svg {
17694
- height: 28px;
17763
+ height: 24px;
17695
17764
  width: auto;
17696
17765
  display: block;
17697
17766
  filter: drop-shadow(0 1px 2px var(--vela-attr-shadow, rgba(0,0,0,0.45)));
@@ -17702,15 +17771,13 @@ var CSS = `
17702
17771
  opacity: 0;
17703
17772
  display: flex;
17704
17773
  align-items: center;
17705
- /* Offset here, not on the image: the clip box must not crop the descender. */
17706
- position: relative;
17707
- top: 3px;
17774
+ /* Same height and baseline as the V (one viewBox height), so no vertical offset. */
17708
17775
  transform: translateX(-8px);
17709
17776
  transition: max-width 0.3s ease, opacity 0.25s ease, transform 0.3s ease;
17710
17777
  flex: none;
17711
17778
  }
17712
17779
  .vela-attribution .vela-attr-wordmark svg {
17713
- height: 27px;
17780
+ height: 24px;
17714
17781
  width: auto;
17715
17782
  display: block;
17716
17783
  filter: drop-shadow(0 1px 2px var(--vela-attr-shadow, rgba(0,0,0,0.45)));
@@ -17725,14 +17792,11 @@ var CSS = `
17725
17792
  (data-layout): the workspace's single grid-wide mark lives OUTSIDE any renderer
17726
17793
  container, so only the shell attribute reaches it. */
17727
17794
  [data-vela-layout='mobile'] .vela-attribution .vela-attr-symbol svg,
17728
- [data-layout='mobile'] .vela-attribution .vela-attr-symbol svg { height: 22px; }
17795
+ [data-layout='mobile'] .vela-attribution .vela-attr-symbol svg { height: 20px; }
17729
17796
  [data-vela-layout='mobile'] .vela-attribution .vela-attr-wordmark,
17730
- [data-layout='mobile'] .vela-attribution .vela-attr-wordmark {
17731
- top: 2px;
17732
- transform: translateX(-6px);
17733
- }
17797
+ [data-layout='mobile'] .vela-attribution .vela-attr-wordmark { transform: translateX(-6px); }
17734
17798
  [data-vela-layout='mobile'] .vela-attribution .vela-attr-wordmark svg,
17735
- [data-layout='mobile'] .vela-attribution .vela-attr-wordmark svg { height: 21px; }
17799
+ [data-layout='mobile'] .vela-attribution .vela-attr-wordmark svg { height: 20px; }
17736
17800
  [data-vela-layout='mobile'] .vela-attribution:hover .vela-attr-wordmark,
17737
17801
  [data-layout='mobile'] .vela-attribution:hover .vela-attr-wordmark { transform: translateX(0); }
17738
17802
  `;
@@ -17789,10 +17853,10 @@ function createAttributionMark(doc, background) {
17789
17853
  const symbol = doc.createElement("span");
17790
17854
  symbol.className = "vela-attr-symbol";
17791
17855
  symbol.setAttribute("aria-hidden", "true");
17792
- symbol.innerHTML = LUXALGO_SYMBOL_SVG;
17856
+ symbol.innerHTML = VELA_MARK_SVG;
17793
17857
  const wordmark = doc.createElement("span");
17794
17858
  wordmark.className = "vela-attr-wordmark";
17795
- wordmark.innerHTML = LUXALGO_WORDMARK_SVG;
17859
+ wordmark.innerHTML = VELA_LETTERS_SVG;
17796
17860
  a.append(symbol, wordmark);
17797
17861
  return a;
17798
17862
  }
@@ -21886,7 +21950,7 @@ var IndicatorHandleImpl = class {
21886
21950
  this.controller.applyProps(this.id, values);
21887
21951
  }
21888
21952
  updateCode(source) {
21889
- this.controller.updateCode(this.id, source);
21953
+ return this.controller.updateCode(this.id, source);
21890
21954
  }
21891
21955
  setVisible(visible) {
21892
21956
  this.controller.setVisible(this.id, visible);
@@ -23701,20 +23765,26 @@ var EngineOrchestrator = class _EngineOrchestrator {
23701
23765
  /**
23702
23766
  * IndicatorController: replace a SCRIPT indicator's source in place (see
23703
23767
  * {@link IndicatorHandle.updateCode}). Prepare-first: the running session keeps
23704
- * computing until the new source has compiled, so a broken edit costs the user
23705
- * nothing but an `error` event. Natives have no script — warn and leave them alone.
23768
+ * computing until the new source has compiled; then the new code runs on TRIAL until
23769
+ * its first model lands, and a failure before that puts the previous code back.
23770
+ * Natives have no script — warn and leave them alone.
23706
23771
  */
23707
23772
  updateCode(id, source) {
23708
23773
  const record = this.registry.get(id);
23709
23774
  const handle = this.handles.get(id);
23710
- if (!record || !handle) return;
23775
+ if (!record || !handle) return Promise.resolve({ ok: false, error: new Error(`[vela] updateCode("${id}") \u2014 the indicator is no longer on the chart.`) });
23711
23776
  if (record.native) {
23712
23777
  console.warn(`[vela] updateCode("${id}") \u2014 a native indicator has no script to update.`);
23713
- return;
23778
+ return Promise.resolve({ ok: false, error: new Error(`[vela] updateCode("${id}") \u2014 a native indicator has no script to update.`) });
23714
23779
  }
23715
- if (source === record.source && record.pendingSource === void 0) return;
23716
- record.pendingSource = source;
23717
- void this.swapSource(id, source, handle);
23780
+ const busy = record.pendingSource !== void 0 || record.codeTrial !== void 0;
23781
+ if (!busy && source === record.source) return Promise.resolve({ ok: true, error: null });
23782
+ return new Promise((resolve) => {
23783
+ (record.codeWaiters ?? (record.codeWaiters = [])).push(resolve);
23784
+ if (record.pendingSource === source || record.pendingSource === void 0 && record.codeTrial && record.source === source) return;
23785
+ record.pendingSource = source;
23786
+ void this.swapSource(id, source, handle);
23787
+ });
23718
23788
  }
23719
23789
  async swapSource(id, source, handle) {
23720
23790
  const engine = this.registry.get(id)?.engine ?? this.engineFor(this.registry.get(id)?.options?.language);
@@ -23725,26 +23795,41 @@ var EngineOrchestrator = class _EngineOrchestrator {
23725
23795
  const record2 = this.registry.get(id);
23726
23796
  if (record2?.pendingSource === source) {
23727
23797
  record2.pendingSource = void 0;
23728
- this.fail(id, handle, err);
23798
+ this.rejectCode(id, record2, handle, err);
23729
23799
  }
23730
23800
  return;
23731
23801
  }
23732
23802
  const record = this.registry.get(id);
23733
23803
  if (!record || record.pendingSource !== source) return;
23734
23804
  record.pendingSource = void 0;
23805
+ const previous = record.codeTrial?.previous ?? {
23806
+ source: record.source,
23807
+ engine: record.engine,
23808
+ prepared: record.prepared,
23809
+ inputValues: record.inputValues,
23810
+ propValues: record.propValues,
23811
+ inputs: [...handle.inputs],
23812
+ props: [...handle.props]
23813
+ };
23814
+ record.inputValues = valuesOnSchema(prepared.inputs, record.inputValues, record.prepared?.inputs);
23815
+ record.propValues = valuesOnSchema(prepared.props ?? [], record.propValues, record.prepared?.props);
23735
23816
  record.source = source;
23736
23817
  record.engine = engine;
23737
23818
  record.prepared = prepared;
23738
23819
  handle.setSource(source);
23739
- record.inputValues = valuesOnSchema(prepared.inputs, record.inputValues);
23740
- record.propValues = valuesOnSchema(prepared.props ?? [], record.propValues);
23741
23820
  handle.setSchema(prepared.inputs);
23742
23821
  handle.setPropsSchema(prepared.props ?? []);
23743
23822
  record.session?.stop();
23744
23823
  record.session = void 0;
23745
23824
  record.pendingStructural = true;
23746
23825
  record.pendingCause = "code";
23747
- if (record.hidden) return;
23826
+ if (record.hidden) {
23827
+ record.codeTrial = void 0;
23828
+ if (record.renderHandle) this.renderer.setIndicatorInputs(record.renderHandle, record.inputValues, record.propValues);
23829
+ this.settleCode(record, { ok: true, error: null });
23830
+ return;
23831
+ }
23832
+ record.codeTrial = { previous };
23748
23833
  if (record.renderHandle) {
23749
23834
  this.renderer.setIndicatorInputs(record.renderHandle, record.inputValues, record.propValues);
23750
23835
  this.setLoading(record, true);
@@ -23752,6 +23837,46 @@ var EngineOrchestrator = class _EngineOrchestrator {
23752
23837
  this.mountLoadingPlaceholder(id, record);
23753
23838
  }
23754
23839
  this.executeIndicator(id, handle);
23840
+ if (this.bars.length === 0 && record.codeTrial) {
23841
+ record.codeTrial = void 0;
23842
+ this.settleCode(record, { ok: true, error: null });
23843
+ }
23844
+ }
23845
+ /** Resolve every `updateCode` caller waiting on this record's chain of edits. */
23846
+ settleCode(record, result) {
23847
+ const waiters = record.codeWaiters;
23848
+ record.codeWaiters = void 0;
23849
+ if (waiters) for (const resolve of waiters) resolve(result);
23850
+ }
23851
+ /**
23852
+ * An update failed — at prepare, or on trial before its first model. A trial puts the
23853
+ * previous code back (source, engine, prepared script, values, schema) and restarts it;
23854
+ * its visuals were never dropped, so the chart keeps painting throughout. Then the
23855
+ * failure reports the usual way and every waiting caller learns it.
23856
+ */
23857
+ rejectCode(id, record, handle, err) {
23858
+ const trial = record.codeTrial;
23859
+ record.codeTrial = void 0;
23860
+ this.fail(id, handle, err);
23861
+ if (trial) {
23862
+ const p = trial.previous;
23863
+ record.session?.stop();
23864
+ record.session = void 0;
23865
+ record.source = p.source;
23866
+ record.engine = p.engine;
23867
+ record.prepared = p.prepared;
23868
+ record.inputValues = p.inputValues;
23869
+ record.propValues = p.propValues;
23870
+ handle.setSource(p.source);
23871
+ handle.setSchema(p.inputs);
23872
+ handle.setPropsSchema(p.props);
23873
+ record.pendingStructural = true;
23874
+ record.pendingCause = void 0;
23875
+ if (record.renderHandle) this.renderer.setIndicatorInputs(record.renderHandle, record.inputValues, record.propValues);
23876
+ if (!record.hidden) this.executeIndicator(id, handle);
23877
+ }
23878
+ const error = err instanceof Error ? err : new Error(String(err));
23879
+ this.settleCode(record, { ok: false, error });
23755
23880
  }
23756
23881
  /** IndicatorController: tear down an indicator and (if now empty) its pane. */
23757
23882
  /** Live handles of every indicator on the chart (script + native), insertion order. */
@@ -23766,6 +23891,7 @@ var EngineOrchestrator = class _EngineOrchestrator {
23766
23891
  removeIndicator(id) {
23767
23892
  const record = this.registry.remove(id);
23768
23893
  if (record?.native?.type === "volume") this.volumeOptedOut = true;
23894
+ if (record) this.settleCode(record, { ok: false, error: new Error(`[vela] updateCode("${id}") \u2014 the indicator was removed.`) });
23769
23895
  record?.session?.stop();
23770
23896
  if (record?.native?.started) record.native.instance.stop();
23771
23897
  this.handles.delete(id);
@@ -23793,6 +23919,10 @@ var EngineOrchestrator = class _EngineOrchestrator {
23793
23919
  if (!visible) {
23794
23920
  record.session?.stop();
23795
23921
  record.session = void 0;
23922
+ if (record.codeTrial) {
23923
+ record.codeTrial = void 0;
23924
+ this.settleCode(record, { ok: true, error: null });
23925
+ }
23796
23926
  if (record.native?.started) record.native.instance.suspend();
23797
23927
  if (record.renderHandle) this.renderer.setIndicatorVisible?.(record.renderHandle, false);
23798
23928
  else if (record.native) this.mountHiddenNativeRow(id, record);
@@ -23880,6 +24010,7 @@ var EngineOrchestrator = class _EngineOrchestrator {
23880
24010
  this.viewportUnsub?.();
23881
24011
  this.paneActionUnsub?.();
23882
24012
  for (const record of this.registry.all()) {
24013
+ this.settleCode(record, { ok: false, error: new Error("[vela] updateCode \u2014 the chart was destroyed.") });
23883
24014
  record.session?.stop();
23884
24015
  if (record.native?.started) record.native.instance.stop();
23885
24016
  }
@@ -23948,7 +24079,8 @@ var EngineOrchestrator = class _EngineOrchestrator {
23948
24079
  const record = this.registry.get(id);
23949
24080
  if (!record || !record.engine || !record.prepared || record.hidden) return;
23950
24081
  const mode = this.config.live && !record.prepared.reactsToViewport && record.engine.capabilities.streaming ? "live" : "static";
23951
- record.session = record.engine.execute(
24082
+ const prepared = record.prepared;
24083
+ const session = record.engine.execute(
23952
24084
  {
23953
24085
  prepared: record.prepared,
23954
24086
  market: this.market(),
@@ -23969,6 +24101,10 @@ var EngineOrchestrator = class _EngineOrchestrator {
23969
24101
  const cause = record.pendingCause ?? "history";
23970
24102
  if (!this.applyModel(id, model)) return;
23971
24103
  record.pendingCause = void 0;
24104
+ if (record.codeTrial) {
24105
+ record.codeTrial = void 0;
24106
+ this.settleCode(record, { ok: true, error: null });
24107
+ }
23972
24108
  this.emitContextChanged(id);
23973
24109
  this.emitScriptRun(id, cause, first);
23974
24110
  },
@@ -23979,9 +24115,17 @@ var EngineOrchestrator = class _EngineOrchestrator {
23979
24115
  handle.emit("alert", { id: a.id, message: a.message, title: a.title, time: a.time });
23980
24116
  },
23981
24117
  onWarning: (w) => this.events.emit("warning", w),
23982
- onError: (err) => this.fail(id, handle, err)
24118
+ onError: (err) => {
24119
+ if (record.codeTrial) this.rejectCode(id, record, handle, err);
24120
+ else this.fail(id, handle, err);
24121
+ }
23983
24122
  }
23984
24123
  );
24124
+ if (record.prepared !== prepared) {
24125
+ session.stop();
24126
+ return;
24127
+ }
24128
+ record.session = session;
23985
24129
  this.emitContextChanged(id);
23986
24130
  }
23987
24131
  /**
@@ -24482,7 +24626,7 @@ function yieldToPaint() {
24482
24626
  }
24483
24627
  return new Promise((resolve) => setTimeout(resolve, 0));
24484
24628
  }
24485
- function valuesOnSchema(schema, previous) {
24629
+ function valuesOnSchema(schema, previous, oldSchema = []) {
24486
24630
  const out = {};
24487
24631
  const declared = /* @__PURE__ */ new Set();
24488
24632
  for (const s of schema) {
@@ -24490,9 +24634,22 @@ function valuesOnSchema(schema, previous) {
24490
24634
  declared.add(s.key);
24491
24635
  declared.add(s.title);
24492
24636
  }
24493
- for (const [k, v] of Object.entries(previous)) if (declared.has(k)) out[k] = v;
24637
+ const oldDefaults = /* @__PURE__ */ new Map();
24638
+ for (const s of oldSchema) {
24639
+ oldDefaults.set(s.key, s.defval);
24640
+ if (!oldDefaults.has(s.title)) oldDefaults.set(s.title, s.defval);
24641
+ }
24642
+ for (const [k, v] of Object.entries(previous)) {
24643
+ if (!declared.has(k)) continue;
24644
+ if (oldDefaults.has(k) && sameInputValue(oldDefaults.get(k), v)) continue;
24645
+ out[k] = v;
24646
+ }
24494
24647
  return out;
24495
24648
  }
24649
+ function sameInputValue(a, b) {
24650
+ if (a === b) return true;
24651
+ return typeof a === "object" && a !== null && typeof b === "object" && b !== null && JSON.stringify(a) === JSON.stringify(b);
24652
+ }
24496
24653
  function blankedModel(model) {
24497
24654
  return {
24498
24655
  ...model,