@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
@@ -214,7 +214,7 @@ var Vela = (function (exports) {
214
214
  this.controller.applyProps(this.id, values);
215
215
  }
216
216
  updateCode(source) {
217
- this.controller.updateCode(this.id, source);
217
+ return this.controller.updateCode(this.id, source);
218
218
  }
219
219
  setVisible(visible) {
220
220
  this.controller.setVisible(this.id, visible);
@@ -617,6 +617,7 @@ var Vela = (function (exports) {
617
617
  registerIcon("plus", S('<path d="M8 2.8v10.4M2.8 8h10.4"/>'));
618
618
  registerIcon("minus", S('<path d="M2.8 8h10.4"/>'));
619
619
  registerIcon("maximize", S('<path d="M2.5 6V3a.5.5 0 0 1 .5-.5h3M10 2.5h3a.5.5 0 0 1 .5.5v3M13.5 10v3a.5.5 0 0 1-.5.5h-3M6 13.5H3a.5.5 0 0 1-.5-.5v-3"/>'));
620
+ registerIcon("restore", S('<path d="M6 2.5v3a.5.5 0 0 1-.5.5h-3M13.5 6h-3a.5.5 0 0 1-.5-.5v-3M10 13.5v-3a.5.5 0 0 1 .5-.5h3M2.5 10h3a.5.5 0 0 1 .5.5v3"/>'));
620
621
  registerIcon("restore", S('<path d="M6.2 2.5v3.7H2.5M9.8 13.5V9.8h3.7M13.5 6.2H9.8V2.5M2.5 9.8h3.7v3.7"/>'));
621
622
  registerIcon("star", S('<path d="M8 2.2l1.75 3.55 3.9.55-2.8 2.75.65 3.9L8 11.1l-3.5 1.85.65-3.9-2.8-2.75 3.9-.55z"/>'));
622
623
  registerIcon("star-filled", S('<path d="M8 2.2l1.75 3.55 3.9.55-2.8 2.75.65 3.9L8 11.1l-3.5 1.85.65-3.9-2.8-2.75 3.9-.55z"/>', 'fill="currentColor"'));
@@ -3275,6 +3276,10 @@ var Vela = (function (exports) {
3275
3276
 
3276
3277
  // src/core/drawings/types/FibLevels.ts
3277
3278
  var FibLevels = class extends FibRatios {
3279
+ /** Price of a level for the two anchor prices; subclasses override to change which anchor ratio 0 sits on. */
3280
+ levelPrice(ratio, p1, p2) {
3281
+ return p1 + ratio * (p2 - p1);
3282
+ }
3278
3283
  /** Per-level pixel line + price for the ENABLED levels, spanning the anchors' time range. */
3279
3284
  levelLines(proj) {
3280
3285
  const a = this.anchors[0];
@@ -3284,11 +3289,10 @@ var Vela = (function (exports) {
3284
3289
  const xb = proj.xOf(b.time);
3285
3290
  const x1 = Math.min(xa, xb);
3286
3291
  const x2 = Math.max(xa, xb);
3287
- const delta = b.price - a.price;
3288
3292
  const out = [];
3289
3293
  for (const lv of this.levels) {
3290
3294
  if (!lv.enabled) continue;
3291
- const price = a.price + lv.ratio * delta;
3295
+ const price = this.levelPrice(lv.ratio, a.price, b.price);
3292
3296
  const y = proj.yOf(price, this.paneId);
3293
3297
  if (y == null) continue;
3294
3298
  out.push({ ratio: lv.ratio, color: lv.color, label: lv.label, price, x1, x2, y });
@@ -3328,8 +3332,7 @@ var Vela = (function (exports) {
3328
3332
  const a = this.anchors[0];
3329
3333
  const b = this.anchors[1];
3330
3334
  if (!a || !b) return null;
3331
- const delta = b.price - a.price;
3332
- const prices = this.levels.filter((l) => l.enabled).map((l) => a.price + l.ratio * delta);
3335
+ const prices = this.levels.filter((l) => l.enabled).map((l) => this.levelPrice(l.ratio, a.price, b.price));
3333
3336
  if (prices.length === 0) return null;
3334
3337
  return { min: Math.min(...prices), max: Math.max(...prices) };
3335
3338
  }
@@ -3415,13 +3418,24 @@ var Vela = (function (exports) {
3415
3418
  // src/core/drawings/types/FibRetracement.ts
3416
3419
  var LEVELS = fibLevels([0, 0.236, 0.382, 0.5, 0.618, 0.786, 1]);
3417
3420
  var FibRetracement = class extends FibLevels {
3418
- constructor() {
3419
- super(...arguments);
3421
+ constructor(init) {
3422
+ super(init);
3420
3423
  this.type = "fibretracement";
3424
+ if (this.reverse === void 0) this.reverse = false;
3421
3425
  }
3422
3426
  defaultLevels() {
3423
3427
  return LEVELS;
3424
3428
  }
3429
+ levelPrice(ratio, p1, p2) {
3430
+ return this.reverse ? p1 + ratio * (p2 - p1) : p2 + ratio * (p1 - p2);
3431
+ }
3432
+ writeProps() {
3433
+ return { ...super.writeProps(), reverse: this.reverse };
3434
+ }
3435
+ readProps(props) {
3436
+ super.readProps(props);
3437
+ this.reverse = typeof props.reverse === "boolean" ? props.reverse : true;
3438
+ }
3425
3439
  };
3426
3440
 
3427
3441
  // src/core/drawings/types/FibExtension.ts
@@ -9234,20 +9248,26 @@ var Vela = (function (exports) {
9234
9248
  /**
9235
9249
  * IndicatorController: replace a SCRIPT indicator's source in place (see
9236
9250
  * {@link IndicatorHandle.updateCode}). Prepare-first: the running session keeps
9237
- * computing until the new source has compiled, so a broken edit costs the user
9238
- * nothing but an `error` event. Natives have no script — warn and leave them alone.
9251
+ * computing until the new source has compiled; then the new code runs on TRIAL until
9252
+ * its first model lands, and a failure before that puts the previous code back.
9253
+ * Natives have no script — warn and leave them alone.
9239
9254
  */
9240
9255
  updateCode(id, source) {
9241
9256
  const record = this.registry.get(id);
9242
9257
  const handle = this.handles.get(id);
9243
- if (!record || !handle) return;
9258
+ if (!record || !handle) return Promise.resolve({ ok: false, error: new Error(`[vela] updateCode("${id}") \u2014 the indicator is no longer on the chart.`) });
9244
9259
  if (record.native) {
9245
9260
  console.warn(`[vela] updateCode("${id}") \u2014 a native indicator has no script to update.`);
9246
- return;
9261
+ return Promise.resolve({ ok: false, error: new Error(`[vela] updateCode("${id}") \u2014 a native indicator has no script to update.`) });
9247
9262
  }
9248
- if (source === record.source && record.pendingSource === void 0) return;
9249
- record.pendingSource = source;
9250
- void this.swapSource(id, source, handle);
9263
+ const busy = record.pendingSource !== void 0 || record.codeTrial !== void 0;
9264
+ if (!busy && source === record.source) return Promise.resolve({ ok: true, error: null });
9265
+ return new Promise((resolve) => {
9266
+ (record.codeWaiters ?? (record.codeWaiters = [])).push(resolve);
9267
+ if (record.pendingSource === source || record.pendingSource === void 0 && record.codeTrial && record.source === source) return;
9268
+ record.pendingSource = source;
9269
+ void this.swapSource(id, source, handle);
9270
+ });
9251
9271
  }
9252
9272
  async swapSource(id, source, handle) {
9253
9273
  const engine = this.registry.get(id)?.engine ?? this.engineFor(this.registry.get(id)?.options?.language);
@@ -9258,26 +9278,41 @@ var Vela = (function (exports) {
9258
9278
  const record2 = this.registry.get(id);
9259
9279
  if (record2?.pendingSource === source) {
9260
9280
  record2.pendingSource = void 0;
9261
- this.fail(id, handle, err);
9281
+ this.rejectCode(id, record2, handle, err);
9262
9282
  }
9263
9283
  return;
9264
9284
  }
9265
9285
  const record = this.registry.get(id);
9266
9286
  if (!record || record.pendingSource !== source) return;
9267
9287
  record.pendingSource = void 0;
9288
+ const previous = record.codeTrial?.previous ?? {
9289
+ source: record.source,
9290
+ engine: record.engine,
9291
+ prepared: record.prepared,
9292
+ inputValues: record.inputValues,
9293
+ propValues: record.propValues,
9294
+ inputs: [...handle.inputs],
9295
+ props: [...handle.props]
9296
+ };
9297
+ record.inputValues = valuesOnSchema(prepared.inputs, record.inputValues, record.prepared?.inputs);
9298
+ record.propValues = valuesOnSchema(prepared.props ?? [], record.propValues, record.prepared?.props);
9268
9299
  record.source = source;
9269
9300
  record.engine = engine;
9270
9301
  record.prepared = prepared;
9271
9302
  handle.setSource(source);
9272
- record.inputValues = valuesOnSchema(prepared.inputs, record.inputValues);
9273
- record.propValues = valuesOnSchema(prepared.props ?? [], record.propValues);
9274
9303
  handle.setSchema(prepared.inputs);
9275
9304
  handle.setPropsSchema(prepared.props ?? []);
9276
9305
  record.session?.stop();
9277
9306
  record.session = void 0;
9278
9307
  record.pendingStructural = true;
9279
9308
  record.pendingCause = "code";
9280
- if (record.hidden) return;
9309
+ if (record.hidden) {
9310
+ record.codeTrial = void 0;
9311
+ if (record.renderHandle) this.renderer.setIndicatorInputs(record.renderHandle, record.inputValues, record.propValues);
9312
+ this.settleCode(record, { ok: true, error: null });
9313
+ return;
9314
+ }
9315
+ record.codeTrial = { previous };
9281
9316
  if (record.renderHandle) {
9282
9317
  this.renderer.setIndicatorInputs(record.renderHandle, record.inputValues, record.propValues);
9283
9318
  this.setLoading(record, true);
@@ -9285,6 +9320,46 @@ var Vela = (function (exports) {
9285
9320
  this.mountLoadingPlaceholder(id, record);
9286
9321
  }
9287
9322
  this.executeIndicator(id, handle);
9323
+ if (this.bars.length === 0 && record.codeTrial) {
9324
+ record.codeTrial = void 0;
9325
+ this.settleCode(record, { ok: true, error: null });
9326
+ }
9327
+ }
9328
+ /** Resolve every `updateCode` caller waiting on this record's chain of edits. */
9329
+ settleCode(record, result) {
9330
+ const waiters = record.codeWaiters;
9331
+ record.codeWaiters = void 0;
9332
+ if (waiters) for (const resolve of waiters) resolve(result);
9333
+ }
9334
+ /**
9335
+ * An update failed — at prepare, or on trial before its first model. A trial puts the
9336
+ * previous code back (source, engine, prepared script, values, schema) and restarts it;
9337
+ * its visuals were never dropped, so the chart keeps painting throughout. Then the
9338
+ * failure reports the usual way and every waiting caller learns it.
9339
+ */
9340
+ rejectCode(id, record, handle, err) {
9341
+ const trial = record.codeTrial;
9342
+ record.codeTrial = void 0;
9343
+ this.fail(id, handle, err);
9344
+ if (trial) {
9345
+ const p = trial.previous;
9346
+ record.session?.stop();
9347
+ record.session = void 0;
9348
+ record.source = p.source;
9349
+ record.engine = p.engine;
9350
+ record.prepared = p.prepared;
9351
+ record.inputValues = p.inputValues;
9352
+ record.propValues = p.propValues;
9353
+ handle.setSource(p.source);
9354
+ handle.setSchema(p.inputs);
9355
+ handle.setPropsSchema(p.props);
9356
+ record.pendingStructural = true;
9357
+ record.pendingCause = void 0;
9358
+ if (record.renderHandle) this.renderer.setIndicatorInputs(record.renderHandle, record.inputValues, record.propValues);
9359
+ if (!record.hidden) this.executeIndicator(id, handle);
9360
+ }
9361
+ const error = err instanceof Error ? err : new Error(String(err));
9362
+ this.settleCode(record, { ok: false, error });
9288
9363
  }
9289
9364
  /** IndicatorController: tear down an indicator and (if now empty) its pane. */
9290
9365
  /** Live handles of every indicator on the chart (script + native), insertion order. */
@@ -9299,6 +9374,7 @@ var Vela = (function (exports) {
9299
9374
  removeIndicator(id) {
9300
9375
  const record = this.registry.remove(id);
9301
9376
  if (record?.native?.type === "volume") this.volumeOptedOut = true;
9377
+ if (record) this.settleCode(record, { ok: false, error: new Error(`[vela] updateCode("${id}") \u2014 the indicator was removed.`) });
9302
9378
  record?.session?.stop();
9303
9379
  if (record?.native?.started) record.native.instance.stop();
9304
9380
  this.handles.delete(id);
@@ -9326,6 +9402,10 @@ var Vela = (function (exports) {
9326
9402
  if (!visible) {
9327
9403
  record.session?.stop();
9328
9404
  record.session = void 0;
9405
+ if (record.codeTrial) {
9406
+ record.codeTrial = void 0;
9407
+ this.settleCode(record, { ok: true, error: null });
9408
+ }
9329
9409
  if (record.native?.started) record.native.instance.suspend();
9330
9410
  if (record.renderHandle) this.renderer.setIndicatorVisible?.(record.renderHandle, false);
9331
9411
  else if (record.native) this.mountHiddenNativeRow(id, record);
@@ -9413,6 +9493,7 @@ var Vela = (function (exports) {
9413
9493
  this.viewportUnsub?.();
9414
9494
  this.paneActionUnsub?.();
9415
9495
  for (const record of this.registry.all()) {
9496
+ this.settleCode(record, { ok: false, error: new Error("[vela] updateCode \u2014 the chart was destroyed.") });
9416
9497
  record.session?.stop();
9417
9498
  if (record.native?.started) record.native.instance.stop();
9418
9499
  }
@@ -9481,7 +9562,8 @@ var Vela = (function (exports) {
9481
9562
  const record = this.registry.get(id);
9482
9563
  if (!record || !record.engine || !record.prepared || record.hidden) return;
9483
9564
  const mode = this.config.live && !record.prepared.reactsToViewport && record.engine.capabilities.streaming ? "live" : "static";
9484
- record.session = record.engine.execute(
9565
+ const prepared = record.prepared;
9566
+ const session = record.engine.execute(
9485
9567
  {
9486
9568
  prepared: record.prepared,
9487
9569
  market: this.market(),
@@ -9502,6 +9584,10 @@ var Vela = (function (exports) {
9502
9584
  const cause = record.pendingCause ?? "history";
9503
9585
  if (!this.applyModel(id, model)) return;
9504
9586
  record.pendingCause = void 0;
9587
+ if (record.codeTrial) {
9588
+ record.codeTrial = void 0;
9589
+ this.settleCode(record, { ok: true, error: null });
9590
+ }
9505
9591
  this.emitContextChanged(id);
9506
9592
  this.emitScriptRun(id, cause, first2);
9507
9593
  },
@@ -9512,9 +9598,17 @@ var Vela = (function (exports) {
9512
9598
  handle.emit("alert", { id: a.id, message: a.message, title: a.title, time: a.time });
9513
9599
  },
9514
9600
  onWarning: (w) => this.events.emit("warning", w),
9515
- onError: (err) => this.fail(id, handle, err)
9601
+ onError: (err) => {
9602
+ if (record.codeTrial) this.rejectCode(id, record, handle, err);
9603
+ else this.fail(id, handle, err);
9604
+ }
9516
9605
  }
9517
9606
  );
9607
+ if (record.prepared !== prepared) {
9608
+ session.stop();
9609
+ return;
9610
+ }
9611
+ record.session = session;
9518
9612
  this.emitContextChanged(id);
9519
9613
  }
9520
9614
  /**
@@ -10015,7 +10109,7 @@ var Vela = (function (exports) {
10015
10109
  }
10016
10110
  return new Promise((resolve) => setTimeout(resolve, 0));
10017
10111
  }
10018
- function valuesOnSchema(schema, previous) {
10112
+ function valuesOnSchema(schema, previous, oldSchema = []) {
10019
10113
  const out = {};
10020
10114
  const declared = /* @__PURE__ */ new Set();
10021
10115
  for (const s of schema) {
@@ -10023,9 +10117,22 @@ var Vela = (function (exports) {
10023
10117
  declared.add(s.key);
10024
10118
  declared.add(s.title);
10025
10119
  }
10026
- for (const [k, v] of Object.entries(previous)) if (declared.has(k)) out[k] = v;
10120
+ const oldDefaults = /* @__PURE__ */ new Map();
10121
+ for (const s of oldSchema) {
10122
+ oldDefaults.set(s.key, s.defval);
10123
+ if (!oldDefaults.has(s.title)) oldDefaults.set(s.title, s.defval);
10124
+ }
10125
+ for (const [k, v] of Object.entries(previous)) {
10126
+ if (!declared.has(k)) continue;
10127
+ if (oldDefaults.has(k) && sameInputValue(oldDefaults.get(k), v)) continue;
10128
+ out[k] = v;
10129
+ }
10027
10130
  return out;
10028
10131
  }
10132
+ function sameInputValue(a, b) {
10133
+ if (a === b) return true;
10134
+ return typeof a === "object" && a !== null && typeof b === "object" && b !== null && JSON.stringify(a) === JSON.stringify(b);
10135
+ }
10029
10136
  function blankedModel(model) {
10030
10137
  return {
10031
10138
  ...model,
@@ -13587,6 +13694,17 @@ ${STATIC_DECLS}
13587
13694
  return span;
13588
13695
  }
13589
13696
 
13697
+ // src/ui/surface-events.ts
13698
+ var SURFACE_OPEN_EVENT = "vela:surface-open";
13699
+ var SURFACE_CLOSE_EVENT = "vela:surface-close";
13700
+ function announceSurface(el, open2, kind, trigger = null) {
13701
+ const View = el.ownerDocument.defaultView;
13702
+ if (!View) return;
13703
+ el.dispatchEvent(
13704
+ new View.CustomEvent(open2 ? SURFACE_OPEN_EVENT : SURFACE_CLOSE_EVENT, { bubbles: true, composed: true, detail: { kind, trigger } })
13705
+ );
13706
+ }
13707
+
13590
13708
  // node_modules/@zag-js/anatomy/dist/create-anatomy.mjs
13591
13709
  var createAnatomy = (name, parts3 = []) => ({
13592
13710
  parts: (...values) => {
@@ -18065,6 +18183,8 @@ ${STATIC_DECLS}
18065
18183
  /** Trigger rect captured when this level opened — the list stays put if the
18066
18184
  * trigger then moves (favorite chips shifting the caret). */
18067
18185
  this.pinnedAnchor = null;
18186
+ /** The open state last announced — see {@link announce}. */
18187
+ this.shown = false;
18068
18188
  this.doc = doc;
18069
18189
  this.host = opts.host;
18070
18190
  this.onSelect = opts.onSelect;
@@ -18078,6 +18198,7 @@ ${STATIC_DECLS}
18078
18198
  this.positioner.appendChild(this.list);
18079
18199
  this.host.appendChild(this.positioner);
18080
18200
  const trigger = opts.trigger;
18201
+ this.opener = trigger ?? opts.opener ?? null;
18081
18202
  this.ctrl = menuController({
18082
18203
  items: [],
18083
18204
  id: opts.id,
@@ -18099,15 +18220,21 @@ ${STATIC_DECLS}
18099
18220
  if (opts.triggerId && trigger) trigger.id = opts.triggerId;
18100
18221
  this.handle = runMachine(this.ctrl.machine, this.ctrl.props, (service) => {
18101
18222
  const api = this.ctrl.connect(service);
18223
+ if (this.shown && !api.open) this.announce(false);
18102
18224
  if (trigger) spreadProps(trigger, api.getTriggerProps(), this.mid);
18103
18225
  spreadProps(this.positioner, api.getPositionerProps(), this.mid);
18104
18226
  spreadProps(this.list, api.getContentProps(), this.mid);
18105
18227
  this.project(api);
18228
+ if (api.open && !this.shown) this.announce(true);
18106
18229
  });
18107
18230
  }
18108
18231
  get api() {
18109
18232
  return this.ctrl.connect(this.handle.service);
18110
18233
  }
18234
+ announce(open2) {
18235
+ this.shown = open2;
18236
+ announceSurface(this.list, open2, "menu", this.opener);
18237
+ }
18111
18238
  setItems(items) {
18112
18239
  this.items = items;
18113
18240
  for (const sub2 of this.subs.values()) sub2.destroy();
@@ -18125,6 +18252,7 @@ ${STATIC_DECLS}
18125
18252
  for (const sub2 of this.subs.values()) sub2.destroy();
18126
18253
  this.subs.clear();
18127
18254
  this.handle.stop();
18255
+ if (this.shown) this.announce(false);
18128
18256
  this.positioner.remove();
18129
18257
  }
18130
18258
  byId(id) {
@@ -18218,6 +18346,7 @@ ${STATIC_DECLS}
18218
18346
  const sub2 = new _Surface(doc, {
18219
18347
  host: this.host,
18220
18348
  placement: "right-start",
18349
+ opener: li,
18221
18350
  onSelect: this.onSelect,
18222
18351
  onFavorite: this.onFavorite,
18223
18352
  checkmarks: this.checkmarks,
@@ -18437,16 +18566,21 @@ ${STATIC_DECLS}
18437
18566
  this.hide();
18438
18567
  };
18439
18568
  const onReflow = () => this.place();
18440
- setTimeout(() => document.addEventListener("pointerdown", onOutside, true), 0);
18569
+ setTimeout(() => {
18570
+ if (this.onOutside === onOutside) document.addEventListener("pointerdown", onOutside, true);
18571
+ }, 0);
18441
18572
  document.addEventListener("keydown", onKey, true);
18442
18573
  window.addEventListener("resize", onReflow, true);
18443
18574
  document.addEventListener("scroll", onReflow, true);
18444
18575
  this.onOutside = onOutside;
18445
18576
  this.onKey = onKey;
18446
18577
  this.onReflow = onReflow;
18578
+ announceSurface(this.el, true, "popover", this.trigger);
18447
18579
  }
18448
18580
  hide() {
18449
18581
  if (!this.shown) return;
18582
+ this.shown = false;
18583
+ announceSurface(this.el, false, "popover", this.trigger);
18450
18584
  if (this.onOutside) document.removeEventListener("pointerdown", this.onOutside, true);
18451
18585
  if (this.onKey) document.removeEventListener("keydown", this.onKey, true);
18452
18586
  if (this.onReflow) {
@@ -18466,7 +18600,6 @@ ${STATIC_DECLS}
18466
18600
  } else {
18467
18601
  this.el.remove();
18468
18602
  }
18469
- this.shown = false;
18470
18603
  if (open === this) open = null;
18471
18604
  this.ctrl.onClose?.();
18472
18605
  }
@@ -20356,6 +20489,8 @@ ${overlayScrollbarCss(".vela-dialog *")}
20356
20489
  // src/ui/components/dialog/view.ts
20357
20490
  var Dialog = class {
20358
20491
  constructor(opts = {}) {
20492
+ this.opener = null;
20493
+ this.wasOpen = false;
20359
20494
  const doc = (opts.host ?? document.body).ownerDocument;
20360
20495
  injectStyles(DIALOG_STYLE_ID, DIALOG_CSS, doc);
20361
20496
  const host = opts.host ?? doc.body;
@@ -20452,6 +20587,7 @@ ${overlayScrollbarCss(".vela-dialog *")}
20452
20587
  const mid = String(this.ctrl.props.id);
20453
20588
  this.handle = runMachine(this.ctrl.machine, this.ctrl.props, (service) => {
20454
20589
  const api = this.ctrl.connect(service);
20590
+ if (this.wasOpen && !api.open) this.announce(false);
20455
20591
  spreadProps(this.backdrop, api.getBackdropProps(), mid);
20456
20592
  spreadProps(this.positioner, api.getPositionerProps(), mid);
20457
20593
  spreadProps(this.panel, api.getContentProps(), mid);
@@ -20459,12 +20595,27 @@ ${overlayScrollbarCss(".vela-dialog *")}
20459
20595
  spreadProps(close, api.getCloseTriggerProps(), mid);
20460
20596
  this.backdrop.style.display = api.open ? "" : "none";
20461
20597
  this.positioner.style.display = api.open ? "" : "none";
20598
+ if (api.open && !this.wasOpen) this.announce(true);
20599
+ if (this.wasOpen && !api.open) this.restoreOpener();
20600
+ this.wasOpen = api.open;
20462
20601
  });
20463
20602
  }
20603
+ /** Closing hands focus back to whatever opened it (Escape, the ✕, hide(), or a
20604
+ * teardown that outruns the machine's close notification). */
20605
+ restoreOpener() {
20606
+ const opener = this.opener;
20607
+ this.opener = null;
20608
+ if (opener?.isConnected) opener.focus({ preventScroll: true });
20609
+ }
20610
+ announce(open2) {
20611
+ const opener = this.opener === this.panel.ownerDocument.body ? null : this.opener;
20612
+ announceSurface(this.panel, open2, "dialog", opener);
20613
+ }
20464
20614
  get open() {
20465
20615
  return this.ctrl.connect(this.handle.service).open;
20466
20616
  }
20467
20617
  show() {
20618
+ this.opener = this.panel.ownerDocument.activeElement;
20468
20619
  this.ctrl.connect(this.handle.service).setOpen(true);
20469
20620
  }
20470
20621
  hide() {
@@ -20479,6 +20630,11 @@ ${overlayScrollbarCss(".vela-dialog *")}
20479
20630
  destroy() {
20480
20631
  if (this.open) this.hide();
20481
20632
  this.handle.stop();
20633
+ if (this.wasOpen) {
20634
+ this.wasOpen = false;
20635
+ this.announce(false);
20636
+ }
20637
+ this.restoreOpener();
20482
20638
  this.backdrop.remove();
20483
20639
  this.positioner.remove();
20484
20640
  }
@@ -21463,14 +21619,49 @@ ${overlayScrollbarCss(".vela-dialog *")}
21463
21619
  const knob = document.createElement("div");
21464
21620
  knob.style.cssText = "position:absolute;top:50%;width:15px;height:15px;border-radius:50%;background:var(--vela-selected-bg);box-shadow:0 1px 3px rgba(0,0,0,0.55);transform:translate(-50%,-50%);pointer-events:none;";
21465
21621
  track.appendChild(knob);
21466
- const pctBox = document.createElement("div");
21467
- pctBox.style.cssText = `min-width:42px;text-align:center;font:var(--vela-font-size-md) ${theme.fontFamily};color:var(--vela-fg);border:1px solid var(--vela-border);border-radius:5px;padding:3px 4px;`;
21622
+ const pctBox = document.createElement("input");
21623
+ pctBox.type = "text";
21624
+ pctBox.inputMode = "numeric";
21625
+ pctBox.title = "Opacity (%)";
21626
+ pctBox.style.cssText = `width:46px;box-sizing:border-box;text-align:center;font:var(--vela-font-size-md) ${theme.fontFamily};color:var(--vela-fg);background:transparent;border:1px solid var(--vela-border);border-radius:5px;padding:3px 4px;outline:none;`;
21627
+ pctBox.addEventListener("focus", () => {
21628
+ pctBox.style.borderColor = "var(--vela-border-strong)";
21629
+ pctBox.select();
21630
+ });
21468
21631
  opRow.append(track, pctBox);
21469
21632
  const paintOpacity = () => {
21470
21633
  track.style.background = `linear-gradient(to right, ${curHex}00, ${curHex}ff), ${CHECKER}`;
21471
21634
  knob.style.left = `${curAlpha * 100}%`;
21472
- pctBox.textContent = `${Math.round(curAlpha * 100)}%`;
21635
+ pctBox.value = `${Math.round(curAlpha * 100)}%`;
21473
21636
  };
21637
+ const commitTyped = () => {
21638
+ pctBox.style.borderColor = "var(--vela-border)";
21639
+ const n = parseFloat(pctBox.value.replace("%", ""));
21640
+ if (Number.isFinite(n)) {
21641
+ const next2 = Math.max(0, Math.min(100, n)) / 100;
21642
+ if (Math.round(next2 * 100) !== Math.round(curAlpha * 100)) {
21643
+ curAlpha = next2;
21644
+ paintOpacity();
21645
+ emit();
21646
+ return;
21647
+ }
21648
+ }
21649
+ paintOpacity();
21650
+ };
21651
+ pctBox.addEventListener("change", commitTyped);
21652
+ pctBox.addEventListener("blur", () => {
21653
+ pctBox.style.borderColor = "var(--vela-border)";
21654
+ paintOpacity();
21655
+ });
21656
+ pctBox.addEventListener("keydown", (e) => {
21657
+ if (e.key === "Escape") return;
21658
+ e.stopPropagation();
21659
+ if (e.key === "Enter") {
21660
+ e.preventDefault();
21661
+ commitTyped();
21662
+ pctBox.blur();
21663
+ }
21664
+ });
21474
21665
  let dragging = false;
21475
21666
  const onDrag = (clientX) => {
21476
21667
  const r = track.getBoundingClientRect();
@@ -24613,15 +24804,23 @@ ${overlayScrollbarCss(".vela-dialog.vela-ind-dialog *", 9)}
24613
24804
  this.seg(x + w, y + h, x, y + h, lineWidth, c);
24614
24805
  this.seg(x, y + h, x, y, lineWidth, c);
24615
24806
  }
24616
- /** Filled circle (triangle fan). */
24807
+ /**
24808
+ * Filled circle (triangle fan), feathered like a line: the rim is padded by {@link AA_PAD} and
24809
+ * edgeDist runs from 0 at the center to the padded radius at the rim, with edgeHalf = r. The
24810
+ * distance grows linearly along each spoke, so the shader's line feather gives a round soft edge.
24811
+ */
24617
24812
  circle(cx, cy, r, c, segments = 16) {
24618
- let px = cx + r;
24813
+ const ext = r + AA_PAD;
24814
+ let px = cx + ext;
24619
24815
  let py = cy;
24816
+ this.ensure(segments * 3);
24620
24817
  for (let i = 1; i <= segments; i += 1) {
24621
24818
  const a = i / segments * Math.PI * 2;
24622
- const nx = cx + Math.cos(a) * r;
24623
- const ny = cy + Math.sin(a) * r;
24624
- this.tri(cx, cy, c, px, py, c, nx, ny, c);
24819
+ const nx = cx + Math.cos(a) * ext;
24820
+ const ny = cy + Math.sin(a) * ext;
24821
+ this.v(cx, cy, c, 0, r);
24822
+ this.v(px, py, c, ext, r);
24823
+ this.v(nx, ny, c, ext, r);
24625
24824
  px = nx;
24626
24825
  py = ny;
24627
24826
  }
@@ -24802,7 +25001,7 @@ void main() {
24802
25001
  }
24803
25002
  mount(canvas) {
24804
25003
  this.canvas = canvas;
24805
- this.gl = canvas.getContext("webgl2", { alpha: true, antialias: true, depth: false, stencil: false, premultipliedAlpha: true });
25004
+ this.gl = canvas.getContext("webgl2", { alpha: true, antialias: false, depth: false, stencil: false, premultipliedAlpha: true });
24806
25005
  if (!this.gl) return;
24807
25006
  if (!this.initGL()) {
24808
25007
  this.gl = null;
@@ -26061,6 +26260,12 @@ void main() {
26061
26260
  this.lastTapT = 0;
26062
26261
  this.lastTapX = 0;
26063
26262
  this.lastTapY = 0;
26263
+ // Whether the last two primary presses were claimed by the drawings layer. A double-click
26264
+ // is the last press plus the one before it; a tool-driven click pair must never fall through
26265
+ // to the pane maximize toggle, even when the tool disarmed itself between the two clicks
26266
+ // (a finished placement leaves plain cursor mode for the second click).
26267
+ this.lastPressDrawing = false;
26268
+ this.prevPressDrawing = false;
26064
26269
  this.onTouchContextMenu = (e) => {
26065
26270
  if (this.touches.size === 0) return;
26066
26271
  if (!(e.target instanceof Node) || !this.el?.contains(e.target)) return;
@@ -26115,19 +26320,24 @@ void main() {
26115
26320
  this.moved = false;
26116
26321
  this.startX = x;
26117
26322
  this.startY = y;
26323
+ this.prevPressDrawing = this.lastPressDrawing;
26324
+ this.lastPressDrawing = false;
26118
26325
  if (this.deps.drawingsClaim?.(x, y)) {
26119
26326
  this.region = "drawing";
26327
+ this.lastPressDrawing = true;
26120
26328
  this.deps.drawingsPointerDown?.(x, y, this.snapMode(e), e.shiftKey, e.ctrlKey || e.metaKey);
26121
26329
  this.capture(e.pointerId);
26122
26330
  return;
26123
26331
  }
26124
26332
  if (e.shiftKey && this.regionAt(x, y) === "data" && this.deps.drawingsMeasureStart?.(x, y, this.snapMode(e))) {
26125
26333
  this.region = "drawing";
26334
+ this.lastPressDrawing = true;
26126
26335
  this.capture(e.pointerId);
26127
26336
  return;
26128
26337
  }
26129
26338
  if ((e.ctrlKey || e.metaKey) && this.regionAt(x, y) === "data" && this.deps.drawingsMarqueeStart?.(x, y)) {
26130
26339
  this.region = "drawing";
26340
+ this.lastPressDrawing = true;
26131
26341
  this.capture(e.pointerId);
26132
26342
  return;
26133
26343
  }
@@ -26243,7 +26453,7 @@ void main() {
26243
26453
  this.deps.drawingsPointerUp?.(x, y, this.snapMode(e));
26244
26454
  } else if (tapRelease && this.region === "data") {
26245
26455
  this.deps.onClick(x, y);
26246
- } else if (this.dragging && this.region === "data") {
26456
+ } else if (this.dragging && this.region === "data" && wasTouch) {
26247
26457
  const stale = e.timeStamp - this.lastT > FLING_STALE_MS;
26248
26458
  if (!stale && Math.abs(this.vx) > FLING_MIN_SPEED) {
26249
26459
  const pitch = this.deps.getCoords().pxPerBar();
@@ -26449,6 +26659,7 @@ void main() {
26449
26659
  if (region === "price") this.deps.resetPriceScale(x, y);
26450
26660
  else if (region === "separator") this.deps.resetPaneSize(y);
26451
26661
  else if (region === "time") this.deps.resetView();
26662
+ else if (this.lastPressDrawing || this.prevPressDrawing) return;
26452
26663
  else this.deps.dataDblClick(x, y);
26453
26664
  }
26454
26665
  };
@@ -28614,6 +28825,7 @@ void main() {
28614
28825
  const step = pickStep(span / Math.max(1, target));
28615
28826
  const zFrom = fromMs + offsetMs;
28616
28827
  const zTo = toMs + offsetMs;
28828
+ if (step >= MONTH) return calendarTicks(zFrom, zTo, step >= YEAR ? 12 : step >= 3 * MONTH ? 3 : 1, offsetMs);
28617
28829
  const first2 = Math.ceil(zFrom / step) * step;
28618
28830
  const out = [];
28619
28831
  for (let zt = first2; zt <= zTo; zt += step) {
@@ -28644,6 +28856,18 @@ void main() {
28644
28856
  }
28645
28857
  return out;
28646
28858
  }
28859
+ function calendarTicks(zFrom, zTo, months, offsetMs) {
28860
+ const d0 = new Date(zFrom);
28861
+ let idx = d0.getUTCFullYear() * 12 + d0.getUTCMonth();
28862
+ if (Date.UTC(Math.floor(idx / 12), idx % 12, 1) < zFrom) idx += 1;
28863
+ idx = Math.ceil(idx / months) * months;
28864
+ const out = [];
28865
+ 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)) {
28866
+ const label = months === 12 ? String(Math.floor(idx / 12)) : MONTHS[idx % 12];
28867
+ out.push({ time: zt - offsetMs, label, major: true });
28868
+ }
28869
+ return out;
28870
+ }
28647
28871
 
28648
28872
  // src/renderers/native/chrome/countdown.ts
28649
28873
  function countdownText(barOpen, barMs, now2) {
@@ -32685,6 +32909,12 @@ ${overlayScrollbarCss(".vela-sd-pane")}
32685
32909
  activeDragId() {
32686
32910
  return this.state.kind === "pressed" && this.state.moved ? this.state.id : null;
32687
32911
  }
32912
+ /** The store drawings a live drag is moving — the pressed one and its riders — or none
32913
+ * before the drag passes the slop. A Ctrl-drag moves copies, so its sources stay put. */
32914
+ movingIds() {
32915
+ if (this.state.kind !== "pressed" || !this.state.moved || this.state.clones) return /* @__PURE__ */ new Set();
32916
+ return /* @__PURE__ */ new Set([this.state.id, ...this.state.riders.map((r) => r.id)]);
32917
+ }
32688
32918
  /** The drawing under a press that has not been released yet (drag or click undecided), or null. */
32689
32919
  pressedId() {
32690
32920
  return this.state.kind === "pressed" ? this.state.id : null;
@@ -33343,6 +33573,17 @@ ${overlayScrollbarCss(".vela-sd-pane")}
33343
33573
  }
33344
33574
  }));
33345
33575
  }
33576
+ if (drawing instanceof FibRetracement) {
33577
+ const fib = drawing;
33578
+ grid.appendChild(fieldRow({
33579
+ label: "Reverse",
33580
+ bool: true,
33581
+ toggle: {
33582
+ checked: fib.reverse,
33583
+ onChange: (v) => actions.patch({ reverse: v })
33584
+ }
33585
+ }));
33586
+ }
33346
33587
  levels.forEach((lv, i) => {
33347
33588
  const row = document.createElement("div");
33348
33589
  row.className = "vela-field-span";
@@ -34710,6 +34951,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
34710
34951
  );
34711
34952
  }
34712
34953
  }
34954
+ announceSurface(fly, true, "menu", cell);
34713
34955
  }
34714
34956
  openMagnetFlyout() {
34715
34957
  const cell = this.magnetCell;
@@ -34733,6 +34975,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
34733
34975
  })
34734
34976
  );
34735
34977
  }
34978
+ announceSurface(fly, true, "menu", cell);
34736
34979
  }
34737
34980
  flyoutHeader(text) {
34738
34981
  const t = this.theme;
@@ -34801,9 +35044,11 @@ ${overlayScrollbarCss(".vela-sd-pane")}
34801
35044
  }
34802
35045
  closeFlyout() {
34803
35046
  this.starEls.clear();
34804
- if (this.flyout) {
34805
- this.flyout.remove();
35047
+ const fly = this.flyout;
35048
+ if (fly) {
34806
35049
  this.flyout = null;
35050
+ announceSurface(fly, false, "menu", this.flyoutCell);
35051
+ fly.remove();
34807
35052
  this.flyoutCell?.classList.remove("vela-open");
34808
35053
  this.flyoutCell = null;
34809
35054
  this.flyoutOwnerId = null;
@@ -35128,6 +35373,8 @@ ${overlayScrollbarCss(".vela-sd-pane")}
35128
35373
  this.drawings = [];
35129
35374
  /** Ids painted on an interleave layer this frame — the top canvas paints only their handles. */
35130
35375
  this.sliced = /* @__PURE__ */ new Set();
35376
+ /** Interleaved drawings mid-drag: painted on the top canvas, left out of their slice. */
35377
+ this.lifted = /* @__PURE__ */ new Set();
35131
35378
  /** Cached slice canvases, keyed `paneId|beforeZ`, reused across frames to avoid churn. */
35132
35379
  this.sliceCache = /* @__PURE__ */ new Map();
35133
35380
  /** Series boundaries per pane as of the last `prepareSlices` — lets a repaint between data
@@ -35215,7 +35462,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
35215
35462
  selectedIds: () => this.selectedIds,
35216
35463
  emit: (i) => this.emit(i),
35217
35464
  changed: () => {
35218
- this.invalidateSlices();
35465
+ this.syncLift();
35219
35466
  this.render();
35220
35467
  },
35221
35468
  openSettings: (id, x, y) => this.openSettingsById(id, x, y),
@@ -35841,6 +36088,20 @@ ${overlayScrollbarCss(".vela-sd-pane")}
35841
36088
  /** A drawing that paints inside the series stack changed (content, not hover): its pixels
35842
36089
  * live in the backend composite, so this layer alone can't show the change — ask for a
35843
36090
  * data frame, which re-runs `prepareSlices` before the backend composites. */
36091
+ /** A drawing being dragged leaves its interleave slice for the top canvas, so each pointer
36092
+ * move repaints one 2D layer instead of re-rasterizing and re-uploading a plot-sized slice
36093
+ * texture through the data frame. The slices rebuild once as the drag starts and once as it
36094
+ * ends (release, cancel), when the lifted set changes. */
36095
+ syncLift() {
36096
+ const moving = this.interaction.movingIds();
36097
+ let same = moving.size === this.lifted.size;
36098
+ if (same) {
36099
+ for (const id of moving) if (!this.lifted.has(id)) same = false;
36100
+ }
36101
+ if (same) return;
36102
+ this.lifted = new Set(moving);
36103
+ this.invalidateSlices();
36104
+ }
35844
36105
  invalidateSlices() {
35845
36106
  if (this.sliced.size > 0 || this.drawings.some((d) => this.isInterleaved(d))) this.deps.requestDataPaint();
35846
36107
  }
@@ -35859,7 +36120,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
35859
36120
  const theme = this.deps.theme();
35860
36121
  const buckets = /* @__PURE__ */ new Map();
35861
36122
  for (const d of this.drawings) {
35862
- if (!d.visible) continue;
36123
+ if (!d.visible || this.lifted.has(d.id)) continue;
35863
36124
  const beforeZ = sliceKeyFor(d.zIndex, this.lastBounds.get(d.paneId) ?? []);
35864
36125
  if (beforeZ === null) continue;
35865
36126
  const key = `${d.paneId}|${beforeZ}`;
@@ -35911,8 +36172,9 @@ ${overlayScrollbarCss(".vela-sd-pane")}
35911
36172
  mutedLabel: edited instanceof TextLabel ? edited.id : null
35912
36173
  };
35913
36174
  this.painter.seriesLook = this.deps.seriesLook();
35914
- this.painter.paintAll(ctx, this.drawings.filter((d) => !this.isInterleaved(d)), proj, this.deps.theme(), targets);
35915
- this.painter.paintHighlights(ctx, this.drawings.filter((d) => this.isInterleaved(d)), proj, handleIdsFor(targets));
36175
+ const onTop = (d) => !this.isInterleaved(d) || this.lifted.has(d.id);
36176
+ this.painter.paintAll(ctx, this.drawings.filter(onTop), proj, this.deps.theme(), targets);
36177
+ this.painter.paintHighlights(ctx, this.drawings.filter((d) => !onTop(d)), proj, handleIdsFor(targets));
35916
36178
  const clones = this.interaction.dragClones();
35917
36179
  if (clones) this.painter.paintAll(ctx, clones, proj, this.deps.theme(), { selected: new Set(clones.map((c) => c.id)) });
35918
36180
  this.layoutTextEditor();
@@ -37189,23 +37451,21 @@ ${overlayScrollbarCss(".vela-sd-pane")}
37189
37451
  return { below, above };
37190
37452
  }
37191
37453
 
37192
- // src/renderers/native/chrome/luxalgo-logos.ts
37193
- 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>';
37194
- 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>';
37454
+ // src/renderers/native/chrome/vela-logos.ts
37455
+ 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>';
37456
+ 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>';
37195
37457
 
37196
37458
  // src/renderers/native/chrome/AttributionMark.ts
37197
- var ATTRIBUTION_URL = "https://luxalgo.com/vela";
37459
+ var ATTRIBUTION_URL = "https://velacharts.dev/?utm_source=vela&utm_medium=attribution";
37198
37460
  var STYLE_ID5 = "vela-attribution-styles";
37199
37461
  var CSS2 = `
37200
37462
  .vela-attribution {
37201
37463
  text-decoration: none;
37202
37464
  display: flex;
37203
37465
  align-items: center;
37204
- /* Gutter, wordmark size and offset below are the brand lockup's own ratios,
37205
- measured off the official horizontal logo: gutter 0.157, wordmark height
37206
- 0.966, and wordmark 0.109 LOWER than the symbol \u2014 box-centering the two
37207
- reads wrong because the symbol's ink hangs low and the wordmark descends. */
37208
- gap: 4px;
37466
+ /* No gutter: the V is the wordmark's first letter, and the letters' viewBox starts
37467
+ where the V's ends, so the kit's own letter spacing comes with them. */
37468
+ gap: 0;
37209
37469
  }
37210
37470
  .vela-attribution .vela-attr-symbol {
37211
37471
  flex: none;
@@ -37213,7 +37473,7 @@ ${overlayScrollbarCss(".vela-sd-pane")}
37213
37473
  line-height: 0;
37214
37474
  }
37215
37475
  .vela-attribution .vela-attr-symbol svg {
37216
- height: 28px;
37476
+ height: 24px;
37217
37477
  width: auto;
37218
37478
  display: block;
37219
37479
  filter: drop-shadow(0 1px 2px var(--vela-attr-shadow, rgba(0,0,0,0.45)));
@@ -37224,15 +37484,13 @@ ${overlayScrollbarCss(".vela-sd-pane")}
37224
37484
  opacity: 0;
37225
37485
  display: flex;
37226
37486
  align-items: center;
37227
- /* Offset here, not on the image: the clip box must not crop the descender. */
37228
- position: relative;
37229
- top: 3px;
37487
+ /* Same height and baseline as the V (one viewBox height), so no vertical offset. */
37230
37488
  transform: translateX(-8px);
37231
37489
  transition: max-width 0.3s ease, opacity 0.25s ease, transform 0.3s ease;
37232
37490
  flex: none;
37233
37491
  }
37234
37492
  .vela-attribution .vela-attr-wordmark svg {
37235
- height: 27px;
37493
+ height: 24px;
37236
37494
  width: auto;
37237
37495
  display: block;
37238
37496
  filter: drop-shadow(0 1px 2px var(--vela-attr-shadow, rgba(0,0,0,0.45)));
@@ -37247,14 +37505,11 @@ ${overlayScrollbarCss(".vela-sd-pane")}
37247
37505
  (data-layout): the workspace's single grid-wide mark lives OUTSIDE any renderer
37248
37506
  container, so only the shell attribute reaches it. */
37249
37507
  [data-vela-layout='mobile'] .vela-attribution .vela-attr-symbol svg,
37250
- [data-layout='mobile'] .vela-attribution .vela-attr-symbol svg { height: 22px; }
37508
+ [data-layout='mobile'] .vela-attribution .vela-attr-symbol svg { height: 20px; }
37251
37509
  [data-vela-layout='mobile'] .vela-attribution .vela-attr-wordmark,
37252
- [data-layout='mobile'] .vela-attribution .vela-attr-wordmark {
37253
- top: 2px;
37254
- transform: translateX(-6px);
37255
- }
37510
+ [data-layout='mobile'] .vela-attribution .vela-attr-wordmark { transform: translateX(-6px); }
37256
37511
  [data-vela-layout='mobile'] .vela-attribution .vela-attr-wordmark svg,
37257
- [data-layout='mobile'] .vela-attribution .vela-attr-wordmark svg { height: 21px; }
37512
+ [data-layout='mobile'] .vela-attribution .vela-attr-wordmark svg { height: 20px; }
37258
37513
  [data-vela-layout='mobile'] .vela-attribution:hover .vela-attr-wordmark,
37259
37514
  [data-layout='mobile'] .vela-attribution:hover .vela-attr-wordmark { transform: translateX(0); }
37260
37515
  `;
@@ -37311,10 +37566,10 @@ ${overlayScrollbarCss(".vela-sd-pane")}
37311
37566
  const symbol = doc.createElement("span");
37312
37567
  symbol.className = "vela-attr-symbol";
37313
37568
  symbol.setAttribute("aria-hidden", "true");
37314
- symbol.innerHTML = LUXALGO_SYMBOL_SVG;
37569
+ symbol.innerHTML = VELA_MARK_SVG;
37315
37570
  const wordmark = doc.createElement("span");
37316
37571
  wordmark.className = "vela-attr-wordmark";
37317
- wordmark.innerHTML = LUXALGO_WORDMARK_SVG;
37572
+ wordmark.innerHTML = VELA_LETTERS_SVG;
37318
37573
  a.append(symbol, wordmark);
37319
37574
  return a;
37320
37575
  }