@trdrs/quickcharts 2.4.0 → 3.0.0

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 (75) hide show
  1. package/CHANGELOG.md +20 -0
  2. package/README.md +97 -7
  3. package/dist/{ar-KSXQ2USS.js → ar-HLKX6L6O.js} +2 -1
  4. package/dist/ar-HLKX6L6O.js.map +1 -0
  5. package/dist/{assets-M5emOz5c.d.ts → assets-C1VjN7DP.d.ts} +1 -0
  6. package/dist/{ca_ES-JG4FM55E.js → ca_ES-3ALUJ2FI.js} +2 -1
  7. package/dist/ca_ES-3ALUJ2FI.js.map +1 -0
  8. package/dist/{chunk-YR7NT5ZW.js → chunk-DBJQXHLQ.js} +8 -2
  9. package/dist/{chunk-YR7NT5ZW.js.map → chunk-DBJQXHLQ.js.map} +1 -1
  10. package/dist/{de-VSW2LHNF.js → de-GXKOZYHP.js} +2 -1
  11. package/dist/de-GXKOZYHP.js.map +1 -0
  12. package/dist/drawings.d.ts +2 -2
  13. package/dist/drawings.js +1 -1
  14. package/dist/{es-5ZXIPVOB.js → es-R7WSUWO2.js} +2 -1
  15. package/dist/es-R7WSUWO2.js.map +1 -0
  16. package/dist/feature-manifest.json +21 -1
  17. package/dist/{fr-4F6DAWGD.js → fr-EBUMQLPT.js} +2 -1
  18. package/dist/fr-EBUMQLPT.js.map +1 -0
  19. package/dist/{he_IL-B7PBQUEV.js → he_IL-GCAXKEWB.js} +2 -1
  20. package/dist/{he_IL-B7PBQUEV.js.map → he_IL-GCAXKEWB.js.map} +1 -1
  21. package/dist/{id_ID-CYJRMXPC.js → id_ID-6JYEEKEA.js} +2 -1
  22. package/dist/id_ID-6JYEEKEA.js.map +1 -0
  23. package/dist/index.d.ts +62 -14
  24. package/dist/index.js +1490 -1402
  25. package/dist/index.js.map +1 -1
  26. package/dist/{it-KTX4SG5P.js → it-IMLHI5VO.js} +2 -1
  27. package/dist/it-IMLHI5VO.js.map +1 -0
  28. package/dist/{ja-V7OURU5D.js → ja-QDEQ2EYA.js} +2 -1
  29. package/dist/ja-QDEQ2EYA.js.map +1 -0
  30. package/dist/{ko-2RNEBYVE.js → ko-MTA7BZI3.js} +2 -1
  31. package/dist/ko-MTA7BZI3.js.map +1 -0
  32. package/dist/{ms_MY-EY235E7Q.js → ms_MY-K4EAHE5J.js} +2 -1
  33. package/dist/ms_MY-K4EAHE5J.js.map +1 -0
  34. package/dist/{pl-ADNVRP55.js → pl-CIIDQ3SB.js} +2 -1
  35. package/dist/pl-CIIDQ3SB.js.map +1 -0
  36. package/dist/{pt-OL2DR3DO.js → pt-3HA2PDUN.js} +2 -1
  37. package/dist/pt-3HA2PDUN.js.map +1 -0
  38. package/dist/quickcharts.css +254 -116
  39. package/dist/{ru-V6YFEPAF.js → ru-2F2VGHMW.js} +2 -1
  40. package/dist/ru-2F2VGHMW.js.map +1 -0
  41. package/dist/{sv-TORXQVE7.js → sv-HCBRKFRZ.js} +2 -1
  42. package/dist/sv-HCBRKFRZ.js.map +1 -0
  43. package/dist/{symbols-BL1fD4CS.d.ts → symbols-6V22WaRX.d.ts} +1 -1
  44. package/dist/symbols.d.ts +1 -1
  45. package/dist/{th-K6SJSYSY.js → th-WWPM2QKB.js} +2 -1
  46. package/dist/th-WWPM2QKB.js.map +1 -0
  47. package/dist/theme-manifest.json +56 -2
  48. package/dist/{tr-4AEM66KW.js → tr-M57AMCWK.js} +2 -1
  49. package/dist/tr-M57AMCWK.js.map +1 -0
  50. package/dist/{vi-YU5XCEUU.js → vi-YJHN2OK7.js} +2 -1
  51. package/dist/vi-YJHN2OK7.js.map +1 -0
  52. package/dist/{zh-QXKRYHU5.js → zh-AIFC65OE.js} +2 -1
  53. package/dist/zh-AIFC65OE.js.map +1 -0
  54. package/dist/{zh_TW-AYPDKG4Q.js → zh_TW-2LLLW4H6.js} +2 -1
  55. package/dist/zh_TW-2LLLW4H6.js.map +1 -0
  56. package/package.json +1 -1
  57. package/dist/ar-KSXQ2USS.js.map +0 -1
  58. package/dist/ca_ES-JG4FM55E.js.map +0 -1
  59. package/dist/de-VSW2LHNF.js.map +0 -1
  60. package/dist/es-5ZXIPVOB.js.map +0 -1
  61. package/dist/fr-4F6DAWGD.js.map +0 -1
  62. package/dist/id_ID-CYJRMXPC.js.map +0 -1
  63. package/dist/it-KTX4SG5P.js.map +0 -1
  64. package/dist/ja-V7OURU5D.js.map +0 -1
  65. package/dist/ko-2RNEBYVE.js.map +0 -1
  66. package/dist/ms_MY-EY235E7Q.js.map +0 -1
  67. package/dist/pl-ADNVRP55.js.map +0 -1
  68. package/dist/pt-OL2DR3DO.js.map +0 -1
  69. package/dist/ru-V6YFEPAF.js.map +0 -1
  70. package/dist/sv-TORXQVE7.js.map +0 -1
  71. package/dist/th-K6SJSYSY.js.map +0 -1
  72. package/dist/tr-4AEM66KW.js.map +0 -1
  73. package/dist/vi-YU5XCEUU.js.map +0 -1
  74. package/dist/zh-QXKRYHU5.js.map +0 -1
  75. package/dist/zh_TW-AYPDKG4Q.js.map +0 -1
package/dist/index.js CHANGED
@@ -82,7 +82,7 @@ import {
82
82
  viewportOf,
83
83
  visibilityPreset,
84
84
  withAlpha
85
- } from "./chunk-YR7NT5ZW.js";
85
+ } from "./chunk-DBJQXHLQ.js";
86
86
  import {
87
87
  ResourceAbortError,
88
88
  memorySaveLoadAdapter
@@ -1267,6 +1267,9 @@ var search = {
1267
1267
  // The asset-class filter strip: the chip for every class, and the strip's own name.
1268
1268
  "search.allClasses": "All",
1269
1269
  "search.classFilter": "Asset class",
1270
+ /** The scope chip's accessible name: what pressing it does. `{scope}` is the host's name for the
1271
+ * scope, which the chip shows; whether the limit stands is the chip's pressed state. */
1272
+ "search.limitToScope": "Limit search to {scope}",
1270
1273
  // The spread operators' names, each for the arithmetic it inserts, and the strip's toggle.
1271
1274
  "search.opDivision": "Division",
1272
1275
  "search.opSubtraction": "Subtraction",
@@ -1904,26 +1907,26 @@ function readingDirection(i18n) {
1904
1907
  return BUILT_IN_LOCALES.find((l) => l.code === i18n.locale())?.dir ?? "ltr";
1905
1908
  }
1906
1909
  var chartDictionaries = createDictionaryLoader(en, {
1907
- de: () => import("./de-VSW2LHNF.js"),
1908
- fr: () => import("./fr-4F6DAWGD.js"),
1909
- es: () => import("./es-5ZXIPVOB.js"),
1910
- it: () => import("./it-KTX4SG5P.js"),
1911
- ca_ES: () => import("./ca_ES-JG4FM55E.js"),
1912
- pl: () => import("./pl-ADNVRP55.js"),
1913
- sv: () => import("./sv-TORXQVE7.js"),
1914
- tr: () => import("./tr-4AEM66KW.js"),
1915
- ru: () => import("./ru-V6YFEPAF.js"),
1916
- pt: () => import("./pt-OL2DR3DO.js"),
1917
- id_ID: () => import("./id_ID-CYJRMXPC.js"),
1918
- ms_MY: () => import("./ms_MY-EY235E7Q.js"),
1919
- th: () => import("./th-K6SJSYSY.js"),
1920
- vi: () => import("./vi-YU5XCEUU.js"),
1921
- ja: () => import("./ja-V7OURU5D.js"),
1922
- ko: () => import("./ko-2RNEBYVE.js"),
1923
- zh: () => import("./zh-QXKRYHU5.js"),
1924
- zh_TW: () => import("./zh_TW-AYPDKG4Q.js"),
1925
- ar: () => import("./ar-KSXQ2USS.js"),
1926
- he_IL: () => import("./he_IL-B7PBQUEV.js")
1910
+ de: () => import("./de-GXKOZYHP.js"),
1911
+ fr: () => import("./fr-EBUMQLPT.js"),
1912
+ es: () => import("./es-R7WSUWO2.js"),
1913
+ it: () => import("./it-IMLHI5VO.js"),
1914
+ ca_ES: () => import("./ca_ES-3ALUJ2FI.js"),
1915
+ pl: () => import("./pl-CIIDQ3SB.js"),
1916
+ sv: () => import("./sv-HCBRKFRZ.js"),
1917
+ tr: () => import("./tr-M57AMCWK.js"),
1918
+ ru: () => import("./ru-2F2VGHMW.js"),
1919
+ pt: () => import("./pt-3HA2PDUN.js"),
1920
+ id_ID: () => import("./id_ID-6JYEEKEA.js"),
1921
+ ms_MY: () => import("./ms_MY-K4EAHE5J.js"),
1922
+ th: () => import("./th-WWPM2QKB.js"),
1923
+ vi: () => import("./vi-YJHN2OK7.js"),
1924
+ ja: () => import("./ja-QDEQ2EYA.js"),
1925
+ ko: () => import("./ko-MTA7BZI3.js"),
1926
+ zh: () => import("./zh-AIFC65OE.js"),
1927
+ zh_TW: () => import("./zh_TW-2LLLW4H6.js"),
1928
+ ar: () => import("./ar-HLKX6L6O.js"),
1929
+ he_IL: () => import("./he_IL-GCAXKEWB.js")
1927
1930
  });
1928
1931
  var dynamic = (t) => t;
1929
1932
  var source = null;
@@ -2060,6 +2063,10 @@ var LIGHT_THEME = {
2060
2063
  "control.offHover": "#8c8c8c",
2061
2064
  "control.offPressed": "#b8b8b8",
2062
2065
  "control.mark": "#ffffff",
2066
+ "control.fieldEdge": "#dbdbdb",
2067
+ "control.fieldEdgeHover": "#a8a8a8",
2068
+ "control.fieldInvalid": "#f23645",
2069
+ "control.fieldFill": "#f2f2f2",
2063
2070
  "status.positive": "#067a67",
2064
2071
  "status.negative": "#cc2f3c",
2065
2072
  "status.warning": "#8a5a00",
@@ -2150,6 +2157,10 @@ var DARK_THEME = {
2150
2157
  "control.offHover": "#707070",
2151
2158
  "control.offPressed": "#636363",
2152
2159
  "control.mark": "#2e2e2e",
2160
+ "control.fieldEdge": "#575757",
2161
+ "control.fieldEdgeHover": "#707070",
2162
+ "control.fieldInvalid": "#f23645",
2163
+ "control.fieldFill": "#2e2e2e",
2153
2164
  "status.positive": "#089981",
2154
2165
  "status.negative": "#f7525f",
2155
2166
  "status.warning": "#f5a623",
@@ -2272,7 +2283,7 @@ var THEME_ROLES = [
2272
2283
  { id: "chrome.surfaceRaised", family: "chrome", kind: "color", description: "The fill of a control sitting on a chrome surface, such as a button or field." },
2273
2284
  { id: "chrome.border", family: "chrome", kind: "color", description: "The ordinary border of a control or panel." },
2274
2285
  { id: "chrome.borderStrong", family: "chrome", kind: "color", description: "A border or divider that must stay visible at a glance.", contrast: [{ over: "chrome.surface", min: 3 }] },
2275
- { id: "chrome.fieldBorder", family: "chrome", kind: "color", description: "The outline of a text field, such as the symbol search field. The field's mark and prompt name it, so the outline is not its only sign." },
2286
+ { id: "chrome.fieldBorder", family: "chrome", kind: "color", description: "The outline of the symbol search field. The field's mark and prompt name it, so the outline is not its only sign." },
2276
2287
  { id: "chrome.caret", family: "chrome", kind: "color", description: "The ink of the arrow that opens a control's menu or flyout.", contrast: [{ over: "chrome.surface", min: 3 }] },
2277
2288
  { id: "chrome.grip", family: "chrome", kind: "color", description: "The dots of a drag handle on a floating toolbar." },
2278
2289
  // No contrast rule: the thumb says where a list is, and the wheel, the drag and the keyboard
@@ -2323,7 +2334,7 @@ var THEME_ROLES = [
2323
2334
  contrast: [{ over: "state.accent", min: 4.5 }]
2324
2335
  },
2325
2336
  { id: "state.selection", family: "state", kind: "color", description: "The tint over selected content." },
2326
- // ── control: switches, checkboxes, and radios ───────────────────────────────────────────────
2337
+ // ── control: switches, checkboxes, radios, and fields ───────────────────────────────────────
2327
2338
  // The emphasis fill is neutral in both modes, the strong end of the grey ramp: a control that is on,
2328
2339
  // a chosen row, a held mode and the primary action all wear it. The mark a control carries is cut
2329
2340
  // from the surface end of the ramp.
@@ -2353,6 +2364,24 @@ var THEME_ROLES = [
2353
2364
  { over: "control.onPressed", min: 3 }
2354
2365
  ]
2355
2366
  },
2367
+ // A field is a box of its own: a text field, a select, a number field or a color well. Its edge
2368
+ // declares no contrast rule, as `chrome.fieldBorder` declares none: the field's label names it, so
2369
+ // the edge is not what identifies it. The invalid edge is how a refused value shows, so it reads
2370
+ // as a non-text indicator on both surfaces a field stands on. The ring a focused field wears is
2371
+ // `state.focusRing`.
2372
+ { id: "control.fieldEdge", family: "control", kind: "color", description: "The edge of a text field, a select, a number field or a color well at rest." },
2373
+ { id: "control.fieldEdgeHover", family: "control", kind: "color", description: "The edge of a field under the pointer." },
2374
+ {
2375
+ id: "control.fieldInvalid",
2376
+ family: "control",
2377
+ kind: "color",
2378
+ description: "The edge and the focus ring of a field holding a value it refuses.",
2379
+ contrast: [
2380
+ { over: "overlay.surface", min: 3 },
2381
+ { over: "chrome.surface", min: 3 }
2382
+ ]
2383
+ },
2384
+ { id: "control.fieldFill", family: "control", kind: "color", description: "The fill of a field that is read-only or disabled." },
2356
2385
  // ── status: feedback, including market session status ───────────────────────────────────────
2357
2386
  { id: "status.positive", family: "status", kind: "color", description: "A positive value or a successful outcome in chart chrome.", contrast: [{ over: "chrome.surface", min: 4.5 }] },
2358
2387
  { id: "status.negative", family: "status", kind: "color", description: "A negative value or a failed outcome in chart chrome.", contrast: [{ over: "chrome.surface", min: 4.5 }] },
@@ -2935,6 +2964,44 @@ function searchSession(datafeed, options, cache, onDispose) {
2935
2964
  inflight.set(k, ask);
2936
2965
  return ask;
2937
2966
  };
2967
+ const searchFor = (query, asked, immediate) => {
2968
+ if (disposed) return;
2969
+ const cls = settleFilter(asked);
2970
+ clearTimeout(timer);
2971
+ const nextKey = keyOf(query, cls, pageSize);
2972
+ const unchanged = key === nextKey;
2973
+ if (!unchanged) {
2974
+ cancelPending();
2975
+ }
2976
+ key = nextKey;
2977
+ filter = cls;
2978
+ const mine = key;
2979
+ const epoch = generation;
2980
+ const retained = cache.get(key);
2981
+ const cached = unchanged && current ? current : retained;
2982
+ current = cached;
2983
+ if (cached) {
2984
+ emit({ query, ...classState(cls), hits: cached.hits, hasMore: cached.hasMore, loading: false, failed: false });
2985
+ if (cached.pages > 1) return;
2986
+ } else {
2987
+ emit({ query, ...classState(cls), loading: true, failed: false });
2988
+ }
2989
+ if (disposed || generation !== epoch || key !== mine) return;
2990
+ const run = () => {
2991
+ if (disposed || generation !== epoch || key !== mine) return;
2992
+ load(mine, query, cls).then((loaded) => {
2993
+ if (disposed || generation !== epoch || key !== mine) return;
2994
+ current = current && current.pages > loaded.pages ? current : loaded;
2995
+ emit({ hits: current.hits, hasMore: current.hasMore, loading: false, failed: false });
2996
+ }).catch(() => {
2997
+ if (disposed || generation !== epoch || key !== mine) return;
2998
+ if (current) emit({ loading: false });
2999
+ else emit({ hits: [], hasMore: false, loading: false, failed: true });
3000
+ });
3001
+ };
3002
+ if (immediate || inflight.has(mine)) run();
3003
+ else timer = setTimeout(run, debounceMs);
3004
+ };
2938
3005
  const controller = {
2939
3006
  state: () => state,
2940
3007
  subscribe(listener) {
@@ -2946,42 +3013,7 @@ function searchSession(datafeed, options, cache, onDispose) {
2946
3013
  };
2947
3014
  },
2948
3015
  search(query, asked = "") {
2949
- if (disposed) return;
2950
- const cls = settleFilter(asked);
2951
- clearTimeout(timer);
2952
- const nextKey = keyOf(query, cls, pageSize);
2953
- const unchanged = key === nextKey;
2954
- if (!unchanged) {
2955
- cancelPending();
2956
- }
2957
- key = nextKey;
2958
- filter = cls;
2959
- const mine = key;
2960
- const epoch = generation;
2961
- const retained = cache.get(key);
2962
- const cached = unchanged && current ? current : retained;
2963
- current = cached;
2964
- if (cached) {
2965
- emit({ query, ...classState(cls), hits: cached.hits, hasMore: cached.hasMore, loading: false, failed: false });
2966
- if (cached.pages > 1) return;
2967
- } else {
2968
- emit({ query, ...classState(cls), loading: true, failed: false });
2969
- }
2970
- if (disposed || generation !== epoch || key !== mine) return;
2971
- const run = () => {
2972
- if (disposed || generation !== epoch || key !== mine) return;
2973
- load(mine, query, cls).then((loaded) => {
2974
- if (disposed || generation !== epoch || key !== mine) return;
2975
- current = current && current.pages > loaded.pages ? current : loaded;
2976
- emit({ hits: current.hits, hasMore: current.hasMore, loading: false, failed: false });
2977
- }).catch(() => {
2978
- if (disposed || generation !== epoch || key !== mine) return;
2979
- if (current) emit({ loading: false });
2980
- else emit({ hits: [], hasMore: false, loading: false, failed: true });
2981
- });
2982
- };
2983
- if (inflight.has(mine)) run();
2984
- else timer = setTimeout(run, debounceMs);
3016
+ searchFor(query, asked, false);
2985
3017
  },
2986
3018
  loadMore() {
2987
3019
  if (disposed || state.loading) return;
@@ -3022,7 +3054,11 @@ function searchSession(datafeed, options, cache, onDispose) {
3022
3054
  onDispose();
3023
3055
  }
3024
3056
  };
3025
- return { controller, cancelPending };
3057
+ const over = (source3) => {
3058
+ const own = completedCache();
3059
+ return searchSession(source3, options, own, () => own.clear());
3060
+ };
3061
+ return { controller, cancelPending, searchNow: (query, asked = "") => searchFor(query, asked, true), over };
3026
3062
  }
3027
3063
  var RECENT_SYMBOLS_CAP = 10;
3028
3064
  function promoteRecent(list, pick, cap = RECENT_SYMBOLS_CAP) {
@@ -7575,6 +7611,21 @@ function refreshOverlays(within) {
7575
7611
  }
7576
7612
  }
7577
7613
 
7614
+ // src/ui/controls/select.ts
7615
+ function selectChevron(icons) {
7616
+ const slot = document.createElement("span");
7617
+ slot.className = "qc-select-chevron";
7618
+ slot.setAttribute("aria-hidden", "true");
7619
+ slot.appendChild(icons.icon("chevronDown18", 18));
7620
+ return slot;
7621
+ }
7622
+ function selectField(select, icons) {
7623
+ const box = document.createElement("span");
7624
+ box.className = "qc-select";
7625
+ box.append(select, selectChevron(icons));
7626
+ return box;
7627
+ }
7628
+
7578
7629
  // src/ui/drawings/fields.ts
7579
7630
  function row(label2, ...controls) {
7580
7631
  const cell2 = el("div", { class: "qc-drawing-row-controls" }, ...controls);
@@ -7593,12 +7644,12 @@ function checkbox(label2, value, onChange) {
7593
7644
  input.addEventListener("change", () => onChange(input.checked));
7594
7645
  return input;
7595
7646
  }
7596
- function dropdown(label2, options, value, labels, onChange) {
7647
+ function dropdown(icons, label2, options, value, labels, onChange) {
7597
7648
  const select = el("select", { class: "qc-field qc-drawing-select", "aria-label": label2 });
7598
7649
  for (const option of options) select.appendChild(el("option", { value: option, text: labels(option) }));
7599
7650
  select.value = value;
7600
7651
  select.addEventListener("change", () => onChange(select.value));
7601
- return select;
7652
+ return selectField(select, icons);
7602
7653
  }
7603
7654
  function numberInput(t, icons, props) {
7604
7655
  const input = el("input", { type: "number", class: "qc-field qc-drawing-number", "aria-label": props.label });
@@ -7750,6 +7801,7 @@ function strokeRows(t, content, options) {
7750
7801
  function lineEndButton(t, icons, box, side, value, onChange) {
7751
7802
  const face = (v) => icons.icon(v === "normal" ? "lineEndNormal" : "lineEndArrow");
7752
7803
  const b = button({ class: "qc-field qc-drawing-line-end", label: t(side === "left" ? "drawing.leftEnd" : "drawing.rightEnd"), icon: face(value) });
7804
+ b.appendChild(selectChevron(icons));
7753
7805
  b.dataset.qcEnd = side;
7754
7806
  b.setAttribute("aria-haspopup", "listbox");
7755
7807
  b.setAttribute("aria-expanded", "false");
@@ -9031,7 +9083,7 @@ function openNameDialog(options) {
9031
9083
  append(
9032
9084
  box,
9033
9085
  ...promptHead(t, options.icons, options.title, () => dialog.close()),
9034
- h("label", { class: "qc-name-field" }, h("span", { class: "qc-name-label" }, options.label), h("span", { class: "qc-name-box" }, field)),
9086
+ h("label", { class: "qc-name-field" }, h("span", { class: "qc-name-label" }, options.label), h("span", { class: "qc-field qc-name-box" }, field)),
9035
9087
  h("div", { class: "qc-prompt-actions" }, button2({ label: t("layouts.cancel"), text: t("layouts.cancel"), className: "qc-button--secondary", onClick: () => dialog.close() }), verb)
9036
9088
  );
9037
9089
  },
@@ -9620,29 +9672,30 @@ function mountTextEditor(session2, deps) {
9620
9672
 
9621
9673
  // src/ui/drawings/dialog.ts
9622
9674
  function dragBy(header, box) {
9623
- let dragging = null;
9675
+ let stop = null;
9624
9676
  header.addEventListener("pointerdown", (event) => {
9625
9677
  if (event.target.closest("button")) return;
9678
+ stop?.();
9626
9679
  const rect = box.getBoundingClientRect();
9627
- dragging = { dx: event.clientX - rect.left, dy: event.clientY - rect.top };
9680
+ const dx = event.clientX - rect.left;
9681
+ const dy = event.clientY - rect.top;
9682
+ stop = dragUntilRelease(
9683
+ (move) => {
9684
+ const x = Math.max(0, Math.min(move.clientX - dx, window.innerWidth - box.offsetWidth));
9685
+ const y = Math.max(0, Math.min(move.clientY - dy, window.innerHeight - box.offsetHeight));
9686
+ box.style.position = "fixed";
9687
+ box.style.left = `${Math.round(x)}px`;
9688
+ box.style.top = `${Math.round(y)}px`;
9689
+ },
9690
+ () => {
9691
+ stop = null;
9692
+ }
9693
+ );
9628
9694
  event.preventDefault();
9629
9695
  });
9630
- const onMove = (event) => {
9631
- if (!dragging) return;
9632
- const x = Math.max(0, Math.min(event.clientX - dragging.dx, window.innerWidth - box.offsetWidth));
9633
- const y = Math.max(0, Math.min(event.clientY - dragging.dy, window.innerHeight - box.offsetHeight));
9634
- box.style.position = "fixed";
9635
- box.style.left = `${Math.round(x)}px`;
9636
- box.style.top = `${Math.round(y)}px`;
9637
- };
9638
- const onUp = () => {
9639
- dragging = null;
9640
- };
9641
- window.addEventListener("pointermove", onMove);
9642
- window.addEventListener("pointerup", onUp);
9643
9696
  return () => {
9644
- window.removeEventListener("pointermove", onMove);
9645
- window.removeEventListener("pointerup", onUp);
9697
+ stop?.();
9698
+ stop = null;
9646
9699
  };
9647
9700
  }
9648
9701
  function openDialog2(options) {
@@ -9861,7 +9914,7 @@ function styleRows(ctx) {
9861
9914
  const inertKeys = new Set(INERT_PROPS[type] ?? []);
9862
9915
  const sect = (key) => key in props && !inertKeys.has(key) && (inputKeys.has(key) ? tab === "Inputs" : tab === "Style");
9863
9916
  const out = [];
9864
- const fontSize = () => dropdown(t("drawing.fontSize"), FONT_SIZES2, String(style.fontSize), (v) => v, (v) => ctx.patchStyle({ fontSize: Number(v) }));
9917
+ const fontSize = () => dropdown(ctx.icons, t("drawing.fontSize"), FONT_SIZES2, String(style.fontSize), (v) => v, (v) => ctx.patchStyle({ fontSize: Number(v) }));
9865
9918
  const toggle = (key, text2) => {
9866
9919
  if (sect(key)) out.push(toggleRow(t(text2), !!props[key], (v) => ctx.patchProps({ [key]: v })));
9867
9920
  };
@@ -9892,7 +9945,7 @@ function styleRows(ctx) {
9892
9945
  }
9893
9946
  if ("extendLeft" in props && sect("extendLeft")) {
9894
9947
  const value = props.extendLeft && props.extendRight ? "Both" : props.extendLeft ? "Left" : props.extendRight ? "Right" : "None";
9895
- out.push(row(t("drawing.extend"), dropdown(t("drawing.extend"), ["None", "Left", "Right", "Both"], value, label(t, EXTEND_LABEL), (v) => ctx.patchProps({ extendLeft: v === "Left" || v === "Both", extendRight: v === "Right" || v === "Both" }))));
9948
+ out.push(row(t("drawing.extend"), dropdown(ctx.icons, t("drawing.extend"), ["None", "Left", "Right", "Both"], value, label(t, EXTEND_LABEL), (v) => ctx.patchProps({ extendLeft: v === "Left" || v === "Both", extendRight: v === "Right" || v === "Both" }))));
9896
9949
  }
9897
9950
  toggle("middlePoint", "drawing.middlePoint");
9898
9951
  toggle("showPriceLabels", "drawing.priceLabels");
@@ -9900,7 +9953,7 @@ function styleRows(ctx) {
9900
9953
  toggle("showTime", "drawing.timeLabel");
9901
9954
  toggle("middleLine", "drawing.middleLine");
9902
9955
  if (sect("variant")) {
9903
- out.push(row(t("drawing.rowStyle"), dropdown(t("drawing.rowStyle"), ["original", "schiff", "modified_schiff", "inside"], props.variant, label(t, VARIANT_LABEL), (v) => ctx.patchProps({ variant: v }))));
9956
+ out.push(row(t("drawing.rowStyle"), dropdown(ctx.icons, t("drawing.rowStyle"), ["original", "schiff", "modified_schiff", "inside"], props.variant, label(t, VARIANT_LABEL), (v) => ctx.patchProps({ variant: v }))));
9904
9957
  }
9905
9958
  if (sect("showPriceDelta")) {
9906
9959
  out.push(el("div", { class: "qc-dialog-heading", text: t("drawing.sectionStats") }));
@@ -9924,10 +9977,10 @@ function styleRows(ctx) {
9924
9977
  toggleRow(t("drawing.barsRange"), !!props.showBarsRange, (v) => ctx.patchProps({ showBarsRange: v })),
9925
9978
  toggleRow(t("drawing.dateTimeRange"), !!props.showDateTimeRange, (v) => ctx.patchProps({ showDateTimeRange: v })),
9926
9979
  toggleRow(t("drawing.angle"), !!props.showAngle, (v) => ctx.patchProps({ showAngle: v })),
9927
- row(t("drawing.statsPosition"), dropdown(t("drawing.statsPosition"), ["left", "center", "right"], props.statsPosition, label(t, SIDE_LABEL), (v) => ctx.patchProps({ statsPosition: v })))
9980
+ row(t("drawing.statsPosition"), dropdown(ctx.icons, t("drawing.statsPosition"), ["left", "center", "right"], props.statsPosition, label(t, SIDE_LABEL), (v) => ctx.patchProps({ statsPosition: v })))
9928
9981
  );
9929
9982
  }
9930
- if (sect("direction")) out.push(row(t("drawing.direction"), dropdown(t("drawing.direction"), ["up", "down"], props.direction, label(t, UPDOWN_LABEL), (v) => ctx.patchProps({ direction: v }))));
9983
+ if (sect("direction")) out.push(row(t("drawing.direction"), dropdown(ctx.icons, t("drawing.direction"), ["up", "down"], props.direction, label(t, UPDOWN_LABEL), (v) => ctx.patchProps({ direction: v }))));
9931
9984
  toggle("showPrices", "drawing.prices");
9932
9985
  toggle("showLevels", "drawing.levels");
9933
9986
  toggle("reverse", "drawing.reverse");
@@ -9976,9 +10029,9 @@ function styleRows(ctx) {
9976
10029
  if (sect("url")) out.push(row(t("drawing.link"), textField(String(props.url ?? ""), t("drawing.link"), (v) => ctx.patchQuiet({ url: v }), { wide: true })));
9977
10030
  if (sect("rowsLayout")) {
9978
10031
  out.push(
9979
- row(t("drawing.rowsLayout"), dropdown(t("drawing.rowsLayout"), ["number", "ticks"], props.rowsLayout, label(t, ROWS_LAYOUT_LABEL), (v) => ctx.patchProps({ rowsLayout: v }))),
10032
+ row(t("drawing.rowsLayout"), dropdown(ctx.icons, t("drawing.rowsLayout"), ["number", "ticks"], props.rowsLayout, label(t, ROWS_LAYOUT_LABEL), (v) => ctx.patchProps({ rowsLayout: v }))),
9980
10033
  row(t("drawing.rowSize"), numberInput(t, ctx.icons, { label: t("drawing.rowSize"), value: Number(props.rowSize), min: 1, max: 400, step: 1, onChange: (v) => ctx.patchProps({ rowSize: v }) })),
9981
- row(t("drawing.volume"), dropdown(t("drawing.volume"), ["updown", "total", "delta"], props.volume, label(t, PROFILE_VOLUME_LABEL), (v) => ctx.patchProps({ volume: v }))),
10034
+ row(t("drawing.volume"), dropdown(ctx.icons, t("drawing.volume"), ["updown", "total", "delta"], props.volume, label(t, PROFILE_VOLUME_LABEL), (v) => ctx.patchProps({ volume: v }))),
9982
10035
  row(t("drawing.valueAreaVolume"), numberInput(t, ctx.icons, { label: t("drawing.valueAreaVolume"), value: Number(props.valueAreaVolume), min: 0, max: 95, step: 5, onChange: (v) => ctx.patchProps({ valueAreaVolume: v }) }))
9983
10036
  );
9984
10037
  if ("extendRight" in props) out.push(toggleRow(t("drawing.extendRight"), !!props.extendRight, (v) => ctx.patchProps({ extendRight: v })));
@@ -9986,7 +10039,7 @@ function styleRows(ctx) {
9986
10039
  if ("rowsLayout" in props && tab === "Style") {
9987
10040
  out.push(
9988
10041
  row(t("drawing.widthPercent"), numberInput(t, ctx.icons, { label: t("drawing.widthPercent"), value: Number(props.widthPercent), min: 5, max: 100, step: 5, onChange: (v) => ctx.patchProps({ widthPercent: v }) })),
9989
- row(t("drawing.placement"), dropdown(t("drawing.placement"), ["left", "right"], props.placement, label(t, SIDE_LABEL), (v) => ctx.patchProps({ placement: v }))),
10042
+ row(t("drawing.placement"), dropdown(ctx.icons, t("drawing.placement"), ["left", "right"], props.placement, label(t, SIDE_LABEL), (v) => ctx.patchProps({ placement: v }))),
9990
10043
  row(t("drawing.upDownVolume"), swatch("upColor"), swatch("downColor")),
9991
10044
  row(t("drawing.valueAreaUpDown"), swatch("valueAreaUpColor"), swatch("valueAreaDownColor"))
9992
10045
  );
@@ -9996,17 +10049,17 @@ function styleRows(ctx) {
9996
10049
  t(level.label),
9997
10050
  checkbox(t("drawing.rowVisible", { name: t(level.label) }), !!props[`${level.key}Visible`], (v) => ctx.patchProps({ [`${level.key}Visible`]: v })),
9998
10051
  swatch(`${level.key}Color`),
9999
- dropdown(t("drawing.thickness"), ["1", "2", "3", "4"], String(Math.min(4, Number(props[`${level.key}Width`]) || 1)), (v) => `${v}px`, (v) => ctx.patchProps({ [`${level.key}Width`]: Number(v) })),
10000
- dropdown(t("drawing.lineStyle"), ["solid", "dashed", "dotted"], props[`${level.key}Style`], (v) => t(v === "solid" ? "drawing.lineSolid" : v === "dashed" ? "drawing.lineDashed" : "drawing.lineDotted"), (v) => ctx.patchProps({ [`${level.key}Style`]: v }))
10052
+ dropdown(ctx.icons, t("drawing.thickness"), ["1", "2", "3", "4"], String(Math.min(4, Number(props[`${level.key}Width`]) || 1)), (v) => `${v}px`, (v) => ctx.patchProps({ [`${level.key}Width`]: Number(v) })),
10053
+ dropdown(ctx.icons, t("drawing.lineStyle"), ["solid", "dashed", "dotted"], props[`${level.key}Style`], (v) => t(v === "solid" ? "drawing.lineSolid" : v === "dashed" ? "drawing.lineDashed" : "drawing.lineDotted"), (v) => ctx.patchProps({ [`${level.key}Style`]: v }))
10001
10054
  )
10002
10055
  );
10003
10056
  }
10004
10057
  out.push(toggleRow(t("drawing.developingPoc"), !!props.developingPoc, (v) => ctx.patchProps({ developingPoc: v })), toggleRow(t("drawing.developingVa"), !!props.developingVa, (v) => ctx.patchProps({ developingVa: v })));
10005
10058
  }
10006
10059
  if (sect("source")) {
10007
- out.push(row(t("drawing.source"), dropdown(t("drawing.source"), ["close", "open", "hl2", "hlc3"], props.source, (v) => v, (v) => ctx.patchProps({ source: v }))));
10060
+ out.push(row(t("drawing.source"), dropdown(ctx.icons, t("drawing.source"), ["close", "open", "hl2", "hlc3"], props.source, (v) => v, (v) => ctx.patchProps({ source: v }))));
10008
10061
  }
10009
- if (sect("mode")) out.push(row(t("drawing.mode"), dropdown(t("drawing.mode"), ["bars", "open", "high", "low", "close", "hl2"], props.mode, label(t, MODE_LABEL), (v) => ctx.patchProps({ mode: v }))));
10062
+ if (sect("mode")) out.push(row(t("drawing.mode"), dropdown(ctx.icons, t("drawing.mode"), ["bars", "open", "high", "low", "close", "hl2"], props.mode, label(t, MODE_LABEL), (v) => ctx.patchProps({ mode: v }))));
10010
10063
  toggle("mirrored", "drawing.mirrored");
10011
10064
  toggle("flipped", "drawing.flipped");
10012
10065
  if (sect("successBackColor")) {
@@ -10045,7 +10098,7 @@ function styleRows(ctx) {
10045
10098
  row(
10046
10099
  t("drawing.risk"),
10047
10100
  numberInput(t, ctx.icons, { label: t("drawing.risk"), value: Number(props.risk), onChange: (v) => ctx.patchProps({ risk: v }) }),
10048
- dropdown(t("drawing.risk"), ["percent", "money"], props.riskDisplay, (v) => v === "percent" ? "%" : "$", (v) => ctx.patchProps({ riskDisplay: v }))
10101
+ dropdown(ctx.icons, t("drawing.risk"), ["percent", "money"], props.riskDisplay, (v) => v === "percent" ? "%" : "$", (v) => ctx.patchProps({ riskDisplay: v }))
10049
10102
  ),
10050
10103
  row(t("drawing.lotSize"), numberInput(t, ctx.icons, { label: t("drawing.lotSize"), value: Number(props.lotSize), min: 0, step: 0.01, onChange: (v) => ctx.patchProps({ lotSize: v }) })),
10051
10104
  row(t("drawing.leverage"), numberInput(t, ctx.icons, { label: t("drawing.leverage"), value: Number(props.leverage), min: 1, max: 500, step: 1, onChange: (v) => ctx.patchProps({ leverage: v }) })),
@@ -10106,11 +10159,11 @@ function textRows(ctx) {
10106
10159
  const alpha = alphaOf(style.textColor);
10107
10160
  ctx.patchStyle({ textColor: alpha < 1 ? withAlpha(c, alpha) : c });
10108
10161
  }, opacity: alphaOf(style.textColor), onOpacity: (v) => ctx.patchStyle({ textColor: withAlpha(style.textColor, v) }) })),
10109
- row(t("drawing.size"), dropdown(t("drawing.size"), FONT_SIZES2, String(style.fontSize), (v) => v, (v) => ctx.patchStyle({ fontSize: Number(v) }))),
10162
+ row(t("drawing.size"), dropdown(ctx.icons, t("drawing.size"), FONT_SIZES2, String(style.fontSize), (v) => v, (v) => ctx.patchStyle({ fontSize: Number(v) }))),
10110
10163
  row(t("drawing.weight"), weight(style.bold, "B", t("drawing.bold"), () => ctx.patchStyle({ bold: !style.bold })), weight(style.italic, "I", t("drawing.italic"), () => ctx.patchStyle({ italic: !style.italic }))),
10111
10164
  area
10112
10165
  ];
10113
- if ("align" in props) out.push(row(t("drawing.alignment"), dropdown(t("drawing.alignment"), ["left", "center"], props.align, label(t, SIDE_LABEL), (v) => ctx.patchProps({ align: v }))));
10166
+ if ("align" in props) out.push(row(t("drawing.alignment"), dropdown(ctx.icons, t("drawing.alignment"), ["left", "center"], props.align, label(t, SIDE_LABEL), (v) => ctx.patchProps({ align: v }))));
10114
10167
  if (NO_STYLE_TAB.has(drawing2.type)) {
10115
10168
  out.push(row(t("drawing.background"), swatchButton(t, box, { label: t("drawing.background"), value: style.fillColor, onPick: (c) => ctx.patchStyle({ fillColor: c, ...style.fillOpacity === 0 ? { fillOpacity: 0.95 } : {} }), opacity: style.fillOpacity, onOpacity: (v) => ctx.patchStyle({ fillOpacity: v }) })));
10116
10169
  if (drawing2.type !== "text") {
@@ -14093,1353 +14146,1358 @@ function mountChartLegend(container, strings, controls) {
14093
14146
  };
14094
14147
  }
14095
14148
 
14096
- // src/inputsEditor.ts
14097
- var titleOf = (key, titles) => titles?.[key] ?? key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/^./, (c) => c.toUpperCase());
14098
- function buildInputFields(inputs2, current, titles) {
14099
- const fields = /* @__PURE__ */ new Map();
14100
- const rows2 = [];
14101
- for (const [key, spec] of Object.entries(inputs2)) {
14102
- const row2 = document.createElement("label");
14103
- row2.className = "qc-inputs-row";
14104
- const name2 = document.createElement("span");
14105
- name2.textContent = titleOf(key, titles);
14106
- row2.appendChild(name2);
14107
- if (spec.kind === "enum") {
14108
- const select = document.createElement("select");
14109
- select.className = "qc-field qc-inputs-select";
14110
- (spec.options ?? []).forEach((label2, i) => {
14111
- const o = document.createElement("option");
14112
- o.value = String(i);
14113
- o.textContent = label2;
14114
- select.appendChild(o);
14115
- });
14116
- select.value = String(current[key] ?? spec.default);
14117
- fields.set(key, select);
14118
- row2.appendChild(select);
14119
- } else {
14120
- const input = document.createElement("input");
14121
- input.type = "number";
14122
- input.className = "qc-field qc-inputs-field";
14123
- if (spec.min !== void 0) input.min = String(spec.min);
14124
- if (spec.max !== void 0) input.max = String(spec.max);
14125
- input.step = spec.kind === "int" ? "1" : "any";
14126
- input.value = String(current[key] ?? spec.default);
14127
- fields.set(key, input);
14128
- row2.appendChild(input);
14129
- }
14130
- rows2.push(row2);
14149
+ // src/ui/icons/draw.ts
14150
+ var SVG_NS2 = "http://www.w3.org/2000/svg";
14151
+ var answered = /* @__PURE__ */ new WeakSet();
14152
+ var isSvg = (node) => typeof node === "object" && node !== null && node.nodeType === 1 && node.namespaceURI === SVG_NS2 && node.localName === "svg";
14153
+ var FAILURE_TEXT = {
14154
+ threw: "the factory threw",
14155
+ "not-svg": "the factory answered something other than an <svg> element",
14156
+ "in-use": "the factory answered an element already in a document or answered before"
14157
+ };
14158
+ function drawHostIcon(factory, context) {
14159
+ let node;
14160
+ try {
14161
+ node = factory(context);
14162
+ } catch {
14163
+ return { failure: "threw" };
14131
14164
  }
14165
+ if (!isSvg(node)) return { failure: "not-svg" };
14166
+ if (node.parentNode !== null || answered.has(node)) return { failure: "in-use" };
14167
+ answered.add(node);
14168
+ node.setAttribute("width", String(context.width));
14169
+ node.setAttribute("height", String(context.height));
14170
+ node.setAttribute("aria-hidden", "true");
14171
+ node.setAttribute("focusable", "false");
14172
+ return { element: node };
14173
+ }
14174
+ function createIconDiagnostics() {
14175
+ const seen = /* @__PURE__ */ new Map();
14132
14176
  return {
14133
- rows: rows2,
14134
- read() {
14135
- const patch = {};
14136
- for (const [key, field] of fields) {
14137
- const spec = inputs2[key];
14138
- let value = Number(field.value);
14139
- if (!Number.isFinite(value)) continue;
14140
- if (spec.kind === "int" || spec.kind === "enum") value = Math.round(value);
14141
- if (spec.min !== void 0) value = Math.max(spec.min, value);
14142
- if (spec.max !== void 0) value = Math.min(spec.max, value);
14143
- patch[key] = value;
14144
- }
14145
- return patch;
14177
+ report(icon, failure) {
14178
+ if (!seen.has(icon)) seen.set(icon, { icon, code: failure, message: `${icon}: ${FAILURE_TEXT[failure]}` });
14146
14179
  },
14147
- first: () => fields.values().next().value ?? null
14148
- };
14149
- }
14150
- function openInputsEditor(container, rect, inputs2, current, onApply, strings = createChartI18n()) {
14151
- const host2 = container.getBoundingClientRect();
14152
- const el2 = document.createElement("div");
14153
- el2.className = "qc-overlay qc-inputs";
14154
- el2.setAttribute("role", "dialog");
14155
- el2.setAttribute("aria-label", strings.t("legend.indicatorSettings"));
14156
- el2.style.left = `${Math.max(4, rect.x - host2.left)}px`;
14157
- el2.style.top = `${Math.max(4, rect.y - host2.top + rect.h + 4)}px`;
14158
- for (const type of ["pointerdown", "pointerup", "pointermove"]) el2.addEventListener(type, (e) => e.stopPropagation());
14159
- const dismiss = () => {
14160
- unsubscribe();
14161
- el2.remove();
14162
- };
14163
- const fields = buildInputFields(inputs2, current);
14164
- for (const row2 of fields.rows) el2.appendChild(row2);
14165
- const apply = () => {
14166
- onApply(fields.read());
14167
- dismiss();
14168
- };
14169
- const buttons = document.createElement("div");
14170
- buttons.className = "qc-inputs-actions";
14171
- const mkButton = (label2, onClick, primary = false) => {
14172
- const b = document.createElement("button");
14173
- b.type = "button";
14174
- b.className = primary ? "qc-button qc-button--primary" : "qc-button";
14175
- b.textContent = label2;
14176
- b.addEventListener("click", onClick);
14177
- buttons.appendChild(b);
14178
- return b;
14180
+ list: () => [...seen.values()]
14179
14181
  };
14180
- const cancelButton = mkButton(strings.t("inputs.cancel"), () => dismiss());
14181
- const applyButton = mkButton(strings.t("inputs.apply"), apply, true);
14182
- el2.appendChild(buttons);
14183
- const unsubscribe = strings.onChange(() => {
14184
- cancelButton.textContent = strings.t("inputs.cancel");
14185
- applyButton.textContent = strings.t("inputs.apply");
14186
- el2.setAttribute("aria-label", strings.t("legend.indicatorSettings"));
14187
- });
14188
- el2.addEventListener("keydown", (e) => {
14189
- e.stopPropagation();
14190
- if (e.key === "Enter") apply();
14191
- else if (e.key === "Escape") dismiss();
14192
- });
14193
- container.appendChild(el2);
14194
- fields.first()?.focus?.();
14195
14182
  }
14196
14183
 
14197
- // src/ui/chrome/menu.ts
14198
- var HOST_MARGIN = 8;
14199
- var byAnchor = /* @__PURE__ */ new WeakMap();
14200
- function toggleMenu(anchor, open2) {
14201
- const current = byAnchor.get(anchor);
14202
- if (current?.open()) current.close();
14203
- else open2();
14204
- }
14205
- function openMenu(options) {
14206
- const { anchor, host: host2 } = options;
14207
- const previous = byAnchor.get(anchor);
14208
- const rtl = isRtl(anchor);
14209
- const role = options.role ?? "menu";
14210
- const element = h("div", {
14211
- class: `qc-overlay qc-menu-panel${options.className ? ` ${options.className}` : ""}`,
14212
- role,
14213
- "aria-label": options.label,
14214
- ...role === "dialog" ? { "aria-modal": "false" } : {}
14215
- });
14216
- if (options.width) element.style.width = `${options.width}px`;
14217
- stopPointer(element);
14218
- const body = h("div", { class: "qc-menu-body" });
14219
- element.appendChild(body);
14220
- const footer = options.footer ? h("div", { class: "qc-menu-footer" }) : null;
14221
- if (footer) element.appendChild(footer);
14222
- let isOpen = true;
14223
- const previouslyFocused = document.activeElement;
14224
- const escape = pushEscapeOwner();
14225
- let untrack = () => void 0;
14226
- const close = () => {
14227
- if (!isOpen) return;
14228
- isOpen = false;
14229
- escape.release();
14230
- const ownedAnchor = byAnchor.get(anchor) === handle;
14231
- if (ownedAnchor) byAnchor.delete(anchor);
14232
- untrack();
14233
- document.removeEventListener("pointerdown", onOutside, true);
14234
- document.removeEventListener("keydown", onDocumentKey, true);
14235
- window.removeEventListener("resize", reposition);
14236
- if (ownedAnchor) anchor.setAttribute("aria-expanded", "false");
14237
- element.remove();
14238
- options.onClose?.();
14239
- if (byAnchor.get(anchor)?.open()) return;
14240
- const target = document.activeElement === document.body || document.activeElement === null || element.contains(document.activeElement) ? anchor : previouslyFocused;
14241
- target?.focus();
14242
- };
14243
- const reposition = () => {
14244
- if (!isOpen) return;
14245
- const a = anchor.getBoundingClientRect();
14246
- const bounds = host2.getBoundingClientRect();
14247
- const below = (options.placement ?? "down") === "down";
14248
- if (!below) element.style.maxHeight = `${Math.max(0, Math.floor(a.top - bounds.top - HOST_MARGIN - 2))}px`;
14249
- element.style.left = "0px";
14250
- element.style.top = "0px";
14251
- const box = element.getBoundingClientRect();
14252
- const alignEnd = (options.align ?? "start") === (rtl ? "start" : "end");
14253
- let left = (alignEnd ? a.right - box.width : a.left) - bounds.left;
14254
- left = Math.max(HOST_MARGIN, Math.min(left, Math.max(HOST_MARGIN, bounds.width - box.width - HOST_MARGIN)));
14255
- let top = (below ? a.bottom + 2 : a.top - box.height - 2) - bounds.top;
14256
- top = Math.max(HOST_MARGIN, Math.min(top, Math.max(HOST_MARGIN, bounds.height - box.height - HOST_MARGIN)));
14257
- element.style.left = `${Math.round(left)}px`;
14258
- element.style.top = `${Math.round(top)}px`;
14259
- };
14260
- const onOutside = (event) => {
14261
- const target = event.target;
14262
- if (!target || element.contains(target) || anchor.contains(target)) return;
14263
- close();
14264
- };
14265
- const onDocumentKey = (event) => {
14266
- if (event.key === "Escape" && ownsEscape(escape.token)) {
14267
- event.stopPropagation();
14268
- event.preventDefault();
14269
- close();
14270
- }
14271
- };
14272
- element.addEventListener("keydown", (event) => {
14273
- if (event.key === "Tab") {
14274
- close();
14275
- return;
14276
- }
14277
- const target = event.target;
14278
- const typing = target instanceof HTMLInputElement && target.type !== "checkbox" && target.type !== "radio";
14279
- if (typing && (event.key === "ArrowLeft" || event.key === "ArrowRight" || event.key === "Home" || event.key === "End")) return;
14280
- if (roveFocus(element, event, "both")) {
14281
- event.preventDefault();
14282
- event.stopPropagation();
14283
- }
14284
- });
14285
- const handle = {
14286
- element,
14287
- close,
14288
- open: () => isOpen,
14289
- refresh() {
14290
- if (!isOpen) return;
14291
- const current = items(element).indexOf(document.activeElement);
14292
- body.replaceChildren();
14293
- options.build(body, handle);
14294
- if (footer && options.footer) {
14295
- footer.replaceChildren();
14296
- options.footer(footer, handle);
14297
- }
14298
- const list2 = items(element);
14299
- if (list2.length === 0) return;
14300
- if (current >= 0 && document.activeElement && !element.contains(document.activeElement)) return;
14301
- armRoving(element, Math.max(0, Math.min(current, list2.length - 1)));
14302
- if (current >= 0) list2[Math.min(current, list2.length - 1)]?.focus();
14303
- reposition();
14304
- },
14305
- reposition
14306
- };
14307
- byAnchor.set(anchor, handle);
14308
- previous?.close();
14309
- if (!isOpen || byAnchor.get(anchor) !== handle) return handle;
14310
- options.build(body, handle);
14311
- if (footer && options.footer) options.footer(footer, handle);
14312
- if (!isOpen || byAnchor.get(anchor) !== handle) return handle;
14313
- host2.appendChild(element);
14314
- untrack = trackOverlay(host2, close, () => handle.refresh());
14315
- anchor.setAttribute("aria-expanded", "true");
14316
- reposition();
14317
- const list = items(element);
14318
- const first = Math.max(0, Math.min(options.initialIndex ?? 0, list.length - 1));
14319
- if (list.length > 0) {
14320
- armRoving(element, first);
14321
- focusItem(list, first);
14322
- list[first]?.scrollIntoView?.({ block: "nearest" });
14323
- } else {
14324
- const focusable = element.querySelector('input, button, select, textarea, [tabindex="0"]');
14325
- focusable?.focus();
14326
- }
14327
- document.addEventListener("pointerdown", onOutside, true);
14328
- document.addEventListener("keydown", onDocumentKey, true);
14329
- window.addEventListener("resize", reposition);
14330
- return handle;
14331
- }
14332
- function menuItem(options) {
14333
- const role = options.role ?? "menuitem";
14334
- const row2 = h("button", {
14335
- type: "button",
14336
- class: `qc-menu-row${options.className ? ` ${options.className}` : ""}`,
14337
- role,
14338
- "data-qc-item": "",
14339
- tabindex: "-1",
14340
- ...options.label ? { "aria-label": options.label } : options.keys ? { "aria-label": options.text } : {},
14341
- ...options.keys ? { "aria-keyshortcuts": options.keys } : {},
14342
- ...role === "menuitemradio" || role === "menuitemcheckbox" ? { "aria-checked": String(options.checked === true) } : {},
14343
- ...role === "option" ? { "aria-selected": String(options.checked === true) } : {}
14344
- });
14345
- if (options.disabled) {
14346
- row2.disabled = true;
14347
- row2.setAttribute("aria-disabled", "true");
14348
- }
14349
- const cell2 = h("span", { class: "qc-menu-icon" });
14350
- if (options.icon) {
14351
- row2.classList.add("qc-menu-row--marked");
14352
- cell2.appendChild(options.icon);
14353
- }
14354
- row2.appendChild(cell2);
14355
- const label2 = h("span", { class: "qc-menu-label" }, options.text);
14356
- row2.appendChild(options.description === void 0 ? label2 : h("span", { class: "qc-menu-text" }, label2, h("span", { class: "qc-menu-description" }, options.description)));
14357
- if (options.hint !== void 0) row2.appendChild(h("span", { class: "qc-menu-hint", ...options.keys ? { "aria-hidden": "true" } : {} }, options.hint));
14358
- if (options.onSelect) row2.addEventListener("click", () => options.onSelect?.());
14359
- return row2;
14360
- }
14361
- function menuHeading(text2) {
14362
- return h("div", { class: "qc-menu-heading", role: "presentation" }, text2);
14363
- }
14364
- function menuSeparator() {
14365
- return h("div", { class: "qc-separator", role: "separator" });
14366
- }
14184
+ // src/ui/drawings/toolIcons.ts
14185
+ var TOOL_ICONS = {
14186
+ trend_line: '<path d="M7.3 20.7 20.7 7.3" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14187
+ ray: '<path d="M8.3 19.7 12.7 15.3 M16.3 11.7 24.4 3.6" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="21.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="13.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14188
+ info_line: '<path d="M7.3 20.7 20.7 7.3" stroke="currentColor" stroke-width="1.2"/><rect x="16.5" y="17.5" width="9" height="7" rx="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14189
+ extended: '<path d="M4.4 25.4 9.3 20.5 M12.4 17.4 17.4 12.4 M20.4 9.4 25.4 4.4" stroke="currentColor" stroke-width="1.2"/><circle cx="10.5" cy="18.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="18.5" cy="10.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14190
+ trend_angle: '<path d="M7.3 20.7 20.7 7.3 M7.5 22.5H24 M15.5 22.5A8 8 0 0 0 13.2 16.8" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14191
+ horizontal_line: '<path d="M4 14.5h8.4 M16.6 14.5H25" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="14.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14192
+ horizontal_ray: '<path d="M8.9 14.5H25" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="14.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14193
+ vertical_line: '<path d="M14.5 4v8.4 M14.5 16.6V25" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="14.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14194
+ cross_line: '<path d="M4 14.5h8.4 M16.6 14.5H25 M14.5 4v8.4 M14.5 16.6V25" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="14.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14195
+ parallel_channel: '<path d="M8.3 18.3 18.3 8.3 M12.4 25.3 17.3 20.4 M20.4 17.3 25.3 12.4" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="19.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="19.5" cy="6.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="18.85" cy="18.85" r="2" stroke="currentColor" stroke-width="1.2"/>',
14196
+ regression_trend: '<path d="M5.5 12 22.5 3 M5.5 25 22.5 16 M7.6 18 20.7 11.1" stroke="currentColor" stroke-width="1.2"/><path d="M5.5 12v4.4 M5.5 20.6V25 M22.5 3v4.4 M22.5 11.6V16" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="18.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="9.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14197
+ flat_top_bottom: '<path d="M7.7 12.6 20.3 7.4 M7.5 22.5h13" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="13.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="6.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14198
+ disjoint_channel: '<path d="M7.3 9.3 20.6 4.6 M7.5 17.7 20.7 22.4" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="10.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="4.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="16.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14199
+ pitchfork: '<path d="M7.3 21.4 19.9 8.9 M6.7 13.4 14.6 21.3 M7.1 10.6 14.2 3.5 M18.1 21.6 25.2 14.5" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="11.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="16.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14200
+ schiff_pitchfork: '<path d="M6.5 22.5H16.5 M10.3 20.4 21.9 8.9 M8.3 13 17 21.7 M9.1 10.6 16.2 3.5 M20.1 21.6 27.2 14.5" stroke="currentColor" stroke-width="1.2"/><circle cx="4.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="7.5" cy="11.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="18.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14201
+ schiff_pitchfork_modified: '<path d="M7.9 22.9 21.9 8.9 M5.5 22.5H16.5 M8.3 13 17 21.7 M9.1 10.6 16.2 3.5 M20.1 21.6 27.2 14.5" stroke="currentColor" stroke-width="1.2"/><circle cx="7.5" cy="11.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="18.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14202
+ inside_pitchfork: '<path d="M6.5 22.5H18.5 M8.4 22.7 10.4 16.6 M11.6 12.7 14.7 3.1 M16 18.7 19.7 7.1 M21.6 20.7 24.7 11.1 M11.8 16.2 18.6 21.6" stroke="currentColor" stroke-width="1.2"/><circle cx="4.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="10.5" cy="14.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="20.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14203
+ fib_retracement: '<path d="M3 4.5h22 M3 10.5h19.4 M3 16.5h22 M6 22.5h19" stroke="currentColor" stroke-width="1.2"/><circle cx="3.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="24.5" cy="10.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14204
+ fib_trend_ext: '<path d="M6.6 16.5H26 M4 20.5h22 M4 24.5h22 M4.5 11.6v2.9 M6.6 9.3 16.6 5.7" stroke="currentColor" stroke-width="1.2"/><circle cx="4.5" cy="9.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="4.5" cy="16.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="18.5" cy="4.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14205
+ fib_channel: '<path d="M7.5 12 21 4.9 M7.3 18.5 23.2 10.1 M5.3 26 23.2 16.7" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="19.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="3.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14206
+ fib_timezone: '<path d="M5.5 4v4.4 M5.5 12.6V25 M14.5 4v13.4 M14.5 21.6V25 M19.5 4v21 M24.5 4v21" stroke="currentColor" stroke-width="1.2"/><path d="M7.2 12.2l1 1 M9 14.5l1.5 1.5 M11.4 16.9l1.2 1.2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="10.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="19.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14207
+ fib_speed_resist_fan: '<path d="M4.5 2v19.4 M4.5 10.5H15 M17.5 12.6v10.9 M6.5 23.5H26" stroke="currentColor" stroke-width="1.2"/><path d="M6.3 22.4 16.4 12.3 M19.3 9.4 25.9 2.9 M6.6 23.4 25.7 17.5 M5.6 21.7 11.5 2.7" stroke="currentColor" stroke-width="1.2"/><circle cx="4.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="17.5" cy="10.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14208
+ fib_trend_time: '<path d="M16.5 2v19.4 M20.5 2v22 M24.5 2v22 M4.7 11.5 8.4 21.8 M11.5 23.5h3" stroke="currentColor" stroke-width="1.2"/><circle cx="4.5" cy="9.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="9.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="16.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14209
+ fib_circles: '<circle cx="14.5" cy="14.5" r="5" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="14.5" r="8" stroke="currentColor" stroke-width="1.2"/><path d="M24.1 8.5A11.3 11.3 0 0 1 8.5 24.1 M4.9 20.5A11.3 11.3 0 0 1 20.5 4.9" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="6.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14210
+ fib_spiral: '<path d="M15.6 13.2a1.7 1.7 0 1 0-3.4 0 3 3 0 0 0 6 0 5.2 5.2 0 1 0-10.4 0 7.6 7.6 0 0 0 14.9 2.4" stroke="currentColor" stroke-width="1.2"/><path d="M15 15.7 18.7 12 M21 9.7 24.2 6.5" stroke="currentColor" stroke-width="1.2"/><circle cx="13.5" cy="16.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="19.5" cy="10.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14211
+ fib_speed_resist_arcs: '<path d="M8.5 9.5A5 5 0 0 0 18.5 9.5 M0.5 9.5A13 13 0 0 0 26.5 9.5 M4.5 9.5A9 9 0 0 0 11 18.2 M16 18.2A9 9 0 0 0 22.5 9.5" stroke="currentColor" stroke-width="1.2"/><circle cx="13.5" cy="9.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="13.5" cy="18.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14212
+ fib_wedge: '<path d="M5.5 8v13 M8 23.5H21" stroke="currentColor" stroke-width="1.2"/><path d="M5.5 17.5A6 6 0 0 1 11.5 23.5 M5.5 13.5A10 10 0 0 1 15.5 23.5 M5.5 9.5A14 14 0 0 1 19.5 23.5" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="23.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14213
+ pitchfan: '<path d="M7.4 21.4 24.4 4.4 M7.3 22.7 16.9 21.2 M20.3 20.7 24.8 19.9 M7.3 22.1 23 13.8 M6.7 21.2 15.1 5.5 M6.3 20.8 7.8 11.4 M8.3 7.8 9 3.3 M9.3 10.6 17.5 18.8" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="7.5" cy="9.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="18.5" cy="20.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14214
+ gannbox: '<path d="M22.5 3.5H3.5V22 M5.5 24.5H24.5V5.5" stroke="currentColor" stroke-width="1.2"/><path d="M3.5 10.5h21 M3.5 17.5h21 M10.5 3.5v21 M17.5 3.5v21" stroke="currentColor" stroke-width="1.2"/><circle cx="3.5" cy="24.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="24.5" cy="3.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14215
+ gannbox_fixed: '<path d="M5.5 23.5H24.5V2.5H3.5V21.5 M4 9.5h20 M3.5 18.5h5 M12.5 18.5h12 M17.5 3v20 M10.5 2.5v12 M10.5 18.5v5" stroke="currentColor" stroke-width="1.2"/><path d="M4.9 22.1 9.1 17.9 M12 15 24 3 M5.4 23 24.5 17 M4.1 21.6 10 2.5 M24.5 23.5A21 21 0 0 0 3.5 2.5" stroke="currentColor" stroke-width="1.2"/>',
14216
+ gannbox_square: '<path d="M22.5 3.5H3.5V22 M5.5 24.5H24.5V5.5" stroke="currentColor" stroke-width="1.2"/><path d="M5.3 23.4 23.5 5.2 M5.6 24.4 24.7 18.5 M4.6 22.7 10.5 3.7 M24.5 6.5A21 21 0 0 1 6.5 24.5" stroke="currentColor" stroke-width="1.2"/><circle cx="3.5" cy="24.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="24.5" cy="3.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14217
+ gannbox_fan: '<path d="M7.4 21.4 14.5 14.3 M17.3 11.5 24.4 4.4 M7.5 22.1 23.3 14.4 M7.5 22.7 24.8 19.9 M6.8 21 14.5 5.2 M6.3 20.7 9.1 3.3" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="15.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14218
+ xabcd_pattern: '<path d="M6.3 20.7 8.6 7.6 M9 7.5 11 11 M11 13.8 6.2 20.6 M14.4 11.7 19.2 8.1 M20.4 8.5 22.6 17.6 M13.9 14 21.6 18.9" stroke="currentColor" stroke-width="1.2"/><circle cx="8.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="12.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="20.5" cy="6.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="23.5" cy="19.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14219
+ cypher_pattern: '<path d="M6.3 20.7 8.6 7.6 M9 7.5 11 11 M11 13.8 6.2 20.6 M14.4 11.7 19.2 8.1 M20.4 8.5 22.6 17.6 M13.9 14 21.6 18.9" stroke="currentColor" stroke-width="1.2"/><circle cx="8.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="12.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="20.5" cy="6.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="23.5" cy="19.5" r="2" stroke="currentColor" stroke-width="1.2"/><text x="14.3" y="24.4" text-anchor="middle" font-size="7.5" fill="currentColor">C</text>',
14220
+ abcd_pattern: '<path d="M9.5 6.7 21.5 5.2 M6.6 9.4 4.4 20.4 M6.5 22.7 18.6 21.2 M21.4 18.6 23.6 7.6 M8.5 9.2 18.8 19.5" stroke="currentColor" stroke-width="1.2"/><circle cx="7.5" cy="7.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="4.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="23.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="20.5" cy="20.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14221
+ triangle_pattern: '<path d="M2.5 1.5V20.8 M2.6 1.9 7.4 4.1 M11.1 5.9 16.4 8.3 M20.1 8.1 26.8 11.1 M4.1 21.2 9.5 18.8 M13.3 17.7 26.8 11.6" stroke="currentColor" stroke-width="1.2"/><path d="M3.7 20.8 9.2 6.6 M9.3 6.4 10.7 16.6 M13.1 17.2 17.8 10.4" stroke="currentColor" stroke-width="1.2"/><circle cx="9.5" cy="4.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="11.5" cy="18.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="18.5" cy="8.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14222
+ three_drives: '<path d="M0.3 4.7 1.4 5.2 M5.1 6.8 8.5 8.2 M12.1 9.8 15.5 11.2 M19.2 12.8 25.1 15.3 M0.3 17.7 1.4 18.2 M5.1 19.8 8.5 21.2 M12.1 22.8 15.5 24.2 M19.2 25.8 20.8 26.5" stroke="currentColor" stroke-width="1.2"/><path d="M3.5 7.5V16.4 M4.3 16.5 8.9 9.9 M10.5 10.5V19.5 M11.3 19.5 15.9 12.9 M17.5 13.5V22.5 M17.7 22.5 24.3 5.2" stroke="currentColor" stroke-width="1.2"/><circle cx="3.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="3.5" cy="18.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="10.5" cy="8.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="10.5" cy="21.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="17.5" cy="11.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="17.5" cy="24.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14223
+ head_and_shoulders: '<path d="M4.4 21.7 6.5 12.6 M7.8 12 10 16.5 M10.6 16.4 13.5 6.3 M15.5 6.2 18.4 16.5 M18.9 16.5 21.1 12.1 M23.4 12.3 25.5 21.4" stroke="currentColor" stroke-width="1.2"/><path d="M1 18.5h7.5 M12.5 18.5h4 M20.5 18.5h6.5" stroke="currentColor" stroke-width="1.2"/><circle cx="3.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="10.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="10.5" cy="18.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="4.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="18.5" cy="18.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="21.5" cy="10.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="25.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14224
+ elliott_impulse_wave: '<path d="M5.2 18.5 9.4 14.3 M11.9 13.9 16.1 18.1 M18.6 17.7 22.7 13.5" stroke="currentColor" stroke-width="1.2"/><circle cx="10.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="17.5" cy="19.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="24.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><text x="10.8" y="7" text-anchor="middle" font-size="7.5" fill="currentColor">1</text><text x="24.6" y="7" text-anchor="middle" font-size="7.5" fill="currentColor">5</text>',
14225
+ elliott_correction: '<path d="M5.2 18.5 9.4 14.3 M11.9 13.9 16.1 18.1 M18.6 17.7 22.7 13.5" stroke="currentColor" stroke-width="1.2"/><circle cx="10.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="17.5" cy="19.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="24.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><text x="10.8" y="7" text-anchor="middle" font-size="7.5" fill="currentColor">A</text><text x="24.6" y="7" text-anchor="middle" font-size="7.5" fill="currentColor">C</text>',
14226
+ elliott_triangle_wave: '<path d="M5.2 18.5 9.4 14.3 M11.9 13.9 16.1 18.1 M18.6 17.7 22.7 13.5" stroke="currentColor" stroke-width="1.2"/><circle cx="10.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="17.5" cy="19.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="24.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><text x="10.8" y="7" text-anchor="middle" font-size="7.5" fill="currentColor">A</text><text x="24.6" y="7" text-anchor="middle" font-size="7.5" fill="currentColor">E</text>',
14227
+ elliott_double_combo: '<path d="M5.2 18.5 9.4 14.3 M11.9 13.9 16.1 18.1 M18.6 17.7 22.7 13.5" stroke="currentColor" stroke-width="1.2"/><circle cx="10.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="17.5" cy="19.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="24.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><text x="10.8" y="7" text-anchor="middle" font-size="7.5" fill="currentColor">W</text><text x="24.6" y="7" text-anchor="middle" font-size="7.5" fill="currentColor">Y</text>',
14228
+ elliott_triple_combo: '<path d="M5.2 18.5 9.4 14.3 M11.9 13.9 16.1 18.1 M18.6 17.7 22.7 13.5" stroke="currentColor" stroke-width="1.2"/><circle cx="10.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="17.5" cy="19.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="24.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><text x="10.8" y="7" text-anchor="middle" font-size="7.5" fill="currentColor">W</text><text x="24.6" y="7" text-anchor="middle" font-size="7.5" fill="currentColor">Z</text>',
14229
+ cyclic_lines: '<path d="M5.5 4v8.4 M5.5 16.6V25 M11.5 4v8.4 M11.5 16.6V25 M17.5 4v21 M23.5 4v21" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="14.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="11.5" cy="14.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14230
+ time_cycles: '<path d="M-2.5 15A5.5 5.5 0 0 1 8.5 15 M8.5 15A5.5 5.5 0 0 1 19.5 15 M19.5 15A5.5 5.5 0 0 1 30.5 15" stroke="currentColor" stroke-width="1.2"/><circle cx="8.5" cy="17.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="19.5" cy="17.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14231
+ sine_line: '<path d="M5.2 14.1C5.2 11.4 6 8.9 7.5 8 M11.1 8.6C12.7 9.9 13.3 12.1 14.1 14.6C15 17.4 15.9 20 17.7 21.3 M21.5 21.5C23 20.9 24 19.1 24.6 17.2C24.9 16.2 25.3 15.1 25.4 14.2" stroke="currentColor" stroke-width="1.2"/><circle cx="9.5" cy="7.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="19.5" cy="21.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14232
+ long_position: '<path d="M8 6.5H25 M5 17.5h20 M8 22.5H25" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="6.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><text x="15.5" y="14.5" text-anchor="middle" font-size="7.5" fill="currentColor">L</text>',
14233
+ short_position: '<path d="M8 6.5H25 M5 11.5h20 M8 22.5H25" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="6.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><text x="15.7" y="19" text-anchor="middle" font-size="7.5" fill="currentColor">S</text>',
14234
+ forecast: '<path d="M7.5 6v6 M7.5 19.5V22 M14.5 5v5 M14.5 18v3 M21.5 5v6" stroke="currentColor" stroke-width="1.2"/><rect x="6.5" y="12.5" width="2" height="7" stroke="currentColor" stroke-width="1.2"/><rect x="13.5" y="10.5" width="2" height="7.5" stroke="currentColor" stroke-width="1.2"/><path d="M19 11h5l-2.5 3z" fill="currentColor"/><circle cx="21.5" cy="16.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14235
+ bars_pattern: '<path d="M6.5 6v6.5 M6.5 19.5V22 M11.5 11v2.5 M11.5 16.5V24 M16.5 5v5.5 M16.5 18.5V21 M21.5 7v4.5 M21.5 16.5V19" stroke="currentColor" stroke-width="1.2"/><rect x="5.5" y="12.5" width="2" height="7" stroke="currentColor" stroke-width="1.2"/><rect x="10.5" y="13.5" width="2" height="3" stroke="currentColor" stroke-width="1.2"/><rect x="15.5" y="10.5" width="2" height="8" stroke="currentColor" stroke-width="1.2"/><rect x="20.5" y="11.5" width="2" height="5" stroke="currentColor" stroke-width="1.2"/>',
14236
+ ghost_feed: '<path d="M4.5 18 7.7 16.7 M9.7 15.9 12.7 14.7 M14.7 13.9 17.7 12.7 M19.7 11.8 22.8 10.5" stroke="currentColor" stroke-width="1.2"/><path d="M8.5 9v4.5 M8.5 18.5v2.5 M13.5 6v5 M13.5 15v5 M18.5 3v5.5 M18.5 16.5v2.5" stroke="currentColor" stroke-width="1.2"/><rect x="7.5" y="13.5" width="2" height="5" stroke="currentColor" stroke-width="1.2"/><rect x="12.5" y="11" width="2" height="4" stroke="currentColor" stroke-width="1.2"/><rect x="17.5" y="8.5" width="2" height="8" stroke="currentColor" stroke-width="1.2"/>',
14237
+ sector: '<path d="M5.5 8v13 M8 23.5H21 M7.6 5.1A18.4 18.4 0 0 1 23.9 21.4" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="23.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14238
+ anchored_vwap: '<path d="M10.5 5v4.5 M10.5 21.5V25 M17.5 2v5.5 M17.5 17.5V23" stroke="currentColor" stroke-width="1.2"/><rect x="8.5" y="9.5" width="4" height="12" stroke="currentColor" stroke-width="1.2"/><rect x="15.5" y="7.5" width="4" height="10" stroke="currentColor" stroke-width="1.2"/><path d="M5.6 15.8 7.5 14.4 14.2 15.9 25 9.7" stroke="currentColor" stroke-width="1.2"/><circle cx="4" cy="17" r="2" stroke="currentColor" stroke-width="1.2"/>',
14239
+ fixed_range_volume_profile: '<path d="M3.5 3v16 M23.5 8v16" stroke="currentColor" stroke-width="1.2"/><rect x="3.5" y="6.5" width="6" height="3" stroke="currentColor" stroke-width="1.2"/><rect x="3.5" y="9.5" width="9" height="3" stroke="currentColor" stroke-width="1.2"/><rect x="3.5" y="12.5" width="4" height="3" stroke="currentColor" stroke-width="1.2"/><circle cx="3.5" cy="21.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="23.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14240
+ anchored_volume_profile: '<path d="M23.5 3v21 M9 13.5h5.5" stroke="currentColor" stroke-width="1.2"/><rect x="17.5" y="7.5" width="6" height="3" stroke="currentColor" stroke-width="1.2"/><rect x="12.5" y="10.5" width="11" height="3" stroke="currentColor" stroke-width="1.2"/><rect x="14.5" y="14.5" width="9" height="3" stroke="currentColor" stroke-width="1.2"/><rect x="20.5" y="17.5" width="3" height="3" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="13.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14241
+ price_range: '<path d="M4 4.5h16.5 M8.5 24.5H25 M14.5 9v14" stroke="currentColor" stroke-width="1.2"/><path d="M14.5 6l2.5 3h-5z" fill="currentColor"/><circle cx="22.5" cy="4.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="24.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14242
+ date_range: '<path d="M4.5 4v16.5 M24.5 8.5V25 M6 14.5h14" stroke="currentColor" stroke-width="1.2"/><path d="M20 12v5l3-2.5z" fill="currentColor"/><circle cx="4.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="24.5" cy="6.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14243
+ date_and_price_range: '<path d="M4 4.5h17.5 M4.5 4v17.5 M6.5 23.5H24 M23.5 6.5V24" stroke="currentColor" stroke-width="1.2"/><path d="M13.5 9v13 M6 14.5h13" stroke="currentColor" stroke-width="1.2"/><path d="M13.5 6l2.5 3h-5z M19 12v5l3-2.5z" fill="currentColor"/><circle cx="4.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="23.5" cy="4.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14244
+ brush: '<path d="M3.5 22.5c2.4-2.6 3.6-5.3 4.5-8 1.2-3.4 5.6-4.2 8.2-1.2 2.8 3.3-.3 9.2-5.5 9.2z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/><path d="M18.2 6.4 16.8 7.7c-1 .9-1 2.4-.1 3.4l1.9 1.9c1 1 2.5.9 3.4 0l5.5-5.7" stroke="currentColor" stroke-width="1.2"/>',
14245
+ highlighter: '<path d="M15 2.7 26 13.7 19.3 20.4 14.7 21.9a1.2 1.2 0 0 1-1.2-.3l-5.9-6a1.2 1.2 0 0 1-.3-1.2L8.4 9.3z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/><path d="M8.9 10.5 18.2 19.8" stroke="currentColor" stroke-width="1.2"/><path d="M7.9 16.9l4.2 4.2-2.6 2.6-6.1-2.4z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/>',
14246
+ arrow_marker: '<path d="M22.7 4.6a.8.8 0 0 1 1 1l-2.5 8.3c-.2.7-1.1.8-1.5.2l-.9-1.7-12.6 10a.8.8 0 0 1-1.1-1.1l10-12.6-1.7-.9c-.6-.4-.5-1.3.2-1.5z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/>',
14247
+ arrow: '<path d="M7.3 20.7 15 13" stroke="currentColor" stroke-width="1.2"/><path d="M21 7l-8 3 5 5z" fill="currentColor"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14248
+ arrow_up: '<path d="M10.5 16.5H4.8L14 5.5l9.2 11h-5.7v6h-7z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/>',
14249
+ arrow_down: '<path d="M10.5 11.5H4.8L14 22.5l9.2-11h-5.7v-6h-7z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/>',
14250
+ rectangle: '<path d="M7.5 5.5h13 M7.5 22.5h13 M5.5 7.5v13 M22.5 7.5v13" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14251
+ rotated_rectangle: '<path d="M14.7 3.6 10.5 7.8 M7.7 10.6 3.5 14.8 M3.5 18.2l6.2 6.2 M13.2 24.5l4.2-4.2 M20.2 17.5l4.2-4.2 M24.4 9.7 18.2 3.5" stroke="currentColor" stroke-width="1.2"/><circle cx="16.5" cy="2.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="9.5" cy="9.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="2.5" cy="16.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="11.5" cy="25.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="18.5" cy="18.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="25.5" cy="11.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14252
+ path: '<path d="M2 18.6 7.7 12.6 M11.3 12.3 14.7 15.7 M18.3 15.7 25.6 8.4 M21 7.5h5.5 M26.5 7.5V13" stroke="currentColor" stroke-width="1.2"/><circle cx="9.5" cy="10.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="16.5" cy="17.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14253
+ circle: '<path d="M23.7 16.4A10 10 0 1 1 23.7 11.6" stroke="currentColor" stroke-width="1.2"/><circle cx="14" cy="14" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="24" cy="14" r="2" stroke="currentColor" stroke-width="1.2"/>',
14254
+ ellipse: '<path d="M17 6.8A11 8 0 0 1 25 12.2 M25 16.8A11 8 0 0 1 17 22.2 M12 22.2A11 8 0 0 1 4 16.8 M4 12.2A11 8 0 0 1 12 6.8" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="6.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="25.5" cy="14.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="3.5" cy="14.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14255
+ polyline: '<path d="M8.3 11.6 13.4 7.1 M16.5 5.5h4 M22.5 7.5v5 M20.5 14.5h-4 M14.5 16.5v4 M12.5 22.5h-4 M6.5 20.5v-6" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="14.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="14.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14256
+ triangle: '<path d="M8.5 22.5h11 M6.5 8.5v12 M7.5 8.3 19.8 21.4" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="6.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="21.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14257
+ arc: '<path d="M8.2 21.4 21.5 7.3" stroke="currentColor" stroke-width="1.2"/><path d="M8 23.9C12.5 26 17.8 26 21.5 23.4 M24 20C26 16 25.7 11 23.9 7.1" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="21.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14258
+ curve: '<path d="M6.3 20.7C6.9 17.2 8 14.3 9.7 12.1 M12.2 9.7C14.7 7.9 17.7 6.8 20.7 6.3" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="10.5" cy="10.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14259
+ double_curve: '<path d="M6 24.9C9.8 26.5 13.3 26.5 15.7 23.6 M17.6 19.6C17.9 17.3 17 16 14.3 13.6C11.9 11.5 11.1 10.3 11.4 8.5 M12.9 5.1C15 2.6 18.1 2.5 21.6 4.1" stroke="currentColor" stroke-width="1.2"/><circle cx="4.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="16.5" cy="21.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="11.5" cy="6.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="23.5" cy="4.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14260
+ text: '<path d="M7.5 9V5.5h13V9 M14 5.5v17 M11 22.5h6" stroke="currentColor" stroke-width="1.2"/>',
14261
+ note: '<rect x="4.5" y="2.5" width="18" height="14" rx="1" stroke="currentColor" stroke-width="1.2"/><path d="M9.5 8V6h9v2 M14 6v7 M12 13h4 M13.5 16.5v4.5" stroke="currentColor" stroke-width="1.2"/><circle cx="13.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14262
+ price_note: '<rect x="4.5" y="2.5" width="18" height="14" rx="1" stroke="currentColor" stroke-width="1.2"/><path d="M13.5 16.5v4.5" stroke="currentColor" stroke-width="1.2"/><text x="14" y="13" text-anchor="middle" font-size="10" fill="currentColor">$</text><circle cx="13.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14263
+ table: '<rect x="3.5" y="5.5" width="21" height="18" rx="1" stroke="currentColor" stroke-width="1.2"/><path d="M3.5 11.5h21 M3.5 17.5h21 M9.5 5.5v18" stroke="currentColor" stroke-width="1.2"/>',
14264
+ callout: '<path d="M9.6 18.5 5.5 23.5V6.5a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/>',
14265
+ comment: '<path d="M5.5 14a7 7 0 0 1 7-7h5a7 7 0 1 1 0 14H6.5a1 1 0 0 1-1-1z" stroke="currentColor" stroke-width="1.2"/>',
14266
+ price_label: '<path d="M5.5 20.5v-14a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1H12.6l-3.2 3.2" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
14267
+ signpost: '<circle cx="14" cy="11.5" r="9" stroke="currentColor" stroke-width="1.2"/><path d="M14 20.5V27" stroke="currentColor" stroke-width="1.2"/><path d="M14 6.2l1.5 3.1 3.4.4-2.5 2.3.6 3.4-3-1.7-3 1.7.6-3.4-2.5-2.3 3.4-.4z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/>',
14268
+ flag: '<path d="M5.5 23V5.5h16.7l-4.6 5.25 4.6 5.25H5.5" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/>',
14269
+ image: '<rect x="3.5" y="4.5" width="21" height="19" rx="3.5" stroke="currentColor" stroke-width="1.2"/><circle cx="10" cy="10" r="1.5" stroke="currentColor" stroke-width="1.2"/><path d="M4.2 21.5 9.3 15.1l3.3 4 M12.9 17.4 18 10.7l5.9 7.7" stroke="currentColor" stroke-width="1.2"/>',
14270
+ content_card: '<rect x="4.5" y="5.5" width="19" height="17" rx="2" stroke="currentColor" stroke-width="1.2"/><path d="M4.5 11.5h19 M8 15.5h9 M8 18.5h6" stroke="currentColor" stroke-width="1.2"/>',
14271
+ pin: '<path d="M14 3.5a7.5 7.5 0 0 1 7.5 7.5c0 4.2-4.2 8.9-7.5 12.6C10.7 19.9 6.5 15.2 6.5 11A7.5 7.5 0 0 1 14 3.5Z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/><circle cx="14" cy="11" r="3" stroke="currentColor" stroke-width="1.2"/>'
14272
+ };
14367
14273
 
14368
- // src/ui/chrome/marketStatus.ts
14369
- var clock = (mins) => `${String(Math.floor(mins / 60) % 24).padStart(2, "0")}:${String(mins % 60).padStart(2, "0")}`;
14370
- function timelineLabels(starts) {
14371
- const sorted = [...new Set(starts.filter((m) => m > 0))].sort((a, b) => a - b);
14372
- const out = [];
14373
- for (let i = 0; i < sorted.length; i++) {
14374
- const a = sorted[i];
14375
- const b = sorted[i + 1];
14376
- if (b !== void 0 && b - a <= 90) {
14377
- out.push({ mins: (a + b) / 2, text: `${clock(a)} ${clock(b)}` });
14378
- i++;
14379
- } else out.push({ mins: a, text: clock(a) });
14380
- }
14381
- return out;
14382
- }
14383
- function openMarketStatus(anchor, deps) {
14384
- const t = deps.i18n.t;
14385
- const now = () => Math.floor(Date.now() / 1e3);
14386
- let timer = null;
14387
- let offLocale = () => void 0;
14388
- const stopUpdates = () => {
14389
- if (timer) clearInterval(timer);
14390
- timer = null;
14391
- offLocale();
14392
- offLocale = () => void 0;
14393
- };
14394
- const titleRow = (state, text2) => {
14395
- const dot = h("span", { class: "qc-session-dot qc-status-dot", ...state ? { "data-qc-session": state } : {} });
14396
- return h("div", { class: "qc-status-title" }, dot, h("span", { class: "qc-title" }, text2));
14397
- };
14398
- const menu2 = openMenu({
14399
- host: deps.host,
14400
- anchor,
14401
- label: t("status.title"),
14402
- role: "dialog",
14403
- className: "qc-status-popup",
14404
- width: 300,
14405
- build(body) {
14406
- const model = deps.model();
14407
- const nowSecs = now();
14408
- const status2 = model ? deps.status(nowSecs) : null;
14409
- if (!model || !status2) {
14410
- body.append(titleRow(null, t("status.unknownTitle")), h("p", { class: "qc-status-text qc-secondary" }, t("status.unknown")));
14411
- return;
14412
- }
14413
- body.append(titleRow(sessionStateAt(model, nowSecs), marketStatusTitle(t, status2)), h("p", { class: "qc-status-text qc-secondary" }, marketStatusText(t, status2, nowSecs)));
14414
- const tl = sessionTimeline(model, nowSecs, deps.i18n.tag());
14415
- const bar = h("div", { class: "qc-status-bar", "aria-hidden": "true" });
14416
- for (const s of tl.segments) {
14417
- const segment = h("div", { class: "qc-status-segment", "data-qc-session": s.state });
14418
- segment.style.width = `${(s.end - s.start) / 1440 * 100}%`;
14419
- bar.appendChild(segment);
14420
- }
14421
- const marker = h("div", { class: "qc-status-now" });
14422
- marker.style.insetInlineStart = `${tl.nowMins / 1440 * 100}%`;
14423
- const track = h("div", { class: "qc-status-track" }, bar, marker);
14424
- body.appendChild(h("div", { class: "qc-status-timeline" }, h("span", { class: "qc-status-day qc-muted" }, tl.dayLabel), track));
14425
- const labels = timelineLabels(tl.segments.map((s) => s.start));
14426
- if (labels.length > 0) {
14427
- const row2 = h("div", { class: "qc-status-labels", "aria-hidden": "true" });
14428
- for (const l of labels) {
14429
- const label2 = h("span", { class: "qc-status-label qc-muted" }, l.text);
14430
- label2.style.insetInlineStart = `${l.mins / 1440 * 100}%`;
14431
- row2.appendChild(label2);
14432
- }
14433
- body.appendChild(row2);
14434
- }
14435
- body.appendChild(h("div", { class: "qc-status-footer qc-muted" }, exchangeTimezoneText(t, tl.timezone, new Date(nowSecs * 1e3))));
14436
- },
14437
- onClose() {
14438
- stopUpdates();
14439
- deps.onClose?.();
14440
- }
14441
- });
14442
- timer = setInterval(() => menu2.refresh(), 6e4);
14443
- offLocale = deps.i18n.onChange(() => menu2.refresh());
14444
- if (!menu2.open()) stopUpdates();
14445
- return menu2;
14446
- }
14274
+ // src/ui/chrome/arrangementGlyphs.ts
14275
+ var ARRANGEMENT_ICONS = {
14276
+ "s": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" d="M2.5 1C1.67 1 1 1.67 1 2.5v12c0 .83.67 1.5 1.5 1.5h14c.83 0 1.5-.67 1.5-1.5v-12c0-.83-.67-1.5-1.5-1.5h-14ZM0 2.5A2.5 2.5 0 0 1 2.5 0h14A2.5 2.5 0 0 1 19 2.5v12a2.5 2.5 0 0 1-2.5 2.5h-14A2.5 2.5 0 0 1 0 14.5v-12Z"></path>' },
14277
+ "2h": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v15H2.5A1.5 1.5 0 0 1 1 14.5v-12ZM10 16h6.5c.83 0 1.5-.67 1.5-1.5v-12c0-.83-.67-1.5-1.5-1.5H10v15ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
14278
+ "2v": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1h14c.83 0 1.5.67 1.5 1.5V8H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5h14c.83 0 1.5-.67 1.5-1.5V9H1Zm1.5-9A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
14279
+ "3h": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H6v15H2.5A1.5 1.5 0 0 1 1 14.5v-12ZM7 16h5V1H7v15Zm6-15v15h3.5c.83 0 1.5-.67 1.5-1.5v-12c0-.83-.67-1.5-1.5-1.5H13ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
14280
+ "3v": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1h14c.83 0 1.5.67 1.5 1.5V5H1V2.5ZM1 6v5h17V6H1Zm17 6H1v2.5c0 .83.67 1.5 1.5 1.5h14c.83 0 1.5-.67 1.5-1.5V12ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
14281
+ "3s": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v15H2.5A1.5 1.5 0 0 1 1 14.5v-12ZM10 16h6.5c.83 0 1.5-.67 1.5-1.5V9h-8v7Zm8-8V2.5c0-.83-.67-1.5-1.5-1.5H10v7h8ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
14282
+ "3r": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v7H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5H9V9H1Zm9 7h6.5c.83 0 1.5-.67 1.5-1.5v-12c0-.83-.67-1.5-1.5-1.5H10v15ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
14283
+ "2-1": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v7H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5h14c.83 0 1.5-.67 1.5-1.5V9H1Zm17-1V2.5c0-.83-.67-1.5-1.5-1.5H10v7h8ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
14284
+ "1-2": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1h14c.83 0 1.5.67 1.5 1.5V8H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5H9V9H1Zm9 7h6.5c.83 0 1.5-.67 1.5-1.5V9h-8v7ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
14285
+ "4": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v7H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5H9V9H1Zm9 7h6.5c.83 0 1.5-.67 1.5-1.5V9h-8v7Zm8-8V2.5c0-.83-.67-1.5-1.5-1.5H10v7h8ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
14286
+ "4v": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1h14c.83 0 1.5.67 1.5 1.5V4H1V2.5ZM1 5v3h17V5H1Zm17 4H1v3h17V9Zm0 4H1v1.5c0 .83.67 1.5 1.5 1.5h14c.83 0 1.5-.67 1.5-1.5V13ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
14287
+ "4h": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H4v15H2.5A1.5 1.5 0 0 1 1 14.5v-12ZM5 16h4V1H5v15Zm5-15v15h4V1h-4Zm5 0v15h1.5c.83 0 1.5-.67 1.5-1.5v-12c0-.83-.67-1.5-1.5-1.5H15ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
14288
+ "4s": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v15H2.5A1.5 1.5 0 0 1 1 14.5v-12ZM10 16h6.5c.83 0 1.5-.67 1.5-1.5V12h-8v4Zm8-5V6h-8v5h8Zm0-6V2.5c0-.83-.67-1.5-1.5-1.5H10v4h8ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
14289
+ "4s-l": { viewBox: "0 0 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M2 3.5C2 2.67 2.67 2 3.5 2H11v4H2V3.5ZM2 7v5h9V7H2Zm0 6v2.5c0 .83.67 1.5 1.5 1.5H11v-4H2Zm10 4h5.5c.83 0 1.5-.67 1.5-1.5v-12c0-.83-.67-1.5-1.5-1.5H12v15ZM3.5 1A2.5 2.5 0 0 0 1 3.5v12A2.5 2.5 0 0 0 3.5 18h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 17.5 1h-14Z"></path>' },
14290
+ "1-3": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1h14c.83 0 1.5.67 1.5 1.5V8H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5H6V9H1Zm6 7h5V9H7v7Zm6 0h3.5c.83 0 1.5-.67 1.5-1.5V9h-5v7ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
14291
+ "3-1": { viewBox: "-1 -1 21 19", body: '<g transform="matrix(1,0,0,-1,0,0)"><path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1h14c.83 0 1.5.67 1.5 1.5V8H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5H6V9H1Zm6 7h5V9H7v7Zm6 0h3.5c.83 0 1.5-.67 1.5-1.5V9h-5v7ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path></g>' },
14292
+ "2-2-l": { viewBox: "0 0 19 17", body: '<path fill="currentColor" fill-rule="evenodd" d="M2.5 1C1.67 1 1 1.67 1 2.5v12c0 .83.67 1.5 1.5 1.5H5V1zM10 16H6V1h4v15m1 0h5.5c.83 0 1.5-.67 1.5-1.5V9h-7zm7-8V2.5c0-.83-.67-1.5-1.5-1.5H11v7zM0 2.5A2.5 2.5 0 0 1 2.5 0h14A2.5 2.5 0 0 1 19 2.5v12a2.5 2.5 0 0 1-2.5 2.5h-14A2.5 2.5 0 0 1 0 14.5z"></path>' },
14293
+ "2-2-r": { viewBox: "0 0 19 17", body: '<path fill="currentColor" fill-rule="evenodd" d="M16.5 1H14v15h2.5c.83 0 1.5-.67 1.5-1.5v-12c0-.83-.67-1.5-1.5-1.5M9 1h4v15H9V1M8 1H2.5C1.67 1 1 1.67 1 2.5V8h7zM1 9v5.5c0 .83.67 1.5 1.5 1.5H8V9zm1.5-9A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0z"></path>' },
14294
+ "2-2": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v7H1V2.5ZM1 9v3h17V9H1Zm17-1V2.5c0-.83-.67-1.5-1.5-1.5H10v7h8Zm0 5H1v1.5c0 .83.67 1.5 1.5 1.5h14c.83 0 1.5-.67 1.5-1.5V13ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
14295
+ "1-4": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1h14c.83 0 1.5.67 1.5 1.5V8H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5H4V9H1Zm4 7h4V9H5v7Zm5 0h4V9h-4v7Zm5 0h1.5c.83 0 1.5-.67 1.5-1.5V9h-3v7ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
14296
+ "5h": { viewBox: "0 0 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M19 3.5c0-.83-.67-1.5-1.5-1.5H17v15h.5c.83 0 1.5-.67 1.5-1.5v-12Zm-17 12c0 .83.67 1.5 1.5 1.5H4V2h-.5C2.67 2 2 2.67 2 3.5v12ZM1.01 3.24A2.5 2.5 0 0 1 3.5 1h14A2.5 2.5 0 0 1 20 3.5v12a2.5 2.5 0 0 1-2.5 2.5h-14A2.5 2.5 0 0 1 1 15.5v-12l.01-.26ZM5 17h3V2H5v15Zm11 0h-3V2h3v15ZM12 2v15H9V2h3Z"></path>' },
14297
+ "5v": { viewBox: "0 0 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 3.5A2.5 2.5 0 0 1 3.5 1h14A2.5 2.5 0 0 1 20 3.5v12a2.5 2.5 0 0 1-2.5 2.5h-14A2.5 2.5 0 0 1 1 15.5v-12ZM3.5 2h14c.83 0 1.5.67 1.5 1.5V4H2v-.5C2 2.67 2.67 2 3.5 2ZM2 5v2h17V5H2Zm17 3H2v3h17V8Zm0 4H2v2h17v-2Zm0 3H2v.5c0 .83.67 1.5 1.5 1.5h14c.83 0 1.5-.67 1.5-1.5V15Z"></path>' },
14298
+ "5s": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v15H2.5A1.5 1.5 0 0 1 1 14.5v-12ZM10 16h6.5c.83 0 1.5-.67 1.5-1.5V13h-8v3Zm8-4V9h-8v3h8Zm0-4V5h-8v3h8Zm0-4V2.5c0-.83-.67-1.5-1.5-1.5H10v3h8ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
14299
+ "5s-l": { viewBox: "-1 -1 21 19", body: '<g transform="matrix(-1,0,0,-1,0,0)"><path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v15H2.5A1.5 1.5 0 0 1 1 14.5v-12ZM10 16h6.5c.83 0 1.5-.67 1.5-1.5V13h-8v3Zm8-4V9h-8v3h8Zm0-4V5h-8v3h8Zm0-4V2.5c0-.83-.67-1.5-1.5-1.5H10v3h8ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path></g>' },
14300
+ "2-3": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v7H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5H6V9H1Zm6 7h5V9H7v7Zm6 0h3.5c.83 0 1.5-.67 1.5-1.5V9h-5v7Zm5-8V2.5c0-.83-.67-1.5-1.5-1.5H10v7h8ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
14301
+ "3-2": { viewBox: "0 0 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M2 3.5C2 2.67 2.67 2 3.5 2H7v7H2V3.5ZM2 10v5.5c0 .83.67 1.5 1.5 1.5h14c.83 0 1.5-.67 1.5-1.5V10h-8v7h-1v-7H2Zm17-1V3.5c0-.83-.67-1.5-1.5-1.5H14v7h5Zm-6-7H8v7h5V2ZM3.5 1A2.5 2.5 0 0 0 1 3.5v12A2.5 2.5 0 0 0 3.5 18h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 17.5 1h-14Z"></path>' },
14302
+ "4-1": { viewBox: "-1 -1 21 19", body: '<g transform="matrix(-1,0,0,-1,0,0)"><path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1h14c.83 0 1.5.67 1.5 1.5V8H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5H4V9H1Zm4 7h4V9H5v7Zm5 0h4V9h-4v7Zm5 0h1.5c.83 0 1.5-.67 1.5-1.5V9h-3v7ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path></g>' },
14303
+ "2-3-l": { viewBox: "0 0 19 17", body: '<path fill="currentColor" fill-rule="evenodd" d="M10 1H6v15h4V1m1 0v4h7V2.5c0-.83-.67-1.5-1.5-1.5zm7 5h-7v5h7zm0 6h-7v4h5.5c.83 0 1.5-.67 1.5-1.5zM2.5 1H5v15H2.5A1.5 1.5 0 0 1 1 14.5v-12C1 1.67 1.67 1 2.5 1m0-1A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0z"></path>' },
14304
+ "2-3-r": { viewBox: "0 0 19 17", body: '<path fill="currentColor" fill-rule="evenodd" d="M16.5 1H14v15h2.5c.83 0 1.5-.67 1.5-1.5v-12c0-.83-.67-1.5-1.5-1.5M9 1h4v15H9V1M8 1H2.5C1.67 1 1 1.67 1 2.5V5h7zM1 6v5h7V6zm0 6v2.5c0 .83.67 1.5 1.5 1.5H8v-4zM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0z"></path>' },
14305
+ "6": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H6v7H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5H6V9H1Zm6 7h5V9H7v7Zm6 0h3.5c.83 0 1.5-.67 1.5-1.5V9h-5v7Zm5-8V2.5c0-.83-.67-1.5-1.5-1.5H13v7h5Zm-6-7H7v7h5V1ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
14306
+ "6h": { viewBox: "0 0 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M2 3.5C2 2.67 2.67 2 3.5 2H4v15h-.5A1.5 1.5 0 0 1 2 15.5v-12ZM5 17h2V2H5v15ZM8 2v15h2V2H8Zm3 0v15h2V2h-2Zm3 0v15h2V2h-2Zm3 0v15h.5c.83 0 1.5-.67 1.5-1.5v-12c0-.83-.67-1.5-1.5-1.5H17ZM3.5 1A2.5 2.5 0 0 0 1 3.5v12A2.5 2.5 0 0 0 3.5 18h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 17.5 1h-14Z"></path>' },
14307
+ "6v": { viewBox: "0 0 21 19", body: '<g fill="none"><rect width="18" height="16" stroke="currentColor" rx="2" x="1.5" y="1.5"></rect><path fill="currentColor" d="M1.5 4h18v1h-18V4Z"></path><path fill="currentColor" d="M2 7h18v1H2V7Z" opacity=".65"></path><path fill="currentColor" d="M1.5 10h18v1h-18v-1Z" opacity=".25"></path><path fill="currentColor" d="M1.5 13h18v1h-18v-1Z" opacity=".05"></path></g>' },
14308
+ "6c": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v4H1V2.5ZM1 6v5h8V6H1Zm0 6v2.5c0 .83.67 1.5 1.5 1.5H9v-4H1Zm9 4h6.5c.83 0 1.5-.67 1.5-1.5V12h-8v4Zm8-5V6h-8v5h8Zm0-6V2.5c0-.83-.67-1.5-1.5-1.5H10v4h8ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
14309
+ "2-4": { viewBox: "0 0 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 3.5A2.5 2.5 0 0 1 3.5 1h14A2.5 2.5 0 0 1 20 3.5v12a2.5 2.5 0 0 1-2.5 2.5h-14A2.5 2.5 0 0 1 1 15.5v-12ZM11 2h6.5c.83 0 1.5.67 1.5 1.5V9h-8V2Zm-1 0H3.5C2.67 2 2 2.67 2 3.5V9h8V2Zm-8 8v5.5c0 .83.67 1.5 1.5 1.5H5v-7H2Zm4 7h4v-7H6v7Zm5 0h4v-7h-4v7Zm5 0h1.5c.83 0 1.5-.67 1.5-1.5V10h-3v7Z"></path>' },
14310
+ "4-2": { viewBox: "0 0 19 17", body: '<path fill="currentColor" fill-rule="evenodd" d="M15 1h1.5c.83 0 1.5.67 1.5 1.5v5h-3zm-1 0h-4v6.5h4zM9 1H5v6.5h4zM4 1H2.5C1.67 1 1 1.67 1 2.5v5h3zM1 8.5v6c0 .83.67 1.5 1.5 1.5H9V8.5H1m9 7.5h6.5c.83 0 1.5-.67 1.5-1.5v-6h-8zM0 2.5A2.5 2.5 0 0 1 2.5 0h14A2.5 2.5 0 0 1 19 2.5v12a2.5 2.5 0 0 1-2.5 2.5h-14A2.5 2.5 0 0 1 0 14.5z"></path>' },
14311
+ "4-3": { viewBox: "0 0 19 17", body: '<path fill="currentColor" fill-rule="evenodd" d="M14 1h-4v7h4zm1 8h-2v7h3.5c.83 0 1.5-.67 1.5-1.5V9zm-3 7V9H7v7zM5 9h1v7H2.5A1.5 1.5 0 0 1 1 14.5V9h4m13-1V2.5c0-.83-.67-1.5-1.5-1.5H15v7zM1 8h3V1H2.5C1.67 1 1 1.67 1 2.5zm4 0h4V1H5zM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0z"></path>' },
14312
+ "7h": { viewBox: "0 0 21 19", body: '<g fill="none"><rect width="18" height="16" stroke="currentColor" rx="2" x="1.5" y="1.5"></rect><path fill="currentColor" d="M4 17V2h1v15H4Z"></path><path fill="currentColor" d="M7 17V2h1v15H7Z" opacity=".85"></path><path fill="currentColor" d="M10 17V2h1v15h-1Z" opacity=".65"></path><path fill="currentColor" d="M13 17V2h1v15h-1Z" opacity=".25"></path><path fill="currentColor" d="M16 17V2h1v15h-1Z" opacity=".05"></path></g>' },
14313
+ "7s": { viewBox: "0 0 19 17", body: '<g fill="currentColor"><path fill-rule="evenodd" d="M16.5 1h-14C1.67 1 1 1.67 1 2.5v12c0 .83.67 1.5 1.5 1.5h14c.83 0 1.5-.67 1.5-1.5v-12c0-.83-.67-1.5-1.5-1.5m-14-1A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0z"></path><path d="M9 3h9v1H9z"></path><path d="M9 17V1h1v16z"></path><path d="M9 6h9v1H9z" opacity=".65"></path><path d="M9 9h9v1H9z" opacity=".25"></path><path d="M9 12h9v1H9z" opacity=".05"></path></g>' },
14314
+ "8": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H4v7H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5H4V9H1Zm4 7h4V9H5v7Zm5 0h4V9h-4v7Zm5 0h1.5c.83 0 1.5-.67 1.5-1.5V9h-3v7Zm3-8V2.5c0-.83-.67-1.5-1.5-1.5H15v7h3Zm-4-7h-4v7h4V1ZM9 1H5v7h4V1ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
14315
+ "8c": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v3H1V2.5ZM1 5v3h8V5H1Zm0 4v3h8V9H1Zm0 4v1.5c0 .83.67 1.5 1.5 1.5H9v-3H1Zm9 3h6.5c.83 0 1.5-.67 1.5-1.5V13h-8v3Zm8-4V9h-8v3h8Zm0-4V5h-8v3h8Zm0-4V2.5c0-.83-.67-1.5-1.5-1.5H10v3h8ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
14316
+ "8h": { viewBox: "0 0 21 19", body: '<g fill="none"><rect width="18" height="16" stroke="currentColor" rx="2" x="1.5" y="1.5"></rect><path fill="currentColor" d="M4 17V2h1v15H4Z"></path><path fill="currentColor" d="M7 17V2h1v15H7Z" opacity=".85"></path><path fill="currentColor" d="M10 17V2h1v15h-1Z" opacity=".65"></path><path fill="currentColor" d="M13 17V2h1v15h-1Z" opacity=".25"></path><path fill="currentColor" d="M16 17V2h1v15h-1Z" opacity=".05"></path></g>' },
14317
+ "8v": { viewBox: "0 0 21 19", body: '<g fill="none"><rect width="18" height="16" stroke="currentColor" rx="2" x="1.5" y="1.5"></rect><path fill="currentColor" d="M1.5 4h18v1h-18V4Z"></path><path fill="currentColor" d="M2 7h18v1H2V7Z" opacity=".65"></path><path fill="currentColor" d="M1.5 10h18v1h-18v-1Z" opacity=".25"></path><path fill="currentColor" d="M1.5 13h18v1h-18v-1Z" opacity=".05"></path></g>' },
14318
+ "9s": { viewBox: "0 0 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M3.5 1A2.5 2.5 0 0 0 1 3.5v12A2.5 2.5 0 0 0 3.5 18h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 17.5 1h-14ZM7 2H3.5C2.67 2 2 2.67 2 3.5V6h5V2Zm1 0v4h5V2H8Zm0 5h5v5H8V7Zm-1 5V7H2v5h5Zm-5 1h5v4H3.5A1.5 1.5 0 0 1 2 15.5V13Zm6 0h5v4H8v-4Zm6 0v4h3.5c.83 0 1.5-.67 1.5-1.5V13h-5Zm5-1V7h-5v5h5ZM14 2v4h5V3.5c0-.83-.67-1.5-1.5-1.5H14Z"></path>' },
14319
+ "5-4": { viewBox: "0 0 19 17", body: '<path fill="currentColor" fill-rule="evenodd" d="M7 1H4v7h3zm1 0v7h3V1zm4 0v7h3V1zm0 8h-2v7h4V9zm3 0h3v5.5c0 .83-.67 1.5-1.5 1.5H15zm1-8v7h2V2.5c0-.83-.67-1.5-1.5-1.5zM8 9H5v7h4V9zM2.5 1H3v7H1V2.5C1 1.67 1.67 1 2.5 1M1 9h3v7H2.5A1.5 1.5 0 0 1 1 14.5zm1.5-9A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0z"></path>' },
14320
+ "9h": { viewBox: "0 0 21 19", body: '<g fill="none"><rect width="18" height="16" stroke="currentColor" rx="2" x="1.5" y="1.5"></rect><path fill="currentColor" d="M4 17V2h1v15H4Z"></path><path fill="currentColor" d="M7 17V2h1v15H7Z" opacity=".85"></path><path fill="currentColor" d="M10 17V2h1v15h-1Z" opacity=".65"></path><path fill="currentColor" d="M13 17V2h1v15h-1Z" opacity=".25"></path><path fill="currentColor" d="M16 17V2h1v15h-1Z" opacity=".05"></path></g>' },
14321
+ "9v": { viewBox: "0 0 21 19", body: '<g fill="none"><rect width="18" height="16" stroke="currentColor" rx="2" x="1.5" y="1.5"></rect><path fill="currentColor" d="M1.5 4h18v1h-18V4Z"></path><path fill="currentColor" d="M2 7h18v1H2V7Z" opacity=".65"></path><path fill="currentColor" d="M1.5 10h18v1h-18v-1Z" opacity=".25"></path><path fill="currentColor" d="M1.5 13h18v1h-18v-1Z" opacity=".05"></path></g>' },
14322
+ "10c5": { viewBox: "0 0 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M2 3.5C2 2.67 2.67 2 3.5 2H4v7H2V3.5ZM2 10v5.5c0 .83.67 1.5 1.5 1.5H4v-7H2Zm3 7h3v-7H5v7Zm4 0h3v-7H9v7Zm4 0h3v-7h-3v7Zm4 0h.5c.83 0 1.5-.67 1.5-1.5V10h-2v7Zm2-8V3.5c0-.83-.67-1.5-1.5-1.5H17v7h2Zm-3-7h-3v7h3V2Zm-4 0H9v7h3V2ZM8 2H5v7h3V2ZM3.5 1A2.5 2.5 0 0 0 1 3.5v12A2.5 2.5 0 0 0 3.5 18h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 17.5 1h-14Z"></path>' },
14323
+ "10h": { viewBox: "0 0 21 19", body: '<g fill="none"><rect width="18" height="16" stroke="currentColor" rx="2" x="1.5" y="1.5"></rect><path fill="currentColor" d="M4 17V2h1v15H4Z"></path><path fill="currentColor" d="M7 17V2h1v15H7Z" opacity=".85"></path><path fill="currentColor" d="M10 17V2h1v15h-1Z" opacity=".65"></path><path fill="currentColor" d="M13 17V2h1v15h-1Z" opacity=".25"></path><path fill="currentColor" d="M16 17V2h1v15h-1Z" opacity=".05"></path></g>' },
14324
+ "10v": { viewBox: "0 0 21 19", body: '<g fill="none"><rect width="18" height="16" stroke="currentColor" rx="2" x="1.5" y="1.5"></rect><path fill="currentColor" d="M1.5 4h18v1h-18V4Z"></path><path fill="currentColor" d="M2 7h18v1H2V7Z" opacity=".65"></path><path fill="currentColor" d="M1.5 10h18v1h-18v-1Z" opacity=".25"></path><path fill="currentColor" d="M1.5 13h18v1h-18v-1Z" opacity=".05"></path></g>' },
14325
+ "12c6": { viewBox: "0 0 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M2 3.5C2 2.67 2.67 2 3.5 2H4v7H2V3.5ZM2 10v5.5c0 .83.67 1.5 1.5 1.5H4v-7H2Zm3 7h2v-7H5v7Zm3 0h2v-7H8v7Zm3 0h2v-7h-2v7Zm3 0h2v-7h-2v7Zm3 0h.5c.83 0 1.5-.67 1.5-1.5V10h-2v7Zm2-8V3.5c0-.83-.67-1.5-1.5-1.5H17v7h2Zm-3-7h-2v7h2V2Zm-3 0h-2v7h2V2Zm-3 0H8v7h2V2ZM7 2H5v7h2V2ZM3.5 1A2.5 2.5 0 0 0 1 3.5v12A2.5 2.5 0 0 0 3.5 18h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 17.5 1h-14Z"></path>' },
14326
+ "12c4": { viewBox: "0 0 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M2 3.5C2 2.67 2.67 2 3.5 2H7v3H2v1h5v3H2v1h5v3H2v1h5v3H3.5A1.5 1.5 0 0 1 2 15.5v-12ZM8 14v3h5v-3H8Zm6 0v3h3.5c.83 0 1.5-.67 1.5-1.5V14h-5Zm5-1h-5v-3h5v3Zm-6 0H8v-3h5v3ZM8 9h5V6H8v3Zm6 0h5V6h-5v3Zm-1-4H8V2h5v3Zm1 13H3.5A2.5 2.5 0 0 1 1 15.5v-12A2.5 2.5 0 0 1 3.5 1h14A2.5 2.5 0 0 1 20 3.5v12a2.5 2.5 0 0 1-2.5 2.5H14Zm0-13V2h3.5c.83 0 1.5.67 1.5 1.5V5h-5Z"></path>' },
14327
+ "12h": { viewBox: "0 0 21 19", body: '<g fill="none"><rect width="18" height="16" stroke="currentColor" rx="2" x="1.5" y="1.5"></rect><path fill="currentColor" d="M4 17V2h1v15H4Z"></path><path fill="currentColor" d="M7 17V2h1v15H7Z" opacity=".85"></path><path fill="currentColor" d="M10 17V2h1v15h-1Z" opacity=".65"></path><path fill="currentColor" d="M13 17V2h1v15h-1Z" opacity=".25"></path><path fill="currentColor" d="M16 17V2h1v15h-1Z" opacity=".05"></path></g>' },
14328
+ "14c7": { viewBox: "0 0 21 19", body: '<g fill="none"><rect width="18" height="16" stroke="currentColor" rx="2" x="1.5" y="1.5"></rect><path fill="currentColor" d="M19 10H2V9h17v1Z"></path><path fill="currentColor" d="M4 17V2h1v15H4Z"></path><path fill="currentColor" d="M7 17V2h1v15H7Z" opacity=".85"></path><path fill="currentColor" d="M10 17V2h1v15h-1Z" opacity=".65"></path><path fill="currentColor" d="M13 17V2h1v15h-1Z" opacity=".25"></path><path fill="currentColor" d="M16 18V2h1v16h-1Z" opacity=".05"></path></g>' },
14329
+ "16c8": { viewBox: "0 0 21 19", body: '<g fill="none"><rect width="18" height="16" stroke="currentColor" rx="2" x="1.5" y="1.5"></rect><path fill="currentColor" d="M19 10H2V9h17v1Z"></path><path fill="currentColor" d="M4 17V2h1v15H4Z"></path><path fill="currentColor" d="M7 17V2h1v15H7Z" opacity=".85"></path><path fill="currentColor" d="M10 17V2h1v15h-1Z" opacity=".65"></path><path fill="currentColor" d="M13 17V2h1v15h-1Z" opacity=".25"></path><path fill="currentColor" d="M16 18V2h1v16h-1Z" opacity=".05"></path></g>' },
14330
+ "16c4": { viewBox: "0 0 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M3.5 2C2.67 2 2 2.67 2 3.5v12c0 .83.67 1.5 1.5 1.5H5v-3H2v-1h3v-3H2V9h3V6H2V5h3V2H3.5ZM6 14v3h4v-3H6Zm4-1H6v-3h4v3Zm1 1v3h4v-3h-4Zm4-1h-4v-3h4v3Zm1 1v3h1.5c.83 0 1.5-.67 1.5-1.5V14h-3Zm3-1h-3v-3h3v3Zm-8-4h4V6h-4v3Zm5-3v3h3V6h-3ZM6 9h4V6H6v3Zm0-4h4V2H6v3Zm10 13H3.5A2.5 2.5 0 0 1 1 15.5v-12A2.5 2.5 0 0 1 3.5 1h14A2.5 2.5 0 0 1 20 3.5v12a2.5 2.5 0 0 1-2.5 2.5H16Zm0-13V2h1.5c.83 0 1.5.67 1.5 1.5V5h-3Zm-1-3h-4v3h4V2Z"></path>' }
14331
+ };
14447
14332
 
14448
- // src/widget/legend.ts
14449
- var COMPARE_ROW_PREFIX = "cmp:";
14450
- var HOST_ROW_PREFIX = "host:";
14451
- function barIndexAt(bars, time) {
14452
- if (bars.length === 0) return -1;
14453
- if (time === null) return bars.length - 1;
14454
- let lo = 0;
14455
- let hi = bars.length - 1;
14456
- while (lo < hi) {
14457
- const mid = lo + hi + 1 >> 1;
14458
- if (bars[mid].t <= time) lo = mid;
14459
- else hi = mid - 1;
14460
- }
14461
- return lo;
14462
- }
14463
- var percentWriters = /* @__PURE__ */ new Map();
14464
- function percentText(fraction, tag) {
14465
- let writer = percentWriters.get(tag);
14466
- if (!writer) {
14467
- writer = new Intl.NumberFormat(tag);
14468
- percentWriters.set(tag, writer);
14469
- }
14470
- const points = Math.round(fraction * 1e4) / 100;
14471
- return `${points > 0 ? "+" : ""}${writer.format(points)}`;
14472
- }
14473
- function attachLegendPlane(deps) {
14474
- if (!deps.enabled) {
14475
- return {
14476
- push: () => void 0,
14477
- setHeader: () => void 0,
14478
- setDot: () => void 0,
14479
- setHostRows: () => void 0,
14480
- destroy: () => void 0
14481
- };
14482
- }
14483
- let destroyed = false;
14484
- const hostRows = /* @__PURE__ */ new Map();
14485
- const paneRemembered = /* @__PURE__ */ new Map();
14486
- const paneKeys = () => {
14487
- const keys = { 0: "main" };
14488
- for (const [id, pane] of Object.entries(deps.indicators.renderer.paneOf())) if (pane > 0) keys[pane] = `indicator:${id}`;
14489
- for (const entry of deps.compare?.api.list() ?? []) {
14490
- const pane = deps.compare.handle.paneIndexOf(entry.symbol);
14491
- if (pane !== null && pane > 0) keys[pane] = `compare:${entry.symbol}`;
14492
- }
14493
- return keys;
14494
- };
14495
- let legend2 = null;
14496
- let status2 = null;
14497
- let hovered = null;
14498
- let named = null;
14499
- let namedTimeframe = null;
14500
- legend2 = mountChartLegend(deps.chrome, deps.i18n, {
14501
- // Every row control is a COMMAND. The legend states an intent by id and the registry decides
14502
- // whether it may run, so a verb the host forbade cannot be reached by clicking either.
14503
- onToggleEye: (id) => {
14504
- if (id.startsWith(COMPARE_ROW_PREFIX)) {
14505
- const symbol = id.slice(COMPARE_ROW_PREFIX.length);
14506
- const entry = deps.compare?.api.list().find((e) => e.symbol === symbol);
14507
- if (entry) deps.commands.execute("chart.compare.setVisible", { symbol, visible: !entry.visible });
14508
- return;
14509
- }
14510
- deps.commands.execute(deps.indicators.isHidden(id) ? "chart.indicators.show" : "chart.indicators.hide", id);
14511
- },
14512
- onTitle: (id) => {
14513
- if (id.startsWith(COMPARE_ROW_PREFIX)) deps.commands.execute("chart.compare.changeSymbol", id.slice(COMPARE_ROW_PREFIX.length));
14514
- },
14515
- onRemove: (id) => {
14516
- if (id.startsWith(COMPARE_ROW_PREFIX)) deps.commands.execute("chart.compare.remove", id.slice(COMPARE_ROW_PREFIX.length));
14517
- else deps.commands.execute("chart.indicators.remove", id);
14518
- },
14519
- ...deps.symbolSearch ? { onSymbol: () => deps.openSearch() } : {},
14520
- painters: deps.painters,
14521
- icons: deps.icons,
14522
- ...deps.marketStatus ? {
14523
- onStatus: (anchor) => {
14524
- if (status2) {
14525
- status2.close();
14526
- return;
14527
- }
14528
- status2 = openMarketStatus(anchor, {
14529
- host: deps.chrome,
14530
- i18n: deps.i18n,
14531
- model: deps.sessionModel,
14532
- status: deps.status,
14533
- onClose: () => {
14534
- status2 = null;
14535
- }
14536
- });
14537
- }
14538
- } : {},
14539
- onSettings: (id, rect) => {
14540
- const host2 = hostRows.get(id);
14541
- if (host2) {
14542
- host2.onSettings?.();
14543
- return;
14544
- }
14545
- if (deps.openIndicatorSettings(id)) return;
14546
- const inst = deps.indicators.list().find((i) => i.id === id);
14547
- if (!inst) return;
14548
- openInputsEditor(
14549
- deps.chrome,
14550
- rect,
14551
- inst.definition.manifest.inputs ?? {},
14552
- { ...manifestInputDefaults(inst.definition.manifest), ...inst.inputs },
14553
- (patch) => deps.indicators.patchInputs(id, patch),
14554
- deps.i18n
14555
- );
14556
- },
14557
- onPaneOp: (id, op) => {
14558
- const paneIdx = deps.indicators.renderer.paneOf()[id];
14559
- if (paneIdx === void 0 || paneIdx === 0) return;
14560
- const panes = deps.chart.panes();
14561
- const heights = {};
14562
- panes.forEach((p, i) => heights[i] = p.getHeight());
14563
- const keys = paneKeys();
14564
- const remembered = {};
14565
- for (const [index, key] of Object.entries(keys)) {
14566
- const height = paneRemembered.get(key);
14567
- if (height !== void 0) remembered[Number(index)] = height;
14568
- }
14569
- const plan = planPaneOp({ heights, remembered }, { kind: op, pane: paneIdx });
14570
- paneRemembered.clear();
14571
- for (const [index, height] of Object.entries(plan.remembered)) {
14572
- const key = keys[Number(index)];
14573
- if (key) paneRemembered.set(key, height);
14574
- }
14575
- for (const [i, h2] of Object.entries(plan.apply)) {
14576
- const index = Number(i);
14577
- panes[index]?.setHeight(h2);
14578
- if (index > 0) deps.indicators.setPaneCollapsed(index, h2 <= COLLAPSED_H);
14579
- }
14580
- deps.indicators.recompute();
14581
- }
14582
- });
14583
- function reading() {
14584
- const bars = deps.bars();
14585
- const index = barIndexAt(bars, hovered);
14586
- const bar = index < 0 ? void 0 : bars[index];
14587
- if (!bar) return null;
14588
- const previous = index > 0 ? bars[index - 1] : void 0;
14589
- const format2 = deps.formatter();
14590
- const change = previous ? bar.c - previous.c : null;
14591
- const fraction = change !== null && previous && previous.c !== 0 ? change / previous.c : null;
14592
- return {
14593
- open: format2.format(bar.o),
14594
- high: format2.format(bar.h),
14595
- low: format2.format(bar.l),
14596
- close: format2.format(bar.c),
14597
- change: change === null ? null : `${change > 0 ? "+" : ""}${format2.format(change)}`,
14598
- percent: fraction === null ? null : percentText(fraction, deps.i18n.tag()),
14599
- direction: change === null || change === 0 ? "flat" : change > 0 ? "up" : "down"
14600
- };
14333
+ // src/ui/icons/catalog.ts
14334
+ var byMeaning = (table) => table;
14335
+ var CONTROL_ICONS = byMeaning({
14336
+ // The top bar and the widget's menus.
14337
+ compare: [ICONS.comparePlus],
14338
+ indicators: [ICONS.indicators],
14339
+ replay: [ICONS.replay],
14340
+ undo: [ICONS.undo],
14341
+ redo: [ICONS.redo],
14342
+ settings: [ICONS.settings, ICONS.gear, ICONS.legendSettings],
14343
+ fullscreen: [ICONS.fullscreen],
14344
+ fullscreenExit: [ICONS.exitFullscreen],
14345
+ image: [ICONS.camera],
14346
+ download: [ICONS.download],
14347
+ copy: [ICONS.copy],
14348
+ caret: [ICONS.menuArrowWide],
14349
+ info: [ICONS.info],
14350
+ // The legend.
14351
+ visible: [ICONS.legendEye],
14352
+ hidden: [ICONS.legendEyeOff],
14353
+ collapse: [ICONS.legendChevron],
14354
+ paneCollapse: [ICONS.paneCollapse],
14355
+ paneRestore: [ICONS.paneRestore],
14356
+ paneMaximize: [ICONS.paneMaximize],
14357
+ marketStatus: [ICONS.marketStatus],
14358
+ replayStatus: [ICONS.replayStatus],
14359
+ replayMark: [ICONS.replayMark],
14360
+ replayCut: [ICONS.replayCut],
14361
+ // The navigation cluster.
14362
+ zoomIn: [ICONS.navZoomIn],
14363
+ zoomOut: [ICONS.navZoomOut],
14364
+ scroll: [ICONS.navScroll],
14365
+ reset: [ICONS.navReset],
14366
+ tileMaximize: [ICONS.tileMaximize],
14367
+ tileRestore: [ICONS.tileRestore],
14368
+ // Rows, lists and dialogs.
14369
+ check: [ICONS.check],
14370
+ close: [ICONS.close, ICONS.closeThin, ICONS.dialogClose],
14371
+ remove: [ICONS.close18, ICONS.removeRow],
14372
+ delete: [ICONS.trash, ICONS.trash28],
14373
+ add: [ICONS.plus, ICONS.plusThin, ICONS.plus24],
14374
+ search: [ICONS.search, ICONS.search24],
14375
+ clear: [ICONS.clear],
14376
+ open: [ICONS.folder],
14377
+ rename: [ICONS.pencil],
14378
+ duplicate: [ICONS.clone],
14379
+ favorite: [ICONS.star, ICONS.pickerStar],
14380
+ favorited: [ICONS.starFilled, ICONS.pickerStarFilled],
14381
+ sortAscending: [ICONS.sortUp, ICONS.sortUpRow],
14382
+ sortDescending: [ICONS.sortDown, ICONS.sortDownRow],
14383
+ chevronUp: [ICONS.chevronUp],
14384
+ chevronDown: [ICONS.chevronDown, ICONS.chevronDown18],
14385
+ chevronLeft: [ICONS.chevronLeft],
14386
+ chevronRight: [ICONS.chevronRight],
14387
+ // The drawing toolbar's arrow, pointing where the flyout it opens will stand.
14388
+ flyout: [ICONS.chevronRight16],
14389
+ submenu: [ICONS.submenuArrow],
14390
+ more: [ICONS.kebab],
14391
+ grip: [ICONS.grip],
14392
+ emptySearch: [SEARCH_EMPTY_MARK],
14393
+ emptyCompare: [COMPARE_EMPTY_MARK],
14394
+ // The symbol search's spread builder.
14395
+ operatorsShow: [ICONS.spreadOpsShow],
14396
+ operatorsHide: [ICONS.spreadOpsHide],
14397
+ operatorAdd: [OPERATOR_GLYPHS.addition],
14398
+ operatorSubtract: [OPERATOR_GLYPHS.subtraction],
14399
+ operatorMultiply: [OPERATOR_GLYPHS.multiplication],
14400
+ operatorDivide: [OPERATOR_GLYPHS.division],
14401
+ operatorPower: [OPERATOR_GLYPHS.exponentiation],
14402
+ operatorReciprocal: [OPERATOR_GLYPHS.reciprocal],
14403
+ // The replay transport.
14404
+ play: [ICONS.play],
14405
+ pause: [ICONS.pause],
14406
+ stepForward: [ICONS.stepForward],
14407
+ stepBack: [ICONS.stepBack],
14408
+ goLive: [ICONS.goLive],
14409
+ selectBar: [ICONS.selectBar],
14410
+ selectDate: [ICONS.calendar],
14411
+ firstAvailable: [ICONS.firstAvailable],
14412
+ randomBar: [ICONS.randomBar],
14413
+ // The drawing toolbar, its menus, the favorites bar and the drawing settings.
14414
+ cursorCross: [ICONS.cursorCross],
14415
+ cursorDot: [ICONS.cursorDot],
14416
+ cursorArrow: [ICONS.cursorArrow],
14417
+ eraser: [ICONS.eraser],
14418
+ measure: [ICONS.ruler],
14419
+ zoomTool: [ICONS.zoomIn],
14420
+ magnet: [ICONS.magnet],
14421
+ magnetStrong: [ICONS.magnetStrong],
14422
+ stayInMode: [ICONS.pin],
14423
+ stayInModeOn: [ICONS.pinOn],
14424
+ locked: [ICONS.lockClosed],
14425
+ unlocked: [ICONS.lockOpen],
14426
+ drawingsShown: [ICONS.drawingsShown],
14427
+ drawingsHidden: [ICONS.drawingsHidden],
14428
+ indicatorsShown: [ICONS.indicatorsShown],
14429
+ indicatorsHidden: [ICONS.indicatorsHidden],
14430
+ allShown: [ICONS.allShown],
14431
+ allHidden: [ICONS.allHidden],
14432
+ hide: [ICONS.eyeCrossed],
14433
+ sync: [ICONS.sync],
14434
+ glyphTools: [ICONS.groupGlyphs],
14435
+ favoritesBar: [ICONS.favoritesBar],
14436
+ template: [ICONS.template],
14437
+ visualOrder: [ICONS.layers],
14438
+ lineColor: [ICONS.pencil16],
14439
+ fillColor: [ICONS.bucket],
14440
+ textColor: [ICONS.textTee],
14441
+ lineSolid: [ICONS.lineSolid],
14442
+ lineDashed: [ICONS.lineDashed],
14443
+ lineDotted: [ICONS.lineDotted],
14444
+ lineThickness1: [ICONS.lineThickness1],
14445
+ lineThickness2: [ICONS.lineThickness2],
14446
+ lineThickness3: [ICONS.lineThickness3],
14447
+ lineThickness4: [ICONS.lineThickness4],
14448
+ // Drawn for a line's left end; the right end wears the same drawing mirrored.
14449
+ lineEndNormal: [ICONS.lineEndNormal],
14450
+ lineEndArrow: [ICONS.lineEndArrow]
14451
+ });
14452
+ var MIRRORED_ICONS = /* @__PURE__ */ new Set(["flyout"]);
14453
+ var MINIATURE_TOOLS = Object.keys(TOOL_ICONS);
14454
+ var ARRANGEMENT_CODES = Object.keys(ARRANGEMENT_ICONS);
14455
+ var toolGlyphs = new Map(MINIATURE_TOOLS.map((type) => [type, { viewBox: "0 0 28 28", body: TOOL_ICONS[type] }]));
14456
+ var arrangementGlyphs = new Map(ARRANGEMENT_CODES.map((code) => [code, { viewBox: ARRANGEMENT_ICONS[code].viewBox, body: ARRANGEMENT_ICONS[code].body }]));
14457
+ var toolGlyph = (type) => toolGlyphs.get(type);
14458
+ var arrangementGlyphOf = (code) => arrangementGlyphs.get(code);
14459
+ var CHART_ICON_IDS = [
14460
+ ...Object.keys(CONTROL_ICONS),
14461
+ ...CHART_STYLES.map((style) => `style.${style}`),
14462
+ ...MINIATURE_TOOLS.map((type) => `tool.${type}`),
14463
+ ...ARRANGEMENT_CODES.map((code) => `layout.${code}`)
14464
+ ];
14465
+ var PUBLISHED = new Set(CHART_ICON_IDS);
14466
+ var ICON_OF = /* @__PURE__ */ new WeakMap();
14467
+ for (const [id, glyphs] of Object.entries(CONTROL_ICONS)) for (const mark of glyphs) ICON_OF.set(mark, id);
14468
+ for (const style of CHART_STYLES) ICON_OF.set(STYLE_ICONS[style], `style.${style}`);
14469
+ for (const type of MINIATURE_TOOLS) ICON_OF.set(toolGlyphs.get(type), `tool.${type}`);
14470
+ for (const code of ARRANGEMENT_CODES) ICON_OF.set(arrangementGlyphs.get(code), `layout.${code}`);
14471
+ var iconOf = (mark) => ICON_OF.get(mark);
14472
+ var GLYPHS_OF = new Map([
14473
+ ...Object.entries(CONTROL_ICONS),
14474
+ ...CHART_STYLES.map((style) => [`style.${style}`, [STYLE_ICONS[style]]]),
14475
+ ...MINIATURE_TOOLS.map((type) => [`tool.${type}`, [toolGlyphs.get(type)]]),
14476
+ ...ARRANGEMENT_CODES.map((code) => [`layout.${code}`, [arrangementGlyphs.get(code)]])
14477
+ ]);
14478
+ var standsAlone = (mark) => !/var\(--|class=/.test(mark.body);
14479
+ function chartIconArtwork(id) {
14480
+ const glyphs = GLYPHS_OF.get(id) ?? [];
14481
+ if (!glyphs.every(standsAlone)) return [];
14482
+ return glyphs.map((mark) => ({
14483
+ viewBox: mark.viewBox,
14484
+ body: mark.body,
14485
+ svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="${mark.viewBox}" fill="none">${mark.body}</svg>`
14486
+ }));
14487
+ }
14488
+ function checkIcons(icons) {
14489
+ if (icons === void 0) return;
14490
+ if (typeof icons !== "object" || icons === null || Array.isArray(icons)) throw new TypeError("icons must be an object");
14491
+ for (const [id, factory] of Object.entries(icons)) {
14492
+ if (!PUBLISHED.has(id)) throw new TypeError(`icons.${id} is not an icon the chart draws; CHART_ICON_IDS lists every one`);
14493
+ if (factory !== void 0 && typeof factory !== "function") throw new TypeError(`icons.${id} must be a function that draws the icon`);
14601
14494
  }
14602
- const paint = () => {
14603
- if (destroyed) return;
14604
- const alive = new Set(Object.values(paneKeys()));
14605
- for (const key of paneRemembered.keys()) if (!alive.has(key)) paneRemembered.delete(key);
14606
- legend2?.setValueShaped(deps.valueShaped());
14607
- legend2?.setQuote(deps.legendValues ? reading() : null);
14608
- const paneOf = deps.indicators.renderer.paneOf();
14609
- const shown2 = (command2) => deps.shown?.(command2) ?? true;
14610
- legend2?.setChips([
14611
- ...deps.indicators.chipsAt(hovered).map((row2) => {
14612
- const paneIndex = paneOf[row2.id] ?? 0;
14613
- const remembered = paneRemembered.get(`indicator:${row2.id}`);
14614
- return {
14615
- ...row2,
14616
- paneIndex,
14617
- maximized: remembered !== void 0 && !row2.collapsed && (deps.chart.panes()[paneIndex]?.getHeight() ?? 0) > remembered,
14618
- ...shown2(row2.hidden ? "chart.indicators.show" : "chart.indicators.hide") ? {} : { hideable: false },
14619
- ...shown2("chart.indicators.remove") ? {} : { removable: false }
14620
- };
14621
- }),
14622
- ...(deps.compare?.chips(hovered) ?? []).map((row2) => ({
14623
- ...row2,
14624
- paneIndex: deps.compare.handle.paneIndexOf(row2.id.slice(COMPARE_ROW_PREFIX.length)) ?? 0,
14625
- ...shown2("chart.compare.setVisible") ? {} : { hideable: false },
14626
- ...shown2("chart.compare.remove") ? {} : { removable: false }
14627
- })),
14628
- ...[...hostRows].map(([id, row2]) => ({
14629
- id,
14630
- title: row2.title,
14631
- inputs: row2.inputs,
14632
- value: null,
14633
- note: row2.status,
14634
- description: row2.description,
14635
- settingsLabel: row2.settingsLabel,
14636
- hidden: false,
14637
- hideable: false,
14638
- removable: false,
14639
- hasInputs: !!row2.onSettings,
14640
- paneIndex: 0
14641
- }))
14642
- ]);
14643
- const tops = {};
14644
- let top = 0;
14645
- const panes = deps.chart.panes();
14646
- const first = panes[0]?.getHTMLElement()?.getBoundingClientRect();
14647
- for (const [index, pane] of panes.entries()) {
14648
- const element = pane.getHTMLElement();
14649
- const rect = element?.getBoundingClientRect();
14650
- tops[index] = rect && first && rect.height > 0 ? rect.top - first.top : top;
14651
- top += pane.getHeight();
14652
- if (element && !observed.has(element)) {
14653
- observed.add(element);
14654
- resize?.observe(element);
14655
- }
14656
- }
14657
- const current = new Set(panes.map((pane) => pane.getHTMLElement()));
14658
- for (const element of observed) if (!current.has(element)) {
14659
- resize?.unobserve(element);
14660
- observed.delete(element);
14661
- }
14662
- legend2?.setPaneTops(tops);
14663
- try {
14664
- const start = deps.chart.priceScale("left").width();
14665
- const end = deps.chart.priceScale("right").width();
14666
- legend2?.setScaleInsets(start, end, deps.chart.timeScale().height());
14667
- deps.chrome.style.setProperty("--qcp-plot-start", `${start}px`);
14668
- deps.chrome.style.setProperty("--qcp-plot-end", `${end}px`);
14669
- } catch {
14670
- }
14671
- };
14672
- const observed = /* @__PURE__ */ new Set();
14673
- const resize = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(() => paint());
14674
- const onCrosshair = (param) => {
14675
- if (deps.replayPhase() === "arming")
14676
- legend2?.setReplayGuide(param.point ? { x: param.point.x, y: param.point.y } : null, deps.chart.timeScale().height());
14677
- const next = typeof param.time === "number" && Number.isFinite(param.time) ? param.time : null;
14678
- if (next === hovered) return;
14679
- hovered = next;
14680
- paint();
14681
- };
14682
- deps.chart.subscribeCrosshairMove(onCrosshair);
14683
- return {
14684
- setHostRows(rows2) {
14685
- if (destroyed) return;
14686
- hostRows.clear();
14687
- for (const row2 of rows2) hostRows.set(`${HOST_ROW_PREFIX}${row2.id}`, { ...row2 });
14688
- paint();
14689
- },
14690
- push() {
14691
- paint();
14692
- },
14693
- setHeader(symbol, tf) {
14694
- if (symbol !== named || deps.replayPhase() !== "off") {
14695
- status2?.close();
14696
- status2 = null;
14697
- }
14698
- legend2?.setReplay(deps.replayPhase());
14699
- if (symbol !== named || tf !== namedTimeframe) {
14700
- named = symbol;
14701
- namedTimeframe = tf;
14702
- hovered = null;
14703
- }
14704
- const info = deps.symbolInfo();
14705
- const label2 = symbolNames(info ?? symbol).title;
14706
- legend2?.setIdentity({ name: label2, symbol, timeframe: tf, exchange: info?.exchange ?? "" });
14707
- },
14708
- setDot(state) {
14709
- const current = deps.status(Math.floor(Date.now() / 1e3));
14710
- legend2?.setDot(state, current ? marketStatusTitle(deps.i18n.t, current) : deps.i18n.t("status.unknownTitle"));
14711
- status2?.refresh();
14712
- },
14713
- destroy() {
14714
- destroyed = true;
14715
- hostRows.clear();
14716
- resize?.disconnect();
14717
- observed.clear();
14718
- deps.chart.unsubscribeCrosshairMove(onCrosshair);
14719
- status2?.close();
14720
- status2 = null;
14721
- legend2?.destroy();
14722
- legend2 = null;
14723
- }
14724
- };
14725
14495
  }
14726
14496
 
14727
- // src/widget/fling.ts
14728
- function attachFling(deps) {
14729
- const scale = () => deps.chart.timeScale();
14730
- let samples = [];
14731
- let movedAt = null;
14732
- let oneFinger = false;
14733
- let frame = null;
14734
- const stop = () => {
14735
- if (frame !== null && typeof cancelAnimationFrame === "function") cancelAnimationFrame(frame);
14736
- frame = null;
14497
+ // src/ui/icons/resolver.ts
14498
+ function createIconResolver(deps) {
14499
+ checkIcons(deps.icons);
14500
+ const icons = deps.icons ?? {};
14501
+ const standing = /* @__PURE__ */ new Set();
14502
+ const forget = new FinalizationRegistry((record3) => standing.delete(record3));
14503
+ const draw = (factory, box, icon) => {
14504
+ const direction = deps.direction();
14505
+ const drawn = drawHostIcon(factory, { document: deps.document, width: box.width, height: box.height, direction });
14506
+ if ("failure" in drawn) {
14507
+ deps.diagnostics.report(icon, drawn.failure);
14508
+ return null;
14509
+ }
14510
+ const record3 = { element: new WeakRef(drawn.element), factory, box, icon, direction };
14511
+ standing.add(record3);
14512
+ forget.register(drawn.element, record3, record3);
14513
+ return drawn.element;
14737
14514
  };
14738
- const record3 = (t) => {
14739
- samples.push({ t, position: scale().scrollPosition() });
14740
- while (samples.length > 2 && samples[0].t < t - 2 * FLING_SAMPLE_MS) samples.shift();
14515
+ const host2 = (id, box) => {
14516
+ const factory = icons[id];
14517
+ return factory ? draw(factory, box, id) : null;
14741
14518
  };
14742
- const coast = (speed) => {
14743
- if (typeof requestAnimationFrame !== "function") return;
14744
- let last = performance.now();
14745
- let travelling = speed;
14746
- let position = null;
14747
- const step = (now) => {
14748
- if (frame === null) return;
14749
- const s = scale();
14750
- position ??= s.scrollPosition();
14751
- const next = flingStep(travelling, Math.max(0, now - last));
14752
- last = now;
14753
- travelling = next.speed;
14754
- position += next.moved;
14755
- s.scrollToPosition(position, false);
14756
- if (Math.abs(travelling) * s.options().barSpacing < FLING_REST_PX_PER_MS) {
14757
- frame = null;
14758
- return;
14519
+ const redraw = () => {
14520
+ const direction = deps.direction();
14521
+ for (const record3 of [...standing]) {
14522
+ if (record3.direction === direction) continue;
14523
+ const element = record3.element.deref();
14524
+ if (!element) {
14525
+ standing.delete(record3);
14526
+ continue;
14759
14527
  }
14760
- frame = requestAnimationFrame(step);
14761
- };
14762
- frame = requestAnimationFrame(step);
14763
- };
14764
- const onStart = (event) => {
14765
- stop();
14766
- samples = [];
14767
- movedAt = null;
14768
- oneFinger = event.touches.length === 1;
14769
- if (oneFinger) record3(performance.now());
14528
+ if (!element.parentNode) continue;
14529
+ const fresh = draw(record3.factory, record3.box, record3.icon);
14530
+ if (!fresh) continue;
14531
+ element.replaceWith(fresh);
14532
+ standing.delete(record3);
14533
+ forget.unregister(record3);
14534
+ }
14770
14535
  };
14771
- const onMove = (event) => {
14772
- if (event.touches.length !== 1) oneFinger = false;
14773
- if (!oneFinger) return;
14774
- if (movedAt !== null) record3(movedAt);
14775
- movedAt = performance.now();
14536
+ const glyph2 = (mark, options = {}) => {
14537
+ const id = iconOf(mark);
14538
+ if (id) {
14539
+ const width = options.size ?? mark.size ?? 28;
14540
+ const drawn = host2(id, { width, height: options.height ?? width });
14541
+ if (drawn) {
14542
+ const span = deps.document.createElement("span");
14543
+ span.className = `qc-icon${options.className ? ` ${options.className}` : ""}`;
14544
+ span.setAttribute("aria-hidden", "true");
14545
+ span.append(drawn);
14546
+ return span;
14547
+ }
14548
+ }
14549
+ return glyph(mark, options);
14776
14550
  };
14777
- const onEnd = (event) => {
14778
- const thrown = oneFinger && event.touches.length === 0;
14779
- oneFinger = false;
14780
- if (!thrown) return;
14781
- if (movedAt !== null) record3(movedAt);
14782
- const spacing = scale().options().barSpacing;
14783
- const speed = flingSpeed(samples, performance.now(), spacing);
14784
- samples = [];
14785
- movedAt = null;
14786
- if (Math.abs(speed) * spacing >= FLING_REST_PX_PER_MS) coast(speed);
14551
+ const widthFor = (mark, height) => mark.aspect === void 0 ? height : Math.round(height * mark.aspect * 1e3) / 1e3;
14552
+ const ownSvg = (mark, width, height) => {
14553
+ const holder = deps.document.createElement("span");
14554
+ holder.innerHTML = `<svg width="${width}" height="${height}" viewBox="${mark.viewBox}" fill="none" aria-hidden="true">${mark.body}</svg>`;
14555
+ return holder.firstElementChild;
14787
14556
  };
14788
- const onCancel = () => {
14789
- oneFinger = false;
14790
- samples = [];
14791
- movedAt = null;
14557
+ const bare = (mark, width, height) => {
14558
+ const id = iconOf(mark);
14559
+ return (id ? host2(id, { width, height }) : null) ?? ownSvg(mark, width, height);
14792
14560
  };
14793
- deps.target.addEventListener("touchstart", onStart, { passive: true });
14794
- deps.target.addEventListener("touchmove", onMove, { passive: true });
14795
- deps.target.addEventListener("touchend", onEnd, { passive: true });
14796
- deps.target.addEventListener("touchcancel", onCancel, { passive: true });
14797
14561
  return {
14798
- stop,
14799
- destroy() {
14800
- stop();
14801
- deps.target.removeEventListener("touchstart", onStart);
14802
- deps.target.removeEventListener("touchmove", onMove);
14803
- deps.target.removeEventListener("touchend", onEnd);
14804
- deps.target.removeEventListener("touchcancel", onCancel);
14805
- }
14562
+ glyph: glyph2,
14563
+ icon(name2, requested) {
14564
+ const mark = ICONS[name2];
14565
+ const height = requested ?? mark.size ?? 28;
14566
+ return bare(mark, widthFor(mark, height), height);
14567
+ },
14568
+ tool(type, size = 28) {
14569
+ const mark = toolGlyph(type);
14570
+ return mark ? bare(mark, size, size) : null;
14571
+ },
14572
+ host: host2,
14573
+ draw,
14574
+ redraw
14806
14575
  };
14807
14576
  }
14808
14577
 
14809
- // src/widget/pinch.ts
14810
- function attachPinch(deps) {
14811
- const scale = () => deps.chart.timeScale();
14812
- let pinch = null;
14813
- let panned = false;
14814
- const read = (touches) => {
14815
- const a = touches[0];
14816
- const b = touches[1];
14817
- const left = deps.chart.chartElement().getBoundingClientRect().left + deps.chart.priceScale("left").width();
14818
- return { distance: Math.hypot(a.clientX - b.clientX, a.clientY - b.clientY), x: (a.clientX + b.clientX) / 2 - left };
14819
- };
14820
- const begin = (event) => {
14821
- pinch = null;
14822
- if (event.touches.length === 1) panned = false;
14823
- if (event.touches.length !== 2 || panned || !scalingOpen(deps.chart.options().handleScale)) return;
14824
- const range2 = scale().getVisibleLogicalRange();
14825
- if (range2 === null) return;
14826
- const { distance, x } = read(event.touches);
14827
- pinch = pinchStart(range2, scale().width(), x, distance);
14828
- };
14829
- const move = (event) => {
14830
- if (event.touches.length === 1 && pinch === null) panned = true;
14831
- if (pinch === null || event.touches.length !== 2) return;
14832
- if (!scalingOpen(deps.chart.options().handleScale)) {
14833
- pinch = null;
14834
- return;
14578
+ // src/inputsEditor.ts
14579
+ var titleOf = (key, titles) => titles?.[key] ?? key.replace(/([a-z])([A-Z])/g, "$1 $2").replace(/^./, (c) => c.toUpperCase());
14580
+ function buildInputFields(icons, inputs2, current, titles) {
14581
+ const fields = /* @__PURE__ */ new Map();
14582
+ const rows2 = [];
14583
+ for (const [key, spec] of Object.entries(inputs2)) {
14584
+ const row2 = document.createElement("label");
14585
+ row2.className = "qc-inputs-row";
14586
+ const name2 = document.createElement("span");
14587
+ name2.textContent = titleOf(key, titles);
14588
+ row2.appendChild(name2);
14589
+ if (spec.kind === "enum") {
14590
+ const select = document.createElement("select");
14591
+ select.className = "qc-field qc-inputs-select";
14592
+ (spec.options ?? []).forEach((label2, i) => {
14593
+ const o = document.createElement("option");
14594
+ o.value = String(i);
14595
+ o.textContent = label2;
14596
+ select.appendChild(o);
14597
+ });
14598
+ select.value = String(current[key] ?? spec.default);
14599
+ fields.set(key, select);
14600
+ row2.appendChild(selectField(select, icons));
14601
+ } else {
14602
+ const input = document.createElement("input");
14603
+ input.type = "number";
14604
+ input.className = "qc-field qc-inputs-field";
14605
+ if (spec.min !== void 0) input.min = String(spec.min);
14606
+ if (spec.max !== void 0) input.max = String(spec.max);
14607
+ input.step = spec.kind === "int" ? "1" : "any";
14608
+ input.value = String(current[key] ?? spec.default);
14609
+ fields.set(key, input);
14610
+ row2.appendChild(input);
14835
14611
  }
14836
- const { distance, x } = read(event.touches);
14837
- const s = scale();
14838
- const width = s.width();
14839
- const options = s.options();
14840
- const plot = { width, minSpacing: options.minBarSpacing, maxSpacing: options.maxBarSpacing > 0 ? options.maxBarSpacing : width / 2 };
14841
- s.setVisibleLogicalRange(pinchRange(pinch, x, distance, plot));
14612
+ rows2.push(row2);
14613
+ }
14614
+ return {
14615
+ rows: rows2,
14616
+ read() {
14617
+ const patch = {};
14618
+ for (const [key, field] of fields) {
14619
+ const spec = inputs2[key];
14620
+ let value = Number(field.value);
14621
+ if (!Number.isFinite(value)) continue;
14622
+ if (spec.kind === "int" || spec.kind === "enum") value = Math.round(value);
14623
+ if (spec.min !== void 0) value = Math.max(spec.min, value);
14624
+ if (spec.max !== void 0) value = Math.min(spec.max, value);
14625
+ patch[key] = value;
14626
+ }
14627
+ return patch;
14628
+ },
14629
+ first: () => fields.values().next().value ?? null
14842
14630
  };
14843
- const end = (event) => {
14844
- if (event.touches.length === 1) panned = false;
14845
- if (event.touches.length === 2) begin(event);
14846
- else pinch = null;
14631
+ }
14632
+ function openInputsEditor(container, rect, inputs2, current, onApply, strings = createChartI18n()) {
14633
+ const icons = createIconResolver({ document: container.ownerDocument, direction: () => readingDirection(strings), diagnostics: createIconDiagnostics() });
14634
+ mountInputsEditor(container, rect, inputs2, current, onApply, strings, icons);
14635
+ }
14636
+ function mountInputsEditor(container, rect, inputs2, current, onApply, strings, icons) {
14637
+ const host2 = container.getBoundingClientRect();
14638
+ const el2 = document.createElement("div");
14639
+ el2.className = "qc-overlay qc-inputs";
14640
+ el2.setAttribute("role", "dialog");
14641
+ el2.setAttribute("aria-label", strings.t("legend.indicatorSettings"));
14642
+ el2.style.left = `${Math.max(4, rect.x - host2.left)}px`;
14643
+ el2.style.top = `${Math.max(4, rect.y - host2.top + rect.h + 4)}px`;
14644
+ for (const type of ["pointerdown", "pointerup", "pointermove"]) el2.addEventListener(type, (e) => e.stopPropagation());
14645
+ const dismiss = () => {
14646
+ unsubscribe();
14647
+ el2.remove();
14847
14648
  };
14848
- deps.target.addEventListener("touchstart", begin, { passive: true });
14849
- deps.target.addEventListener("touchmove", move, { passive: true });
14850
- deps.target.addEventListener("touchend", end, { passive: true });
14851
- deps.target.addEventListener("touchcancel", end, { passive: true });
14852
- return {
14853
- destroy() {
14854
- pinch = null;
14855
- deps.target.removeEventListener("touchstart", begin);
14856
- deps.target.removeEventListener("touchmove", move);
14857
- deps.target.removeEventListener("touchend", end);
14858
- deps.target.removeEventListener("touchcancel", end);
14859
- }
14649
+ const fields = buildInputFields(icons, inputs2, current);
14650
+ for (const row2 of fields.rows) el2.appendChild(row2);
14651
+ const apply = () => {
14652
+ onApply(fields.read());
14653
+ dismiss();
14654
+ };
14655
+ const buttons = document.createElement("div");
14656
+ buttons.className = "qc-inputs-actions";
14657
+ const mkButton = (label2, onClick, primary = false) => {
14658
+ const b = document.createElement("button");
14659
+ b.type = "button";
14660
+ b.className = primary ? "qc-button qc-button--primary" : "qc-button";
14661
+ b.textContent = label2;
14662
+ b.addEventListener("click", onClick);
14663
+ buttons.appendChild(b);
14664
+ return b;
14860
14665
  };
14666
+ const cancelButton = mkButton(strings.t("inputs.cancel"), () => dismiss());
14667
+ const applyButton = mkButton(strings.t("inputs.apply"), apply, true);
14668
+ el2.appendChild(buttons);
14669
+ const unsubscribe = strings.onChange(() => {
14670
+ cancelButton.textContent = strings.t("inputs.cancel");
14671
+ applyButton.textContent = strings.t("inputs.apply");
14672
+ el2.setAttribute("aria-label", strings.t("legend.indicatorSettings"));
14673
+ });
14674
+ el2.addEventListener("keydown", (e) => {
14675
+ e.stopPropagation();
14676
+ if (e.key === "Enter") apply();
14677
+ else if (e.key === "Escape") dismiss();
14678
+ });
14679
+ container.appendChild(el2);
14680
+ fields.first()?.focus?.();
14861
14681
  }
14862
14682
 
14863
- // src/widget/freePan.ts
14864
- function attachFreePan(deps) {
14865
- let landed = null;
14866
- const onPlot = (clientX, clientY) => {
14867
- const box = deps.chart.chartElement().getBoundingClientRect();
14868
- const left = box.left + deps.chart.priceScale("left").width();
14869
- const right = left + deps.chart.timeScale().width();
14870
- return clientX >= left && clientX <= right && clientY >= box.top && clientY <= box.bottom - deps.chart.timeScale().height();
14683
+ // src/ui/chrome/menu.ts
14684
+ var HOST_MARGIN = 8;
14685
+ var byAnchor = /* @__PURE__ */ new WeakMap();
14686
+ function toggleMenu(anchor, open2) {
14687
+ const current = byAnchor.get(anchor);
14688
+ if (current?.open()) current.close();
14689
+ else open2();
14690
+ }
14691
+ function openMenu(options) {
14692
+ const { anchor, host: host2 } = options;
14693
+ const previous = byAnchor.get(anchor);
14694
+ const rtl = isRtl(anchor);
14695
+ const role = options.role ?? "menu";
14696
+ const element = h("div", {
14697
+ class: `qc-overlay qc-menu-panel${options.className ? ` ${options.className}` : ""}`,
14698
+ role,
14699
+ "aria-label": options.label,
14700
+ ...role === "dialog" ? { "aria-modal": "false" } : {}
14701
+ });
14702
+ if (options.width) element.style.width = `${options.width}px`;
14703
+ stopPointer(element);
14704
+ const body = h("div", { class: "qc-menu-body" });
14705
+ element.appendChild(body);
14706
+ const footer = options.footer ? h("div", { class: "qc-menu-footer" }) : null;
14707
+ if (footer) element.appendChild(footer);
14708
+ let isOpen = true;
14709
+ const previouslyFocused = document.activeElement;
14710
+ const escape = pushEscapeOwner();
14711
+ let untrack = () => void 0;
14712
+ const close = () => {
14713
+ if (!isOpen) return;
14714
+ isOpen = false;
14715
+ escape.release();
14716
+ const ownedAnchor = byAnchor.get(anchor) === handle;
14717
+ if (ownedAnchor) byAnchor.delete(anchor);
14718
+ untrack();
14719
+ document.removeEventListener("pointerdown", onOutside, true);
14720
+ document.removeEventListener("keydown", onDocumentKey, true);
14721
+ window.removeEventListener("resize", reposition);
14722
+ if (ownedAnchor) anchor.setAttribute("aria-expanded", "false");
14723
+ element.remove();
14724
+ options.onClose?.();
14725
+ if (byAnchor.get(anchor)?.open()) return;
14726
+ const target = document.activeElement === document.body || document.activeElement === null || element.contains(document.activeElement) ? anchor : previouslyFocused;
14727
+ target?.focus();
14871
14728
  };
14872
- const release = () => {
14873
- if (deps.framing()) deps.release();
14729
+ const reposition = () => {
14730
+ if (!isOpen) return;
14731
+ const a = anchor.getBoundingClientRect();
14732
+ const bounds = host2.getBoundingClientRect();
14733
+ const below = (options.placement ?? "down") === "down";
14734
+ if (!below) element.style.maxHeight = `${Math.max(0, Math.floor(a.top - bounds.top - HOST_MARGIN - 2))}px`;
14735
+ element.style.left = "0px";
14736
+ element.style.top = "0px";
14737
+ const box = element.getBoundingClientRect();
14738
+ const alignEnd = (options.align ?? "start") === (rtl ? "start" : "end");
14739
+ let left = (alignEnd ? a.right - box.width : a.left) - bounds.left;
14740
+ left = Math.max(HOST_MARGIN, Math.min(left, Math.max(HOST_MARGIN, bounds.width - box.width - HOST_MARGIN)));
14741
+ let top = (below ? a.bottom + 2 : a.top - box.height - 2) - bounds.top;
14742
+ top = Math.max(HOST_MARGIN, Math.min(top, Math.max(HOST_MARGIN, bounds.height - box.height - HOST_MARGIN)));
14743
+ element.style.left = `${Math.round(left)}px`;
14744
+ element.style.top = `${Math.round(top)}px`;
14874
14745
  };
14875
- const onStart = (event) => {
14876
- landed = null;
14877
- if (event.touches.length === 2) {
14878
- if (scalingOpen(deps.chart.options().handleScale)) release();
14879
- return;
14746
+ const onOutside = (event) => {
14747
+ const target = event.target;
14748
+ if (!target || element.contains(target) || anchor.contains(target)) return;
14749
+ close();
14750
+ };
14751
+ const onDocumentKey = (event) => {
14752
+ if (event.key === "Escape" && ownsEscape(escape.token)) {
14753
+ event.stopPropagation();
14754
+ event.preventDefault();
14755
+ close();
14880
14756
  }
14881
- const touch = event.touches[0];
14882
- if (event.touches.length !== 1 || !touch || !onPlot(touch.clientX, touch.clientY)) return;
14883
- landed = { x: touch.clientX, y: touch.clientY, at: performance.now() };
14884
14757
  };
14885
- const onMove = (event) => {
14886
- if (landed === null) return;
14887
- const touch = event.touches[0];
14888
- if (event.touches.length !== 1 || !touch) {
14889
- landed = null;
14758
+ element.addEventListener("keydown", (event) => {
14759
+ if (event.key === "Tab") {
14760
+ close();
14890
14761
  return;
14891
14762
  }
14892
- if (Math.abs(touch.clientX - landed.x) + Math.abs(touch.clientY - landed.y) < RENDERER_DRAG_START_PX) return;
14893
- const started = landed;
14894
- landed = null;
14895
- if (performance.now() - started.at >= RENDERER_LONG_TAP_MS) return;
14896
- if (scrollOpen(deps.chart.options().handleScroll)) release();
14897
- };
14898
- const onEnd = () => {
14899
- landed = null;
14900
- };
14901
- deps.target.addEventListener("touchstart", onStart, { passive: true });
14902
- deps.target.addEventListener("touchmove", onMove, { passive: true });
14903
- deps.target.addEventListener("touchend", onEnd, { passive: true });
14904
- deps.target.addEventListener("touchcancel", onEnd, { passive: true });
14905
- return {
14906
- destroy() {
14907
- landed = null;
14908
- deps.target.removeEventListener("touchstart", onStart);
14909
- deps.target.removeEventListener("touchmove", onMove);
14910
- deps.target.removeEventListener("touchend", onEnd);
14911
- deps.target.removeEventListener("touchcancel", onEnd);
14763
+ const target = event.target;
14764
+ const typing = target instanceof HTMLInputElement && target.type !== "checkbox" && target.type !== "radio";
14765
+ if (typing && (event.key === "ArrowLeft" || event.key === "ArrowRight" || event.key === "Home" || event.key === "End")) return;
14766
+ if (roveFocus(element, event, "both")) {
14767
+ event.preventDefault();
14768
+ event.stopPropagation();
14912
14769
  }
14770
+ });
14771
+ const handle = {
14772
+ element,
14773
+ close,
14774
+ open: () => isOpen,
14775
+ refresh() {
14776
+ if (!isOpen) return;
14777
+ const current = items(element).indexOf(document.activeElement);
14778
+ body.replaceChildren();
14779
+ options.build(body, handle);
14780
+ if (footer && options.footer) {
14781
+ footer.replaceChildren();
14782
+ options.footer(footer, handle);
14783
+ }
14784
+ const list2 = items(element);
14785
+ if (list2.length === 0) return;
14786
+ if (current >= 0 && document.activeElement && !element.contains(document.activeElement)) return;
14787
+ armRoving(element, Math.max(0, Math.min(current, list2.length - 1)));
14788
+ if (current >= 0) list2[Math.min(current, list2.length - 1)]?.focus();
14789
+ reposition();
14790
+ },
14791
+ reposition
14913
14792
  };
14793
+ byAnchor.set(anchor, handle);
14794
+ previous?.close();
14795
+ if (!isOpen || byAnchor.get(anchor) !== handle) return handle;
14796
+ options.build(body, handle);
14797
+ if (footer && options.footer) options.footer(footer, handle);
14798
+ if (!isOpen || byAnchor.get(anchor) !== handle) return handle;
14799
+ host2.appendChild(element);
14800
+ untrack = trackOverlay(host2, close, () => handle.refresh());
14801
+ anchor.setAttribute("aria-expanded", "true");
14802
+ reposition();
14803
+ const list = items(element);
14804
+ const first = Math.max(0, Math.min(options.initialIndex ?? 0, list.length - 1));
14805
+ if (list.length > 0) {
14806
+ armRoving(element, first);
14807
+ focusItem(list, first);
14808
+ list[first]?.scrollIntoView?.({ block: "nearest" });
14809
+ } else {
14810
+ const focusable = element.querySelector('input, button, select, textarea, [tabindex="0"]');
14811
+ focusable?.focus();
14812
+ }
14813
+ document.addEventListener("pointerdown", onOutside, true);
14814
+ document.addEventListener("keydown", onDocumentKey, true);
14815
+ window.addEventListener("resize", reposition);
14816
+ return handle;
14817
+ }
14818
+ function menuItem(options) {
14819
+ const role = options.role ?? "menuitem";
14820
+ const row2 = h("button", {
14821
+ type: "button",
14822
+ class: `qc-menu-row${options.className ? ` ${options.className}` : ""}`,
14823
+ role,
14824
+ "data-qc-item": "",
14825
+ tabindex: "-1",
14826
+ ...options.label ? { "aria-label": options.label } : options.keys ? { "aria-label": options.text } : {},
14827
+ ...options.keys ? { "aria-keyshortcuts": options.keys } : {},
14828
+ ...role === "menuitemradio" || role === "menuitemcheckbox" ? { "aria-checked": String(options.checked === true) } : {},
14829
+ ...role === "option" ? { "aria-selected": String(options.checked === true) } : {}
14830
+ });
14831
+ if (options.disabled) {
14832
+ row2.disabled = true;
14833
+ row2.setAttribute("aria-disabled", "true");
14834
+ }
14835
+ const cell2 = h("span", { class: "qc-menu-icon" });
14836
+ if (options.icon) {
14837
+ row2.classList.add("qc-menu-row--marked");
14838
+ cell2.appendChild(options.icon);
14839
+ }
14840
+ row2.appendChild(cell2);
14841
+ const label2 = h("span", { class: "qc-menu-label" }, options.text);
14842
+ row2.appendChild(options.description === void 0 ? label2 : h("span", { class: "qc-menu-text" }, label2, h("span", { class: "qc-menu-description" }, options.description)));
14843
+ if (options.hint !== void 0) row2.appendChild(h("span", { class: "qc-menu-hint", ...options.keys ? { "aria-hidden": "true" } : {} }, options.hint));
14844
+ if (options.onSelect) row2.addEventListener("click", () => options.onSelect?.());
14845
+ return row2;
14846
+ }
14847
+ function menuHeading(text2) {
14848
+ return h("div", { class: "qc-menu-heading", role: "presentation" }, text2);
14849
+ }
14850
+ function menuSeparator() {
14851
+ return h("div", { class: "qc-separator", role: "separator" });
14914
14852
  }
14915
14853
 
14916
- // src/widget/plotArea.ts
14917
- function measurePlotArea(chart, host2) {
14918
- const row2 = chart.panes()[0]?.getHTMLElement();
14919
- if (!row2) return null;
14920
- const size = chart.paneSize(0);
14921
- if (!(size.width > 0) || !(size.height > 0)) return null;
14922
- const outer = host2.getBoundingClientRect();
14923
- const top = row2.getBoundingClientRect().top;
14924
- const left = chart.chartElement().getBoundingClientRect().left + chart.priceScale("left").width();
14925
- const round = (n) => Math.round(n * 100) / 100;
14926
- return {
14927
- top: round(top - outer.top),
14928
- right: round(outer.right - (left + size.width)),
14929
- bottom: round(outer.bottom - (top + size.height)),
14930
- left: round(left - outer.left),
14931
- width: round(size.width),
14932
- height: round(size.height)
14854
+ // src/ui/chrome/marketStatus.ts
14855
+ var clock = (mins) => `${String(Math.floor(mins / 60) % 24).padStart(2, "0")}:${String(mins % 60).padStart(2, "0")}`;
14856
+ function timelineLabels(starts) {
14857
+ const sorted = [...new Set(starts.filter((m) => m > 0))].sort((a, b) => a - b);
14858
+ const out = [];
14859
+ for (let i = 0; i < sorted.length; i++) {
14860
+ const a = sorted[i];
14861
+ const b = sorted[i + 1];
14862
+ if (b !== void 0 && b - a <= 90) {
14863
+ out.push({ mins: (a + b) / 2, text: `${clock(a)} ${clock(b)}` });
14864
+ i++;
14865
+ } else out.push({ mins: a, text: clock(a) });
14866
+ }
14867
+ return out;
14868
+ }
14869
+ function openMarketStatus(anchor, deps) {
14870
+ const t = deps.i18n.t;
14871
+ const now = () => Math.floor(Date.now() / 1e3);
14872
+ let timer = null;
14873
+ let offLocale = () => void 0;
14874
+ const stopUpdates = () => {
14875
+ if (timer) clearInterval(timer);
14876
+ timer = null;
14877
+ offLocale();
14878
+ offLocale = () => void 0;
14879
+ };
14880
+ const titleRow = (state, text2) => {
14881
+ const dot = h("span", { class: "qc-session-dot qc-status-dot", ...state ? { "data-qc-session": state } : {} });
14882
+ return h("div", { class: "qc-status-title" }, dot, h("span", { class: "qc-title" }, text2));
14933
14883
  };
14884
+ const menu2 = openMenu({
14885
+ host: deps.host,
14886
+ anchor,
14887
+ label: t("status.title"),
14888
+ role: "dialog",
14889
+ className: "qc-status-popup",
14890
+ width: 300,
14891
+ build(body) {
14892
+ const model = deps.model();
14893
+ const nowSecs = now();
14894
+ const status2 = model ? deps.status(nowSecs) : null;
14895
+ if (!model || !status2) {
14896
+ body.append(titleRow(null, t("status.unknownTitle")), h("p", { class: "qc-status-text qc-secondary" }, t("status.unknown")));
14897
+ return;
14898
+ }
14899
+ body.append(titleRow(sessionStateAt(model, nowSecs), marketStatusTitle(t, status2)), h("p", { class: "qc-status-text qc-secondary" }, marketStatusText(t, status2, nowSecs)));
14900
+ const tl = sessionTimeline(model, nowSecs, deps.i18n.tag());
14901
+ const bar = h("div", { class: "qc-status-bar", "aria-hidden": "true" });
14902
+ for (const s of tl.segments) {
14903
+ const segment = h("div", { class: "qc-status-segment", "data-qc-session": s.state });
14904
+ segment.style.width = `${(s.end - s.start) / 1440 * 100}%`;
14905
+ bar.appendChild(segment);
14906
+ }
14907
+ const marker = h("div", { class: "qc-status-now" });
14908
+ marker.style.insetInlineStart = `${tl.nowMins / 1440 * 100}%`;
14909
+ const track = h("div", { class: "qc-status-track" }, bar, marker);
14910
+ body.appendChild(h("div", { class: "qc-status-timeline" }, h("span", { class: "qc-status-day qc-muted" }, tl.dayLabel), track));
14911
+ const labels = timelineLabels(tl.segments.map((s) => s.start));
14912
+ if (labels.length > 0) {
14913
+ const row2 = h("div", { class: "qc-status-labels", "aria-hidden": "true" });
14914
+ for (const l of labels) {
14915
+ const label2 = h("span", { class: "qc-status-label qc-muted" }, l.text);
14916
+ label2.style.insetInlineStart = `${l.mins / 1440 * 100}%`;
14917
+ row2.appendChild(label2);
14918
+ }
14919
+ body.appendChild(row2);
14920
+ }
14921
+ body.appendChild(h("div", { class: "qc-status-footer qc-muted" }, exchangeTimezoneText(t, tl.timezone, new Date(nowSecs * 1e3))));
14922
+ },
14923
+ onClose() {
14924
+ stopUpdates();
14925
+ deps.onClose?.();
14926
+ }
14927
+ });
14928
+ timer = setInterval(() => menu2.refresh(), 6e4);
14929
+ offLocale = deps.i18n.onChange(() => menu2.refresh());
14930
+ if (!menu2.open()) stopUpdates();
14931
+ return menu2;
14932
+ }
14933
+
14934
+ // src/widget/legend.ts
14935
+ var COMPARE_ROW_PREFIX = "cmp:";
14936
+ var HOST_ROW_PREFIX = "host:";
14937
+ function barIndexAt(bars, time) {
14938
+ if (bars.length === 0) return -1;
14939
+ if (time === null) return bars.length - 1;
14940
+ let lo = 0;
14941
+ let hi = bars.length - 1;
14942
+ while (lo < hi) {
14943
+ const mid = lo + hi + 1 >> 1;
14944
+ if (bars[mid].t <= time) lo = mid;
14945
+ else hi = mid - 1;
14946
+ }
14947
+ return lo;
14934
14948
  }
14935
- var sameArea = (a, b) => b !== null && a.top === b.top && a.right === b.right && a.bottom === b.bottom && a.left === b.left && a.width === b.width && a.height === b.height;
14936
- function watchPlotArea(deps) {
14937
- let area = null;
14938
- let frame = null;
14949
+ var percentWriters = /* @__PURE__ */ new Map();
14950
+ function percentText(fraction, tag) {
14951
+ let writer = percentWriters.get(tag);
14952
+ if (!writer) {
14953
+ writer = new Intl.NumberFormat(tag);
14954
+ percentWriters.set(tag, writer);
14955
+ }
14956
+ const points = Math.round(fraction * 1e4) / 100;
14957
+ return `${points > 0 ? "+" : ""}${writer.format(points)}`;
14958
+ }
14959
+ function attachLegendPlane(deps) {
14960
+ if (!deps.enabled) {
14961
+ return {
14962
+ push: () => void 0,
14963
+ setHeader: () => void 0,
14964
+ setDot: () => void 0,
14965
+ setHostRows: () => void 0,
14966
+ destroy: () => void 0
14967
+ };
14968
+ }
14939
14969
  let destroyed = false;
14940
- let row2 = null;
14941
- const resize = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(() => schedule());
14942
- const measure2 = () => {
14943
- frame = null;
14944
- if (destroyed) return;
14945
- const nextRow = deps.chart.panes()[0]?.getHTMLElement() ?? null;
14946
- if (nextRow !== row2) {
14947
- if (row2) resize?.unobserve(row2);
14948
- if (nextRow) resize?.observe(nextRow);
14949
- row2 = nextRow;
14970
+ const hostRows = /* @__PURE__ */ new Map();
14971
+ const paneRemembered = /* @__PURE__ */ new Map();
14972
+ const paneKeys = () => {
14973
+ const keys = { 0: "main" };
14974
+ for (const [id, pane] of Object.entries(deps.indicators.renderer.paneOf())) if (pane > 0) keys[pane] = `indicator:${id}`;
14975
+ for (const entry of deps.compare?.api.list() ?? []) {
14976
+ const pane = deps.compare.handle.paneIndexOf(entry.symbol);
14977
+ if (pane !== null && pane > 0) keys[pane] = `compare:${entry.symbol}`;
14950
14978
  }
14951
- const next = measurePlotArea(deps.chart, deps.host);
14952
- if (next === null || sameArea(next, area)) return;
14953
- area = next;
14954
- deps.changed(next);
14979
+ return keys;
14955
14980
  };
14956
- function schedule() {
14957
- if (destroyed || frame !== null) return;
14958
- if (typeof requestAnimationFrame !== "function") {
14959
- measure2();
14960
- return;
14981
+ let legend2 = null;
14982
+ let status2 = null;
14983
+ let hovered = null;
14984
+ let named = null;
14985
+ let namedTimeframe = null;
14986
+ legend2 = mountChartLegend(deps.chrome, deps.i18n, {
14987
+ // Every row control is a COMMAND. The legend states an intent by id and the registry decides
14988
+ // whether it may run, so a verb the host forbade cannot be reached by clicking either.
14989
+ onToggleEye: (id) => {
14990
+ if (id.startsWith(COMPARE_ROW_PREFIX)) {
14991
+ const symbol = id.slice(COMPARE_ROW_PREFIX.length);
14992
+ const entry = deps.compare?.api.list().find((e) => e.symbol === symbol);
14993
+ if (entry) deps.commands.execute("chart.compare.setVisible", { symbol, visible: !entry.visible });
14994
+ return;
14995
+ }
14996
+ deps.commands.execute(deps.indicators.isHidden(id) ? "chart.indicators.show" : "chart.indicators.hide", id);
14997
+ },
14998
+ onTitle: (id) => {
14999
+ if (id.startsWith(COMPARE_ROW_PREFIX)) deps.commands.execute("chart.compare.changeSymbol", id.slice(COMPARE_ROW_PREFIX.length));
15000
+ },
15001
+ onRemove: (id) => {
15002
+ if (id.startsWith(COMPARE_ROW_PREFIX)) deps.commands.execute("chart.compare.remove", id.slice(COMPARE_ROW_PREFIX.length));
15003
+ else deps.commands.execute("chart.indicators.remove", id);
15004
+ },
15005
+ ...deps.symbolSearch ? { onSymbol: () => deps.openSearch() } : {},
15006
+ painters: deps.painters,
15007
+ icons: deps.icons,
15008
+ ...deps.marketStatus ? {
15009
+ onStatus: (anchor) => {
15010
+ if (status2) {
15011
+ status2.close();
15012
+ return;
15013
+ }
15014
+ status2 = openMarketStatus(anchor, {
15015
+ host: deps.chrome,
15016
+ i18n: deps.i18n,
15017
+ model: deps.sessionModel,
15018
+ status: deps.status,
15019
+ onClose: () => {
15020
+ status2 = null;
15021
+ }
15022
+ });
15023
+ }
15024
+ } : {},
15025
+ onSettings: (id, rect) => {
15026
+ const host2 = hostRows.get(id);
15027
+ if (host2) {
15028
+ host2.onSettings?.();
15029
+ return;
15030
+ }
15031
+ if (deps.openIndicatorSettings(id)) return;
15032
+ const inst = deps.indicators.list().find((i) => i.id === id);
15033
+ if (!inst) return;
15034
+ mountInputsEditor(
15035
+ deps.chrome,
15036
+ rect,
15037
+ inst.definition.manifest.inputs ?? {},
15038
+ { ...manifestInputDefaults(inst.definition.manifest), ...inst.inputs },
15039
+ (patch) => deps.indicators.patchInputs(id, patch),
15040
+ deps.i18n,
15041
+ deps.icons
15042
+ );
15043
+ },
15044
+ onPaneOp: (id, op) => {
15045
+ const paneIdx = deps.indicators.renderer.paneOf()[id];
15046
+ if (paneIdx === void 0 || paneIdx === 0) return;
15047
+ const panes = deps.chart.panes();
15048
+ const heights = {};
15049
+ panes.forEach((p, i) => heights[i] = p.getHeight());
15050
+ const keys = paneKeys();
15051
+ const remembered = {};
15052
+ for (const [index, key] of Object.entries(keys)) {
15053
+ const height = paneRemembered.get(key);
15054
+ if (height !== void 0) remembered[Number(index)] = height;
15055
+ }
15056
+ const plan = planPaneOp({ heights, remembered }, { kind: op, pane: paneIdx });
15057
+ paneRemembered.clear();
15058
+ for (const [index, height] of Object.entries(plan.remembered)) {
15059
+ const key = keys[Number(index)];
15060
+ if (key) paneRemembered.set(key, height);
15061
+ }
15062
+ for (const [i, h2] of Object.entries(plan.apply)) {
15063
+ const index = Number(i);
15064
+ panes[index]?.setHeight(h2);
15065
+ if (index > 0) deps.indicators.setPaneCollapsed(index, h2 <= COLLAPSED_H);
15066
+ }
15067
+ deps.indicators.recompute();
14961
15068
  }
14962
- frame = requestAnimationFrame(measure2);
15069
+ });
15070
+ function reading() {
15071
+ const bars = deps.bars();
15072
+ const index = barIndexAt(bars, hovered);
15073
+ const bar = index < 0 ? void 0 : bars[index];
15074
+ if (!bar) return null;
15075
+ const previous = index > 0 ? bars[index - 1] : void 0;
15076
+ const format2 = deps.formatter();
15077
+ const change = previous ? bar.c - previous.c : null;
15078
+ const fraction = change !== null && previous && previous.c !== 0 ? change / previous.c : null;
15079
+ return {
15080
+ open: format2.format(bar.o),
15081
+ high: format2.format(bar.h),
15082
+ low: format2.format(bar.l),
15083
+ close: format2.format(bar.c),
15084
+ change: change === null ? null : `${change > 0 ? "+" : ""}${format2.format(change)}`,
15085
+ percent: fraction === null ? null : percentText(fraction, deps.i18n.tag()),
15086
+ direction: change === null || change === 0 ? "flat" : change > 0 ? "up" : "down"
15087
+ };
14963
15088
  }
14964
- deps.chart.timeScale().subscribeSizeChange(schedule);
14965
- resize?.observe(deps.host);
14966
- resize?.observe(deps.chart.chartElement());
14967
- schedule();
14968
- return {
14969
- current() {
14970
- if (destroyed) return null;
14971
- return area ?? measurePlotArea(deps.chart, deps.host);
15089
+ const paint = () => {
15090
+ if (destroyed) return;
15091
+ const alive = new Set(Object.values(paneKeys()));
15092
+ for (const key of paneRemembered.keys()) if (!alive.has(key)) paneRemembered.delete(key);
15093
+ legend2?.setValueShaped(deps.valueShaped());
15094
+ legend2?.setQuote(deps.legendValues ? reading() : null);
15095
+ const paneOf = deps.indicators.renderer.paneOf();
15096
+ const shown2 = (command2) => deps.shown?.(command2) ?? true;
15097
+ legend2?.setChips([
15098
+ ...deps.indicators.chipsAt(hovered).map((row2) => {
15099
+ const paneIndex = paneOf[row2.id] ?? 0;
15100
+ const remembered = paneRemembered.get(`indicator:${row2.id}`);
15101
+ return {
15102
+ ...row2,
15103
+ paneIndex,
15104
+ maximized: remembered !== void 0 && !row2.collapsed && (deps.chart.panes()[paneIndex]?.getHeight() ?? 0) > remembered,
15105
+ ...shown2(row2.hidden ? "chart.indicators.show" : "chart.indicators.hide") ? {} : { hideable: false },
15106
+ ...shown2("chart.indicators.remove") ? {} : { removable: false }
15107
+ };
15108
+ }),
15109
+ ...(deps.compare?.chips(hovered) ?? []).map((row2) => ({
15110
+ ...row2,
15111
+ paneIndex: deps.compare.handle.paneIndexOf(row2.id.slice(COMPARE_ROW_PREFIX.length)) ?? 0,
15112
+ ...shown2("chart.compare.setVisible") ? {} : { hideable: false },
15113
+ ...shown2("chart.compare.remove") ? {} : { removable: false }
15114
+ })),
15115
+ ...[...hostRows].map(([id, row2]) => ({
15116
+ id,
15117
+ title: row2.title,
15118
+ inputs: row2.inputs,
15119
+ value: null,
15120
+ note: row2.status,
15121
+ description: row2.description,
15122
+ settingsLabel: row2.settingsLabel,
15123
+ hidden: false,
15124
+ hideable: false,
15125
+ removable: false,
15126
+ hasInputs: !!row2.onSettings,
15127
+ paneIndex: 0
15128
+ }))
15129
+ ]);
15130
+ const tops = {};
15131
+ let top = 0;
15132
+ const panes = deps.chart.panes();
15133
+ const first = panes[0]?.getHTMLElement()?.getBoundingClientRect();
15134
+ for (const [index, pane] of panes.entries()) {
15135
+ const element = pane.getHTMLElement();
15136
+ const rect = element?.getBoundingClientRect();
15137
+ tops[index] = rect && first && rect.height > 0 ? rect.top - first.top : top;
15138
+ top += pane.getHeight();
15139
+ if (element && !observed.has(element)) {
15140
+ observed.add(element);
15141
+ resize?.observe(element);
15142
+ }
15143
+ }
15144
+ const current = new Set(panes.map((pane) => pane.getHTMLElement()));
15145
+ for (const element of observed) if (!current.has(element)) {
15146
+ resize?.unobserve(element);
15147
+ observed.delete(element);
15148
+ }
15149
+ legend2?.setPaneTops(tops);
15150
+ try {
15151
+ const start = deps.chart.priceScale("left").width();
15152
+ const end = deps.chart.priceScale("right").width();
15153
+ legend2?.setScaleInsets(start, end, deps.chart.timeScale().height());
15154
+ deps.chrome.style.setProperty("--qcp-plot-start", `${start}px`);
15155
+ deps.chrome.style.setProperty("--qcp-plot-end", `${end}px`);
15156
+ } catch {
15157
+ }
15158
+ };
15159
+ const observed = /* @__PURE__ */ new Set();
15160
+ const resize = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(() => paint());
15161
+ const onCrosshair = (param) => {
15162
+ if (deps.replayPhase() === "arming")
15163
+ legend2?.setReplayGuide(param.point ? { x: param.point.x, y: param.point.y } : null, deps.chart.timeScale().height());
15164
+ const next = typeof param.time === "number" && Number.isFinite(param.time) ? param.time : null;
15165
+ if (next === hovered) return;
15166
+ hovered = next;
15167
+ paint();
15168
+ };
15169
+ deps.chart.subscribeCrosshairMove(onCrosshair);
15170
+ return {
15171
+ setHostRows(rows2) {
15172
+ if (destroyed) return;
15173
+ hostRows.clear();
15174
+ for (const row2 of rows2) hostRows.set(`${HOST_ROW_PREFIX}${row2.id}`, { ...row2 });
15175
+ paint();
15176
+ },
15177
+ push() {
15178
+ paint();
15179
+ },
15180
+ setHeader(symbol, tf) {
15181
+ if (symbol !== named || deps.replayPhase() !== "off") {
15182
+ status2?.close();
15183
+ status2 = null;
15184
+ }
15185
+ legend2?.setReplay(deps.replayPhase());
15186
+ if (symbol !== named || tf !== namedTimeframe) {
15187
+ named = symbol;
15188
+ namedTimeframe = tf;
15189
+ hovered = null;
15190
+ }
15191
+ const info = deps.symbolInfo();
15192
+ const label2 = symbolNames(info ?? symbol).title;
15193
+ legend2?.setIdentity({ name: label2, symbol, timeframe: tf, exchange: info?.exchange ?? "" });
15194
+ },
15195
+ setDot(state) {
15196
+ const current = deps.status(Math.floor(Date.now() / 1e3));
15197
+ legend2?.setDot(state, current ? marketStatusTitle(deps.i18n.t, current) : deps.i18n.t("status.unknownTitle"));
15198
+ status2?.refresh();
14972
15199
  },
14973
15200
  destroy() {
14974
- if (destroyed) return;
14975
15201
  destroyed = true;
14976
- if (frame !== null && typeof cancelAnimationFrame === "function") cancelAnimationFrame(frame);
14977
- frame = null;
15202
+ hostRows.clear();
14978
15203
  resize?.disconnect();
14979
- try {
14980
- deps.chart.timeScale().unsubscribeSizeChange(schedule);
14981
- } catch {
14982
- }
14983
- }
14984
- };
14985
- }
14986
-
14987
- // src/contextMenu.ts
14988
- function chartContextMenuGroups(c) {
14989
- const t = c.t ?? englishChartStrings();
14990
- const clipboard2 = [{ kind: "item", id: "copy-price", label: t("menu.copyPrice", { price: c.priceText }) }];
14991
- if (c.canPaste !== false) clipboard2.push({ kind: "item", id: "paste", label: t("menu.paste"), shortcut: t("drawing.hintPaste", { modifier: t(isApplePlatform() ? "drawing.modifierCommand" : "drawing.modifierControl") }) });
14992
- const remove = [];
14993
- if (c.indicatorCount > 0) remove.push({ kind: "item", id: "remove-indicators", label: t("menu.removeIndicators", { count: c.indicatorCount }) });
14994
- if (c.drawingCount > 0) remove.push({ kind: "item", id: "remove-drawings", label: t("menu.removeDrawings", { count: c.drawingCount }) });
14995
- return [
14996
- { slot: "view", rows: [{ kind: "item", id: "reset-view", label: t("menu.resetView"), shortcut: "Alt + R", icon: "reset" }] },
14997
- { slot: "clipboard", rows: clipboard2 },
14998
- { slot: "remove", rows: remove },
14999
- { slot: "settings", rows: c.canSettings !== false ? [{ kind: "item", id: "settings", label: t("menu.settings"), icon: "settings" }] : [] }
15000
- ];
15001
- }
15002
- function flattenMenuGroups(groups) {
15003
- const rows2 = [];
15004
- for (const g of groups.filter((g2) => g2.length > 0)) {
15005
- if (rows2.length) rows2.push({ kind: "separator" });
15006
- rows2.push(...g);
15007
- }
15008
- return rows2;
15009
- }
15010
- function chartContextMenu(c) {
15011
- return flattenMenuGroups(chartContextMenuGroups(c).map((g) => g.rows));
15012
- }
15013
-
15014
- // src/ui/icons/draw.ts
15015
- var SVG_NS2 = "http://www.w3.org/2000/svg";
15016
- var answered = /* @__PURE__ */ new WeakSet();
15017
- var isSvg = (node) => typeof node === "object" && node !== null && node.nodeType === 1 && node.namespaceURI === SVG_NS2 && node.localName === "svg";
15018
- var FAILURE_TEXT = {
15019
- threw: "the factory threw",
15020
- "not-svg": "the factory answered something other than an <svg> element",
15021
- "in-use": "the factory answered an element already in a document or answered before"
15022
- };
15023
- function drawHostIcon(factory, context) {
15024
- let node;
15025
- try {
15026
- node = factory(context);
15027
- } catch {
15028
- return { failure: "threw" };
15029
- }
15030
- if (!isSvg(node)) return { failure: "not-svg" };
15031
- if (node.parentNode !== null || answered.has(node)) return { failure: "in-use" };
15032
- answered.add(node);
15033
- node.setAttribute("width", String(context.width));
15034
- node.setAttribute("height", String(context.height));
15035
- node.setAttribute("aria-hidden", "true");
15036
- node.setAttribute("focusable", "false");
15037
- return { element: node };
15038
- }
15039
- function createIconDiagnostics() {
15040
- const seen = /* @__PURE__ */ new Map();
15041
- return {
15042
- report(icon, failure) {
15043
- if (!seen.has(icon)) seen.set(icon, { icon, code: failure, message: `${icon}: ${FAILURE_TEXT[failure]}` });
15044
- },
15045
- list: () => [...seen.values()]
15046
- };
15047
- }
15048
-
15049
- // src/ui/drawings/toolIcons.ts
15050
- var TOOL_ICONS = {
15051
- trend_line: '<path d="M7.3 20.7 20.7 7.3" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15052
- ray: '<path d="M8.3 19.7 12.7 15.3 M16.3 11.7 24.4 3.6" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="21.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="13.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15053
- info_line: '<path d="M7.3 20.7 20.7 7.3" stroke="currentColor" stroke-width="1.2"/><rect x="16.5" y="17.5" width="9" height="7" rx="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15054
- extended: '<path d="M4.4 25.4 9.3 20.5 M12.4 17.4 17.4 12.4 M20.4 9.4 25.4 4.4" stroke="currentColor" stroke-width="1.2"/><circle cx="10.5" cy="18.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="18.5" cy="10.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15055
- trend_angle: '<path d="M7.3 20.7 20.7 7.3 M7.5 22.5H24 M15.5 22.5A8 8 0 0 0 13.2 16.8" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15056
- horizontal_line: '<path d="M4 14.5h8.4 M16.6 14.5H25" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="14.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15057
- horizontal_ray: '<path d="M8.9 14.5H25" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="14.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15058
- vertical_line: '<path d="M14.5 4v8.4 M14.5 16.6V25" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="14.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15059
- cross_line: '<path d="M4 14.5h8.4 M16.6 14.5H25 M14.5 4v8.4 M14.5 16.6V25" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="14.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15060
- parallel_channel: '<path d="M8.3 18.3 18.3 8.3 M12.4 25.3 17.3 20.4 M20.4 17.3 25.3 12.4" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="19.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="19.5" cy="6.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="18.85" cy="18.85" r="2" stroke="currentColor" stroke-width="1.2"/>',
15061
- regression_trend: '<path d="M5.5 12 22.5 3 M5.5 25 22.5 16 M7.6 18 20.7 11.1" stroke="currentColor" stroke-width="1.2"/><path d="M5.5 12v4.4 M5.5 20.6V25 M22.5 3v4.4 M22.5 11.6V16" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="18.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="9.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15062
- flat_top_bottom: '<path d="M7.7 12.6 20.3 7.4 M7.5 22.5h13" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="13.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="6.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15063
- disjoint_channel: '<path d="M7.3 9.3 20.6 4.6 M7.5 17.7 20.7 22.4" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="10.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="4.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="16.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15064
- pitchfork: '<path d="M7.3 21.4 19.9 8.9 M6.7 13.4 14.6 21.3 M7.1 10.6 14.2 3.5 M18.1 21.6 25.2 14.5" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="11.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="16.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15065
- schiff_pitchfork: '<path d="M6.5 22.5H16.5 M10.3 20.4 21.9 8.9 M8.3 13 17 21.7 M9.1 10.6 16.2 3.5 M20.1 21.6 27.2 14.5" stroke="currentColor" stroke-width="1.2"/><circle cx="4.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="7.5" cy="11.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="18.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15066
- schiff_pitchfork_modified: '<path d="M7.9 22.9 21.9 8.9 M5.5 22.5H16.5 M8.3 13 17 21.7 M9.1 10.6 16.2 3.5 M20.1 21.6 27.2 14.5" stroke="currentColor" stroke-width="1.2"/><circle cx="7.5" cy="11.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="18.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15067
- inside_pitchfork: '<path d="M6.5 22.5H18.5 M8.4 22.7 10.4 16.6 M11.6 12.7 14.7 3.1 M16 18.7 19.7 7.1 M21.6 20.7 24.7 11.1 M11.8 16.2 18.6 21.6" stroke="currentColor" stroke-width="1.2"/><circle cx="4.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="10.5" cy="14.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="20.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15068
- fib_retracement: '<path d="M3 4.5h22 M3 10.5h19.4 M3 16.5h22 M6 22.5h19" stroke="currentColor" stroke-width="1.2"/><circle cx="3.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="24.5" cy="10.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15069
- fib_trend_ext: '<path d="M6.6 16.5H26 M4 20.5h22 M4 24.5h22 M4.5 11.6v2.9 M6.6 9.3 16.6 5.7" stroke="currentColor" stroke-width="1.2"/><circle cx="4.5" cy="9.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="4.5" cy="16.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="18.5" cy="4.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15070
- fib_channel: '<path d="M7.5 12 21 4.9 M7.3 18.5 23.2 10.1 M5.3 26 23.2 16.7" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="19.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="3.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15071
- fib_timezone: '<path d="M5.5 4v4.4 M5.5 12.6V25 M14.5 4v13.4 M14.5 21.6V25 M19.5 4v21 M24.5 4v21" stroke="currentColor" stroke-width="1.2"/><path d="M7.2 12.2l1 1 M9 14.5l1.5 1.5 M11.4 16.9l1.2 1.2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="10.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="19.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15072
- fib_speed_resist_fan: '<path d="M4.5 2v19.4 M4.5 10.5H15 M17.5 12.6v10.9 M6.5 23.5H26" stroke="currentColor" stroke-width="1.2"/><path d="M6.3 22.4 16.4 12.3 M19.3 9.4 25.9 2.9 M6.6 23.4 25.7 17.5 M5.6 21.7 11.5 2.7" stroke="currentColor" stroke-width="1.2"/><circle cx="4.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="17.5" cy="10.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15073
- fib_trend_time: '<path d="M16.5 2v19.4 M20.5 2v22 M24.5 2v22 M4.7 11.5 8.4 21.8 M11.5 23.5h3" stroke="currentColor" stroke-width="1.2"/><circle cx="4.5" cy="9.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="9.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="16.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15074
- fib_circles: '<circle cx="14.5" cy="14.5" r="5" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="14.5" r="8" stroke="currentColor" stroke-width="1.2"/><path d="M24.1 8.5A11.3 11.3 0 0 1 8.5 24.1 M4.9 20.5A11.3 11.3 0 0 1 20.5 4.9" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="6.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15075
- fib_spiral: '<path d="M15.6 13.2a1.7 1.7 0 1 0-3.4 0 3 3 0 0 0 6 0 5.2 5.2 0 1 0-10.4 0 7.6 7.6 0 0 0 14.9 2.4" stroke="currentColor" stroke-width="1.2"/><path d="M15 15.7 18.7 12 M21 9.7 24.2 6.5" stroke="currentColor" stroke-width="1.2"/><circle cx="13.5" cy="16.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="19.5" cy="10.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15076
- fib_speed_resist_arcs: '<path d="M8.5 9.5A5 5 0 0 0 18.5 9.5 M0.5 9.5A13 13 0 0 0 26.5 9.5 M4.5 9.5A9 9 0 0 0 11 18.2 M16 18.2A9 9 0 0 0 22.5 9.5" stroke="currentColor" stroke-width="1.2"/><circle cx="13.5" cy="9.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="13.5" cy="18.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15077
- fib_wedge: '<path d="M5.5 8v13 M8 23.5H21" stroke="currentColor" stroke-width="1.2"/><path d="M5.5 17.5A6 6 0 0 1 11.5 23.5 M5.5 13.5A10 10 0 0 1 15.5 23.5 M5.5 9.5A14 14 0 0 1 19.5 23.5" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="23.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15078
- pitchfan: '<path d="M7.4 21.4 24.4 4.4 M7.3 22.7 16.9 21.2 M20.3 20.7 24.8 19.9 M7.3 22.1 23 13.8 M6.7 21.2 15.1 5.5 M6.3 20.8 7.8 11.4 M8.3 7.8 9 3.3 M9.3 10.6 17.5 18.8" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="7.5" cy="9.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="18.5" cy="20.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15079
- gannbox: '<path d="M22.5 3.5H3.5V22 M5.5 24.5H24.5V5.5" stroke="currentColor" stroke-width="1.2"/><path d="M3.5 10.5h21 M3.5 17.5h21 M10.5 3.5v21 M17.5 3.5v21" stroke="currentColor" stroke-width="1.2"/><circle cx="3.5" cy="24.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="24.5" cy="3.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15080
- gannbox_fixed: '<path d="M5.5 23.5H24.5V2.5H3.5V21.5 M4 9.5h20 M3.5 18.5h5 M12.5 18.5h12 M17.5 3v20 M10.5 2.5v12 M10.5 18.5v5" stroke="currentColor" stroke-width="1.2"/><path d="M4.9 22.1 9.1 17.9 M12 15 24 3 M5.4 23 24.5 17 M4.1 21.6 10 2.5 M24.5 23.5A21 21 0 0 0 3.5 2.5" stroke="currentColor" stroke-width="1.2"/>',
15081
- gannbox_square: '<path d="M22.5 3.5H3.5V22 M5.5 24.5H24.5V5.5" stroke="currentColor" stroke-width="1.2"/><path d="M5.3 23.4 23.5 5.2 M5.6 24.4 24.7 18.5 M4.6 22.7 10.5 3.7 M24.5 6.5A21 21 0 0 1 6.5 24.5" stroke="currentColor" stroke-width="1.2"/><circle cx="3.5" cy="24.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="24.5" cy="3.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15082
- gannbox_fan: '<path d="M7.4 21.4 14.5 14.3 M17.3 11.5 24.4 4.4 M7.5 22.1 23.3 14.4 M7.5 22.7 24.8 19.9 M6.8 21 14.5 5.2 M6.3 20.7 9.1 3.3" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="15.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15083
- xabcd_pattern: '<path d="M6.3 20.7 8.6 7.6 M9 7.5 11 11 M11 13.8 6.2 20.6 M14.4 11.7 19.2 8.1 M20.4 8.5 22.6 17.6 M13.9 14 21.6 18.9" stroke="currentColor" stroke-width="1.2"/><circle cx="8.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="12.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="20.5" cy="6.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="23.5" cy="19.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15084
- cypher_pattern: '<path d="M6.3 20.7 8.6 7.6 M9 7.5 11 11 M11 13.8 6.2 20.6 M14.4 11.7 19.2 8.1 M20.4 8.5 22.6 17.6 M13.9 14 21.6 18.9" stroke="currentColor" stroke-width="1.2"/><circle cx="8.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="12.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="20.5" cy="6.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="23.5" cy="19.5" r="2" stroke="currentColor" stroke-width="1.2"/><text x="14.3" y="24.4" text-anchor="middle" font-size="7.5" fill="currentColor">C</text>',
15085
- abcd_pattern: '<path d="M9.5 6.7 21.5 5.2 M6.6 9.4 4.4 20.4 M6.5 22.7 18.6 21.2 M21.4 18.6 23.6 7.6 M8.5 9.2 18.8 19.5" stroke="currentColor" stroke-width="1.2"/><circle cx="7.5" cy="7.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="4.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="23.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="20.5" cy="20.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15086
- triangle_pattern: '<path d="M2.5 1.5V20.8 M2.6 1.9 7.4 4.1 M11.1 5.9 16.4 8.3 M20.1 8.1 26.8 11.1 M4.1 21.2 9.5 18.8 M13.3 17.7 26.8 11.6" stroke="currentColor" stroke-width="1.2"/><path d="M3.7 20.8 9.2 6.6 M9.3 6.4 10.7 16.6 M13.1 17.2 17.8 10.4" stroke="currentColor" stroke-width="1.2"/><circle cx="9.5" cy="4.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="11.5" cy="18.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="18.5" cy="8.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15087
- three_drives: '<path d="M0.3 4.7 1.4 5.2 M5.1 6.8 8.5 8.2 M12.1 9.8 15.5 11.2 M19.2 12.8 25.1 15.3 M0.3 17.7 1.4 18.2 M5.1 19.8 8.5 21.2 M12.1 22.8 15.5 24.2 M19.2 25.8 20.8 26.5" stroke="currentColor" stroke-width="1.2"/><path d="M3.5 7.5V16.4 M4.3 16.5 8.9 9.9 M10.5 10.5V19.5 M11.3 19.5 15.9 12.9 M17.5 13.5V22.5 M17.7 22.5 24.3 5.2" stroke="currentColor" stroke-width="1.2"/><circle cx="3.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="3.5" cy="18.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="10.5" cy="8.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="10.5" cy="21.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="17.5" cy="11.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="17.5" cy="24.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15088
- head_and_shoulders: '<path d="M4.4 21.7 6.5 12.6 M7.8 12 10 16.5 M10.6 16.4 13.5 6.3 M15.5 6.2 18.4 16.5 M18.9 16.5 21.1 12.1 M23.4 12.3 25.5 21.4" stroke="currentColor" stroke-width="1.2"/><path d="M1 18.5h7.5 M12.5 18.5h4 M20.5 18.5h6.5" stroke="currentColor" stroke-width="1.2"/><circle cx="3.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="10.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="10.5" cy="18.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="4.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="18.5" cy="18.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="21.5" cy="10.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="25.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15089
- elliott_impulse_wave: '<path d="M5.2 18.5 9.4 14.3 M11.9 13.9 16.1 18.1 M18.6 17.7 22.7 13.5" stroke="currentColor" stroke-width="1.2"/><circle cx="10.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="17.5" cy="19.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="24.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><text x="10.8" y="7" text-anchor="middle" font-size="7.5" fill="currentColor">1</text><text x="24.6" y="7" text-anchor="middle" font-size="7.5" fill="currentColor">5</text>',
15090
- elliott_correction: '<path d="M5.2 18.5 9.4 14.3 M11.9 13.9 16.1 18.1 M18.6 17.7 22.7 13.5" stroke="currentColor" stroke-width="1.2"/><circle cx="10.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="17.5" cy="19.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="24.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><text x="10.8" y="7" text-anchor="middle" font-size="7.5" fill="currentColor">A</text><text x="24.6" y="7" text-anchor="middle" font-size="7.5" fill="currentColor">C</text>',
15091
- elliott_triangle_wave: '<path d="M5.2 18.5 9.4 14.3 M11.9 13.9 16.1 18.1 M18.6 17.7 22.7 13.5" stroke="currentColor" stroke-width="1.2"/><circle cx="10.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="17.5" cy="19.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="24.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><text x="10.8" y="7" text-anchor="middle" font-size="7.5" fill="currentColor">A</text><text x="24.6" y="7" text-anchor="middle" font-size="7.5" fill="currentColor">E</text>',
15092
- elliott_double_combo: '<path d="M5.2 18.5 9.4 14.3 M11.9 13.9 16.1 18.1 M18.6 17.7 22.7 13.5" stroke="currentColor" stroke-width="1.2"/><circle cx="10.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="17.5" cy="19.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="24.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><text x="10.8" y="7" text-anchor="middle" font-size="7.5" fill="currentColor">W</text><text x="24.6" y="7" text-anchor="middle" font-size="7.5" fill="currentColor">Y</text>',
15093
- elliott_triple_combo: '<path d="M5.2 18.5 9.4 14.3 M11.9 13.9 16.1 18.1 M18.6 17.7 22.7 13.5" stroke="currentColor" stroke-width="1.2"/><circle cx="10.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="17.5" cy="19.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="24.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><text x="10.8" y="7" text-anchor="middle" font-size="7.5" fill="currentColor">W</text><text x="24.6" y="7" text-anchor="middle" font-size="7.5" fill="currentColor">Z</text>',
15094
- cyclic_lines: '<path d="M5.5 4v8.4 M5.5 16.6V25 M11.5 4v8.4 M11.5 16.6V25 M17.5 4v21 M23.5 4v21" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="14.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="11.5" cy="14.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15095
- time_cycles: '<path d="M-2.5 15A5.5 5.5 0 0 1 8.5 15 M8.5 15A5.5 5.5 0 0 1 19.5 15 M19.5 15A5.5 5.5 0 0 1 30.5 15" stroke="currentColor" stroke-width="1.2"/><circle cx="8.5" cy="17.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="19.5" cy="17.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15096
- sine_line: '<path d="M5.2 14.1C5.2 11.4 6 8.9 7.5 8 M11.1 8.6C12.7 9.9 13.3 12.1 14.1 14.6C15 17.4 15.9 20 17.7 21.3 M21.5 21.5C23 20.9 24 19.1 24.6 17.2C24.9 16.2 25.3 15.1 25.4 14.2" stroke="currentColor" stroke-width="1.2"/><circle cx="9.5" cy="7.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="19.5" cy="21.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15097
- long_position: '<path d="M8 6.5H25 M5 17.5h20 M8 22.5H25" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="6.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><text x="15.5" y="14.5" text-anchor="middle" font-size="7.5" fill="currentColor">L</text>',
15098
- short_position: '<path d="M8 6.5H25 M5 11.5h20 M8 22.5H25" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="6.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><text x="15.7" y="19" text-anchor="middle" font-size="7.5" fill="currentColor">S</text>',
15099
- forecast: '<path d="M7.5 6v6 M7.5 19.5V22 M14.5 5v5 M14.5 18v3 M21.5 5v6" stroke="currentColor" stroke-width="1.2"/><rect x="6.5" y="12.5" width="2" height="7" stroke="currentColor" stroke-width="1.2"/><rect x="13.5" y="10.5" width="2" height="7.5" stroke="currentColor" stroke-width="1.2"/><path d="M19 11h5l-2.5 3z" fill="currentColor"/><circle cx="21.5" cy="16.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15100
- bars_pattern: '<path d="M6.5 6v6.5 M6.5 19.5V22 M11.5 11v2.5 M11.5 16.5V24 M16.5 5v5.5 M16.5 18.5V21 M21.5 7v4.5 M21.5 16.5V19" stroke="currentColor" stroke-width="1.2"/><rect x="5.5" y="12.5" width="2" height="7" stroke="currentColor" stroke-width="1.2"/><rect x="10.5" y="13.5" width="2" height="3" stroke="currentColor" stroke-width="1.2"/><rect x="15.5" y="10.5" width="2" height="8" stroke="currentColor" stroke-width="1.2"/><rect x="20.5" y="11.5" width="2" height="5" stroke="currentColor" stroke-width="1.2"/>',
15101
- ghost_feed: '<path d="M4.5 18 7.7 16.7 M9.7 15.9 12.7 14.7 M14.7 13.9 17.7 12.7 M19.7 11.8 22.8 10.5" stroke="currentColor" stroke-width="1.2"/><path d="M8.5 9v4.5 M8.5 18.5v2.5 M13.5 6v5 M13.5 15v5 M18.5 3v5.5 M18.5 16.5v2.5" stroke="currentColor" stroke-width="1.2"/><rect x="7.5" y="13.5" width="2" height="5" stroke="currentColor" stroke-width="1.2"/><rect x="12.5" y="11" width="2" height="4" stroke="currentColor" stroke-width="1.2"/><rect x="17.5" y="8.5" width="2" height="8" stroke="currentColor" stroke-width="1.2"/>',
15102
- sector: '<path d="M5.5 8v13 M8 23.5H21 M7.6 5.1A18.4 18.4 0 0 1 23.9 21.4" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="23.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15103
- anchored_vwap: '<path d="M10.5 5v4.5 M10.5 21.5V25 M17.5 2v5.5 M17.5 17.5V23" stroke="currentColor" stroke-width="1.2"/><rect x="8.5" y="9.5" width="4" height="12" stroke="currentColor" stroke-width="1.2"/><rect x="15.5" y="7.5" width="4" height="10" stroke="currentColor" stroke-width="1.2"/><path d="M5.6 15.8 7.5 14.4 14.2 15.9 25 9.7" stroke="currentColor" stroke-width="1.2"/><circle cx="4" cy="17" r="2" stroke="currentColor" stroke-width="1.2"/>',
15104
- fixed_range_volume_profile: '<path d="M3.5 3v16 M23.5 8v16" stroke="currentColor" stroke-width="1.2"/><rect x="3.5" y="6.5" width="6" height="3" stroke="currentColor" stroke-width="1.2"/><rect x="3.5" y="9.5" width="9" height="3" stroke="currentColor" stroke-width="1.2"/><rect x="3.5" y="12.5" width="4" height="3" stroke="currentColor" stroke-width="1.2"/><circle cx="3.5" cy="21.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="23.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15105
- anchored_volume_profile: '<path d="M23.5 3v21 M9 13.5h5.5" stroke="currentColor" stroke-width="1.2"/><rect x="17.5" y="7.5" width="6" height="3" stroke="currentColor" stroke-width="1.2"/><rect x="12.5" y="10.5" width="11" height="3" stroke="currentColor" stroke-width="1.2"/><rect x="14.5" y="14.5" width="9" height="3" stroke="currentColor" stroke-width="1.2"/><rect x="20.5" y="17.5" width="3" height="3" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="13.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15106
- price_range: '<path d="M4 4.5h16.5 M8.5 24.5H25 M14.5 9v14" stroke="currentColor" stroke-width="1.2"/><path d="M14.5 6l2.5 3h-5z" fill="currentColor"/><circle cx="22.5" cy="4.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="24.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15107
- date_range: '<path d="M4.5 4v16.5 M24.5 8.5V25 M6 14.5h14" stroke="currentColor" stroke-width="1.2"/><path d="M20 12v5l3-2.5z" fill="currentColor"/><circle cx="4.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="24.5" cy="6.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15108
- date_and_price_range: '<path d="M4 4.5h17.5 M4.5 4v17.5 M6.5 23.5H24 M23.5 6.5V24" stroke="currentColor" stroke-width="1.2"/><path d="M13.5 9v13 M6 14.5h13" stroke="currentColor" stroke-width="1.2"/><path d="M13.5 6l2.5 3h-5z M19 12v5l3-2.5z" fill="currentColor"/><circle cx="4.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="23.5" cy="4.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15109
- brush: '<path d="M3.5 22.5c2.4-2.6 3.6-5.3 4.5-8 1.2-3.4 5.6-4.2 8.2-1.2 2.8 3.3-.3 9.2-5.5 9.2z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/><path d="M18.2 6.4 16.8 7.7c-1 .9-1 2.4-.1 3.4l1.9 1.9c1 1 2.5.9 3.4 0l5.5-5.7" stroke="currentColor" stroke-width="1.2"/>',
15110
- highlighter: '<path d="M15 2.7 26 13.7 19.3 20.4 14.7 21.9a1.2 1.2 0 0 1-1.2-.3l-5.9-6a1.2 1.2 0 0 1-.3-1.2L8.4 9.3z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/><path d="M8.9 10.5 18.2 19.8" stroke="currentColor" stroke-width="1.2"/><path d="M7.9 16.9l4.2 4.2-2.6 2.6-6.1-2.4z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/>',
15111
- arrow_marker: '<path d="M22.7 4.6a.8.8 0 0 1 1 1l-2.5 8.3c-.2.7-1.1.8-1.5.2l-.9-1.7-12.6 10a.8.8 0 0 1-1.1-1.1l10-12.6-1.7-.9c-.6-.4-.5-1.3.2-1.5z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/>',
15112
- arrow: '<path d="M7.3 20.7 15 13" stroke="currentColor" stroke-width="1.2"/><path d="M21 7l-8 3 5 5z" fill="currentColor"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15113
- arrow_up: '<path d="M10.5 16.5H4.8L14 5.5l9.2 11h-5.7v6h-7z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/>',
15114
- arrow_down: '<path d="M10.5 11.5H4.8L14 22.5l9.2-11h-5.7v-6h-7z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/>',
15115
- rectangle: '<path d="M7.5 5.5h13 M7.5 22.5h13 M5.5 7.5v13 M22.5 7.5v13" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15116
- rotated_rectangle: '<path d="M14.7 3.6 10.5 7.8 M7.7 10.6 3.5 14.8 M3.5 18.2l6.2 6.2 M13.2 24.5l4.2-4.2 M20.2 17.5l4.2-4.2 M24.4 9.7 18.2 3.5" stroke="currentColor" stroke-width="1.2"/><circle cx="16.5" cy="2.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="9.5" cy="9.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="2.5" cy="16.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="11.5" cy="25.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="18.5" cy="18.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="25.5" cy="11.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15117
- path: '<path d="M2 18.6 7.7 12.6 M11.3 12.3 14.7 15.7 M18.3 15.7 25.6 8.4 M21 7.5h5.5 M26.5 7.5V13" stroke="currentColor" stroke-width="1.2"/><circle cx="9.5" cy="10.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="16.5" cy="17.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15118
- circle: '<path d="M23.7 16.4A10 10 0 1 1 23.7 11.6" stroke="currentColor" stroke-width="1.2"/><circle cx="14" cy="14" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="24" cy="14" r="2" stroke="currentColor" stroke-width="1.2"/>',
15119
- ellipse: '<path d="M17 6.8A11 8 0 0 1 25 12.2 M25 16.8A11 8 0 0 1 17 22.2 M12 22.2A11 8 0 0 1 4 16.8 M4 12.2A11 8 0 0 1 12 6.8" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="6.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="25.5" cy="14.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="3.5" cy="14.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15120
- polyline: '<path d="M8.3 11.6 13.4 7.1 M16.5 5.5h4 M22.5 7.5v5 M20.5 14.5h-4 M14.5 16.5v4 M12.5 22.5h-4 M6.5 20.5v-6" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="12.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="14.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="14.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="14.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15121
- triangle: '<path d="M8.5 22.5h11 M6.5 8.5v12 M7.5 8.3 19.8 21.4" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="6.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="21.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15122
- arc: '<path d="M8.2 21.4 21.5 7.3" stroke="currentColor" stroke-width="1.2"/><path d="M8 23.9C12.5 26 17.8 26 21.5 23.4 M24 20C26 16 25.7 11 23.9 7.1" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="21.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15123
- curve: '<path d="M6.3 20.7C6.9 17.2 8 14.3 9.7 12.1 M12.2 9.7C14.7 7.9 17.7 6.8 20.7 6.3" stroke="currentColor" stroke-width="1.2"/><circle cx="5.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="10.5" cy="10.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="22.5" cy="5.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15124
- double_curve: '<path d="M6 24.9C9.8 26.5 13.3 26.5 15.7 23.6 M17.6 19.6C17.9 17.3 17 16 14.3 13.6C11.9 11.5 11.1 10.3 11.4 8.5 M12.9 5.1C15 2.6 18.1 2.5 21.6 4.1" stroke="currentColor" stroke-width="1.2"/><circle cx="4.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="16.5" cy="21.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="11.5" cy="6.5" r="2" stroke="currentColor" stroke-width="1.2"/><circle cx="23.5" cy="4.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15125
- text: '<path d="M7.5 9V5.5h13V9 M14 5.5v17 M11 22.5h6" stroke="currentColor" stroke-width="1.2"/>',
15126
- note: '<rect x="4.5" y="2.5" width="18" height="14" rx="1" stroke="currentColor" stroke-width="1.2"/><path d="M9.5 8V6h9v2 M14 6v7 M12 13h4 M13.5 16.5v4.5" stroke="currentColor" stroke-width="1.2"/><circle cx="13.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15127
- price_note: '<rect x="4.5" y="2.5" width="18" height="14" rx="1" stroke="currentColor" stroke-width="1.2"/><path d="M13.5 16.5v4.5" stroke="currentColor" stroke-width="1.2"/><text x="14" y="13" text-anchor="middle" font-size="10" fill="currentColor">$</text><circle cx="13.5" cy="23.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15128
- table: '<rect x="3.5" y="5.5" width="21" height="18" rx="1" stroke="currentColor" stroke-width="1.2"/><path d="M3.5 11.5h21 M3.5 17.5h21 M9.5 5.5v18" stroke="currentColor" stroke-width="1.2"/>',
15129
- callout: '<path d="M9.6 18.5 5.5 23.5V6.5a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/>',
15130
- comment: '<path d="M5.5 14a7 7 0 0 1 7-7h5a7 7 0 1 1 0 14H6.5a1 1 0 0 1-1-1z" stroke="currentColor" stroke-width="1.2"/>',
15131
- price_label: '<path d="M5.5 20.5v-14a1 1 0 0 1 1-1h16a1 1 0 0 1 1 1v11a1 1 0 0 1-1 1H12.6l-3.2 3.2" stroke="currentColor" stroke-width="1.2"/><circle cx="6.5" cy="22.5" r="2" stroke="currentColor" stroke-width="1.2"/>',
15132
- signpost: '<circle cx="14" cy="11.5" r="9" stroke="currentColor" stroke-width="1.2"/><path d="M14 20.5V27" stroke="currentColor" stroke-width="1.2"/><path d="M14 6.2l1.5 3.1 3.4.4-2.5 2.3.6 3.4-3-1.7-3 1.7.6-3.4-2.5-2.3 3.4-.4z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/>',
15133
- flag: '<path d="M5.5 23V5.5h16.7l-4.6 5.25 4.6 5.25H5.5" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/>',
15134
- image: '<rect x="3.5" y="4.5" width="21" height="19" rx="3.5" stroke="currentColor" stroke-width="1.2"/><circle cx="10" cy="10" r="1.5" stroke="currentColor" stroke-width="1.2"/><path d="M4.2 21.5 9.3 15.1l3.3 4 M12.9 17.4 18 10.7l5.9 7.7" stroke="currentColor" stroke-width="1.2"/>',
15135
- content_card: '<rect x="4.5" y="5.5" width="19" height="17" rx="2" stroke="currentColor" stroke-width="1.2"/><path d="M4.5 11.5h19 M8 15.5h9 M8 18.5h6" stroke="currentColor" stroke-width="1.2"/>',
15136
- pin: '<path d="M14 3.5a7.5 7.5 0 0 1 7.5 7.5c0 4.2-4.2 8.9-7.5 12.6C10.7 19.9 6.5 15.2 6.5 11A7.5 7.5 0 0 1 14 3.5Z" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round"/><circle cx="14" cy="11" r="3" stroke="currentColor" stroke-width="1.2"/>'
15137
- };
15138
-
15139
- // src/ui/chrome/arrangementGlyphs.ts
15140
- var ARRANGEMENT_ICONS = {
15141
- "s": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" d="M2.5 1C1.67 1 1 1.67 1 2.5v12c0 .83.67 1.5 1.5 1.5h14c.83 0 1.5-.67 1.5-1.5v-12c0-.83-.67-1.5-1.5-1.5h-14ZM0 2.5A2.5 2.5 0 0 1 2.5 0h14A2.5 2.5 0 0 1 19 2.5v12a2.5 2.5 0 0 1-2.5 2.5h-14A2.5 2.5 0 0 1 0 14.5v-12Z"></path>' },
15142
- "2h": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v15H2.5A1.5 1.5 0 0 1 1 14.5v-12ZM10 16h6.5c.83 0 1.5-.67 1.5-1.5v-12c0-.83-.67-1.5-1.5-1.5H10v15ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
15143
- "2v": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1h14c.83 0 1.5.67 1.5 1.5V8H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5h14c.83 0 1.5-.67 1.5-1.5V9H1Zm1.5-9A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
15144
- "3h": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H6v15H2.5A1.5 1.5 0 0 1 1 14.5v-12ZM7 16h5V1H7v15Zm6-15v15h3.5c.83 0 1.5-.67 1.5-1.5v-12c0-.83-.67-1.5-1.5-1.5H13ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
15145
- "3v": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1h14c.83 0 1.5.67 1.5 1.5V5H1V2.5ZM1 6v5h17V6H1Zm17 6H1v2.5c0 .83.67 1.5 1.5 1.5h14c.83 0 1.5-.67 1.5-1.5V12ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
15146
- "3s": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v15H2.5A1.5 1.5 0 0 1 1 14.5v-12ZM10 16h6.5c.83 0 1.5-.67 1.5-1.5V9h-8v7Zm8-8V2.5c0-.83-.67-1.5-1.5-1.5H10v7h8ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
15147
- "3r": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v7H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5H9V9H1Zm9 7h6.5c.83 0 1.5-.67 1.5-1.5v-12c0-.83-.67-1.5-1.5-1.5H10v15ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
15148
- "2-1": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v7H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5h14c.83 0 1.5-.67 1.5-1.5V9H1Zm17-1V2.5c0-.83-.67-1.5-1.5-1.5H10v7h8ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
15149
- "1-2": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1h14c.83 0 1.5.67 1.5 1.5V8H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5H9V9H1Zm9 7h6.5c.83 0 1.5-.67 1.5-1.5V9h-8v7ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
15150
- "4": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v7H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5H9V9H1Zm9 7h6.5c.83 0 1.5-.67 1.5-1.5V9h-8v7Zm8-8V2.5c0-.83-.67-1.5-1.5-1.5H10v7h8ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
15151
- "4v": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1h14c.83 0 1.5.67 1.5 1.5V4H1V2.5ZM1 5v3h17V5H1Zm17 4H1v3h17V9Zm0 4H1v1.5c0 .83.67 1.5 1.5 1.5h14c.83 0 1.5-.67 1.5-1.5V13ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
15152
- "4h": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H4v15H2.5A1.5 1.5 0 0 1 1 14.5v-12ZM5 16h4V1H5v15Zm5-15v15h4V1h-4Zm5 0v15h1.5c.83 0 1.5-.67 1.5-1.5v-12c0-.83-.67-1.5-1.5-1.5H15ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
15153
- "4s": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v15H2.5A1.5 1.5 0 0 1 1 14.5v-12ZM10 16h6.5c.83 0 1.5-.67 1.5-1.5V12h-8v4Zm8-5V6h-8v5h8Zm0-6V2.5c0-.83-.67-1.5-1.5-1.5H10v4h8ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
15154
- "4s-l": { viewBox: "0 0 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M2 3.5C2 2.67 2.67 2 3.5 2H11v4H2V3.5ZM2 7v5h9V7H2Zm0 6v2.5c0 .83.67 1.5 1.5 1.5H11v-4H2Zm10 4h5.5c.83 0 1.5-.67 1.5-1.5v-12c0-.83-.67-1.5-1.5-1.5H12v15ZM3.5 1A2.5 2.5 0 0 0 1 3.5v12A2.5 2.5 0 0 0 3.5 18h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 17.5 1h-14Z"></path>' },
15155
- "1-3": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1h14c.83 0 1.5.67 1.5 1.5V8H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5H6V9H1Zm6 7h5V9H7v7Zm6 0h3.5c.83 0 1.5-.67 1.5-1.5V9h-5v7ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
15156
- "3-1": { viewBox: "-1 -1 21 19", body: '<g transform="matrix(1,0,0,-1,0,0)"><path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1h14c.83 0 1.5.67 1.5 1.5V8H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5H6V9H1Zm6 7h5V9H7v7Zm6 0h3.5c.83 0 1.5-.67 1.5-1.5V9h-5v7ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path></g>' },
15157
- "2-2-l": { viewBox: "0 0 19 17", body: '<path fill="currentColor" fill-rule="evenodd" d="M2.5 1C1.67 1 1 1.67 1 2.5v12c0 .83.67 1.5 1.5 1.5H5V1zM10 16H6V1h4v15m1 0h5.5c.83 0 1.5-.67 1.5-1.5V9h-7zm7-8V2.5c0-.83-.67-1.5-1.5-1.5H11v7zM0 2.5A2.5 2.5 0 0 1 2.5 0h14A2.5 2.5 0 0 1 19 2.5v12a2.5 2.5 0 0 1-2.5 2.5h-14A2.5 2.5 0 0 1 0 14.5z"></path>' },
15158
- "2-2-r": { viewBox: "0 0 19 17", body: '<path fill="currentColor" fill-rule="evenodd" d="M16.5 1H14v15h2.5c.83 0 1.5-.67 1.5-1.5v-12c0-.83-.67-1.5-1.5-1.5M9 1h4v15H9V1M8 1H2.5C1.67 1 1 1.67 1 2.5V8h7zM1 9v5.5c0 .83.67 1.5 1.5 1.5H8V9zm1.5-9A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0z"></path>' },
15159
- "2-2": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v7H1V2.5ZM1 9v3h17V9H1Zm17-1V2.5c0-.83-.67-1.5-1.5-1.5H10v7h8Zm0 5H1v1.5c0 .83.67 1.5 1.5 1.5h14c.83 0 1.5-.67 1.5-1.5V13ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
15160
- "1-4": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1h14c.83 0 1.5.67 1.5 1.5V8H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5H4V9H1Zm4 7h4V9H5v7Zm5 0h4V9h-4v7Zm5 0h1.5c.83 0 1.5-.67 1.5-1.5V9h-3v7ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
15161
- "5h": { viewBox: "0 0 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M19 3.5c0-.83-.67-1.5-1.5-1.5H17v15h.5c.83 0 1.5-.67 1.5-1.5v-12Zm-17 12c0 .83.67 1.5 1.5 1.5H4V2h-.5C2.67 2 2 2.67 2 3.5v12ZM1.01 3.24A2.5 2.5 0 0 1 3.5 1h14A2.5 2.5 0 0 1 20 3.5v12a2.5 2.5 0 0 1-2.5 2.5h-14A2.5 2.5 0 0 1 1 15.5v-12l.01-.26ZM5 17h3V2H5v15Zm11 0h-3V2h3v15ZM12 2v15H9V2h3Z"></path>' },
15162
- "5v": { viewBox: "0 0 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 3.5A2.5 2.5 0 0 1 3.5 1h14A2.5 2.5 0 0 1 20 3.5v12a2.5 2.5 0 0 1-2.5 2.5h-14A2.5 2.5 0 0 1 1 15.5v-12ZM3.5 2h14c.83 0 1.5.67 1.5 1.5V4H2v-.5C2 2.67 2.67 2 3.5 2ZM2 5v2h17V5H2Zm17 3H2v3h17V8Zm0 4H2v2h17v-2Zm0 3H2v.5c0 .83.67 1.5 1.5 1.5h14c.83 0 1.5-.67 1.5-1.5V15Z"></path>' },
15163
- "5s": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v15H2.5A1.5 1.5 0 0 1 1 14.5v-12ZM10 16h6.5c.83 0 1.5-.67 1.5-1.5V13h-8v3Zm8-4V9h-8v3h8Zm0-4V5h-8v3h8Zm0-4V2.5c0-.83-.67-1.5-1.5-1.5H10v3h8ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
15164
- "5s-l": { viewBox: "-1 -1 21 19", body: '<g transform="matrix(-1,0,0,-1,0,0)"><path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v15H2.5A1.5 1.5 0 0 1 1 14.5v-12ZM10 16h6.5c.83 0 1.5-.67 1.5-1.5V13h-8v3Zm8-4V9h-8v3h8Zm0-4V5h-8v3h8Zm0-4V2.5c0-.83-.67-1.5-1.5-1.5H10v3h8ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path></g>' },
15165
- "2-3": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v7H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5H6V9H1Zm6 7h5V9H7v7Zm6 0h3.5c.83 0 1.5-.67 1.5-1.5V9h-5v7Zm5-8V2.5c0-.83-.67-1.5-1.5-1.5H10v7h8ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
15166
- "3-2": { viewBox: "0 0 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M2 3.5C2 2.67 2.67 2 3.5 2H7v7H2V3.5ZM2 10v5.5c0 .83.67 1.5 1.5 1.5h14c.83 0 1.5-.67 1.5-1.5V10h-8v7h-1v-7H2Zm17-1V3.5c0-.83-.67-1.5-1.5-1.5H14v7h5Zm-6-7H8v7h5V2ZM3.5 1A2.5 2.5 0 0 0 1 3.5v12A2.5 2.5 0 0 0 3.5 18h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 17.5 1h-14Z"></path>' },
15167
- "4-1": { viewBox: "-1 -1 21 19", body: '<g transform="matrix(-1,0,0,-1,0,0)"><path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1h14c.83 0 1.5.67 1.5 1.5V8H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5H4V9H1Zm4 7h4V9H5v7Zm5 0h4V9h-4v7Zm5 0h1.5c.83 0 1.5-.67 1.5-1.5V9h-3v7ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path></g>' },
15168
- "2-3-l": { viewBox: "0 0 19 17", body: '<path fill="currentColor" fill-rule="evenodd" d="M10 1H6v15h4V1m1 0v4h7V2.5c0-.83-.67-1.5-1.5-1.5zm7 5h-7v5h7zm0 6h-7v4h5.5c.83 0 1.5-.67 1.5-1.5zM2.5 1H5v15H2.5A1.5 1.5 0 0 1 1 14.5v-12C1 1.67 1.67 1 2.5 1m0-1A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0z"></path>' },
15169
- "2-3-r": { viewBox: "0 0 19 17", body: '<path fill="currentColor" fill-rule="evenodd" d="M16.5 1H14v15h2.5c.83 0 1.5-.67 1.5-1.5v-12c0-.83-.67-1.5-1.5-1.5M9 1h4v15H9V1M8 1H2.5C1.67 1 1 1.67 1 2.5V5h7zM1 6v5h7V6zm0 6v2.5c0 .83.67 1.5 1.5 1.5H8v-4zM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0z"></path>' },
15170
- "6": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H6v7H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5H6V9H1Zm6 7h5V9H7v7Zm6 0h3.5c.83 0 1.5-.67 1.5-1.5V9h-5v7Zm5-8V2.5c0-.83-.67-1.5-1.5-1.5H13v7h5Zm-6-7H7v7h5V1ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
15171
- "6h": { viewBox: "0 0 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M2 3.5C2 2.67 2.67 2 3.5 2H4v15h-.5A1.5 1.5 0 0 1 2 15.5v-12ZM5 17h2V2H5v15ZM8 2v15h2V2H8Zm3 0v15h2V2h-2Zm3 0v15h2V2h-2Zm3 0v15h.5c.83 0 1.5-.67 1.5-1.5v-12c0-.83-.67-1.5-1.5-1.5H17ZM3.5 1A2.5 2.5 0 0 0 1 3.5v12A2.5 2.5 0 0 0 3.5 18h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 17.5 1h-14Z"></path>' },
15172
- "6v": { viewBox: "0 0 21 19", body: '<g fill="none"><rect width="18" height="16" stroke="currentColor" rx="2" x="1.5" y="1.5"></rect><path fill="currentColor" d="M1.5 4h18v1h-18V4Z"></path><path fill="currentColor" d="M2 7h18v1H2V7Z" opacity=".65"></path><path fill="currentColor" d="M1.5 10h18v1h-18v-1Z" opacity=".25"></path><path fill="currentColor" d="M1.5 13h18v1h-18v-1Z" opacity=".05"></path></g>' },
15173
- "6c": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v4H1V2.5ZM1 6v5h8V6H1Zm0 6v2.5c0 .83.67 1.5 1.5 1.5H9v-4H1Zm9 4h6.5c.83 0 1.5-.67 1.5-1.5V12h-8v4Zm8-5V6h-8v5h8Zm0-6V2.5c0-.83-.67-1.5-1.5-1.5H10v4h8ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
15174
- "2-4": { viewBox: "0 0 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 3.5A2.5 2.5 0 0 1 3.5 1h14A2.5 2.5 0 0 1 20 3.5v12a2.5 2.5 0 0 1-2.5 2.5h-14A2.5 2.5 0 0 1 1 15.5v-12ZM11 2h6.5c.83 0 1.5.67 1.5 1.5V9h-8V2Zm-1 0H3.5C2.67 2 2 2.67 2 3.5V9h8V2Zm-8 8v5.5c0 .83.67 1.5 1.5 1.5H5v-7H2Zm4 7h4v-7H6v7Zm5 0h4v-7h-4v7Zm5 0h1.5c.83 0 1.5-.67 1.5-1.5V10h-3v7Z"></path>' },
15175
- "4-2": { viewBox: "0 0 19 17", body: '<path fill="currentColor" fill-rule="evenodd" d="M15 1h1.5c.83 0 1.5.67 1.5 1.5v5h-3zm-1 0h-4v6.5h4zM9 1H5v6.5h4zM4 1H2.5C1.67 1 1 1.67 1 2.5v5h3zM1 8.5v6c0 .83.67 1.5 1.5 1.5H9V8.5H1m9 7.5h6.5c.83 0 1.5-.67 1.5-1.5v-6h-8zM0 2.5A2.5 2.5 0 0 1 2.5 0h14A2.5 2.5 0 0 1 19 2.5v12a2.5 2.5 0 0 1-2.5 2.5h-14A2.5 2.5 0 0 1 0 14.5z"></path>' },
15176
- "4-3": { viewBox: "0 0 19 17", body: '<path fill="currentColor" fill-rule="evenodd" d="M14 1h-4v7h4zm1 8h-2v7h3.5c.83 0 1.5-.67 1.5-1.5V9zm-3 7V9H7v7zM5 9h1v7H2.5A1.5 1.5 0 0 1 1 14.5V9h4m13-1V2.5c0-.83-.67-1.5-1.5-1.5H15v7zM1 8h3V1H2.5C1.67 1 1 1.67 1 2.5zm4 0h4V1H5zM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0z"></path>' },
15177
- "7h": { viewBox: "0 0 21 19", body: '<g fill="none"><rect width="18" height="16" stroke="currentColor" rx="2" x="1.5" y="1.5"></rect><path fill="currentColor" d="M4 17V2h1v15H4Z"></path><path fill="currentColor" d="M7 17V2h1v15H7Z" opacity=".85"></path><path fill="currentColor" d="M10 17V2h1v15h-1Z" opacity=".65"></path><path fill="currentColor" d="M13 17V2h1v15h-1Z" opacity=".25"></path><path fill="currentColor" d="M16 17V2h1v15h-1Z" opacity=".05"></path></g>' },
15178
- "7s": { viewBox: "0 0 19 17", body: '<g fill="currentColor"><path fill-rule="evenodd" d="M16.5 1h-14C1.67 1 1 1.67 1 2.5v12c0 .83.67 1.5 1.5 1.5h14c.83 0 1.5-.67 1.5-1.5v-12c0-.83-.67-1.5-1.5-1.5m-14-1A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0z"></path><path d="M9 3h9v1H9z"></path><path d="M9 17V1h1v16z"></path><path d="M9 6h9v1H9z" opacity=".65"></path><path d="M9 9h9v1H9z" opacity=".25"></path><path d="M9 12h9v1H9z" opacity=".05"></path></g>' },
15179
- "8": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H4v7H1V2.5ZM1 9v5.5c0 .83.67 1.5 1.5 1.5H4V9H1Zm4 7h4V9H5v7Zm5 0h4V9h-4v7Zm5 0h1.5c.83 0 1.5-.67 1.5-1.5V9h-3v7Zm3-8V2.5c0-.83-.67-1.5-1.5-1.5H15v7h3Zm-4-7h-4v7h4V1ZM9 1H5v7h4V1ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
15180
- "8c": { viewBox: "-1 -1 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M1 2.5C1 1.67 1.67 1 2.5 1H9v3H1V2.5ZM1 5v3h8V5H1Zm0 4v3h8V9H1Zm0 4v1.5c0 .83.67 1.5 1.5 1.5H9v-3H1Zm9 3h6.5c.83 0 1.5-.67 1.5-1.5V13h-8v3Zm8-4V9h-8v3h8Zm0-4V5h-8v3h8Zm0-4V2.5c0-.83-.67-1.5-1.5-1.5H10v3h8ZM2.5 0A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0h-14Z"></path>' },
15181
- "8h": { viewBox: "0 0 21 19", body: '<g fill="none"><rect width="18" height="16" stroke="currentColor" rx="2" x="1.5" y="1.5"></rect><path fill="currentColor" d="M4 17V2h1v15H4Z"></path><path fill="currentColor" d="M7 17V2h1v15H7Z" opacity=".85"></path><path fill="currentColor" d="M10 17V2h1v15h-1Z" opacity=".65"></path><path fill="currentColor" d="M13 17V2h1v15h-1Z" opacity=".25"></path><path fill="currentColor" d="M16 17V2h1v15h-1Z" opacity=".05"></path></g>' },
15182
- "8v": { viewBox: "0 0 21 19", body: '<g fill="none"><rect width="18" height="16" stroke="currentColor" rx="2" x="1.5" y="1.5"></rect><path fill="currentColor" d="M1.5 4h18v1h-18V4Z"></path><path fill="currentColor" d="M2 7h18v1H2V7Z" opacity=".65"></path><path fill="currentColor" d="M1.5 10h18v1h-18v-1Z" opacity=".25"></path><path fill="currentColor" d="M1.5 13h18v1h-18v-1Z" opacity=".05"></path></g>' },
15183
- "9s": { viewBox: "0 0 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M3.5 1A2.5 2.5 0 0 0 1 3.5v12A2.5 2.5 0 0 0 3.5 18h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 17.5 1h-14ZM7 2H3.5C2.67 2 2 2.67 2 3.5V6h5V2Zm1 0v4h5V2H8Zm0 5h5v5H8V7Zm-1 5V7H2v5h5Zm-5 1h5v4H3.5A1.5 1.5 0 0 1 2 15.5V13Zm6 0h5v4H8v-4Zm6 0v4h3.5c.83 0 1.5-.67 1.5-1.5V13h-5Zm5-1V7h-5v5h5ZM14 2v4h5V3.5c0-.83-.67-1.5-1.5-1.5H14Z"></path>' },
15184
- "5-4": { viewBox: "0 0 19 17", body: '<path fill="currentColor" fill-rule="evenodd" d="M7 1H4v7h3zm1 0v7h3V1zm4 0v7h3V1zm0 8h-2v7h4V9zm3 0h3v5.5c0 .83-.67 1.5-1.5 1.5H15zm1-8v7h2V2.5c0-.83-.67-1.5-1.5-1.5zM8 9H5v7h4V9zM2.5 1H3v7H1V2.5C1 1.67 1.67 1 2.5 1M1 9h3v7H2.5A1.5 1.5 0 0 1 1 14.5zm1.5-9A2.5 2.5 0 0 0 0 2.5v12A2.5 2.5 0 0 0 2.5 17h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 16.5 0z"></path>' },
15185
- "9h": { viewBox: "0 0 21 19", body: '<g fill="none"><rect width="18" height="16" stroke="currentColor" rx="2" x="1.5" y="1.5"></rect><path fill="currentColor" d="M4 17V2h1v15H4Z"></path><path fill="currentColor" d="M7 17V2h1v15H7Z" opacity=".85"></path><path fill="currentColor" d="M10 17V2h1v15h-1Z" opacity=".65"></path><path fill="currentColor" d="M13 17V2h1v15h-1Z" opacity=".25"></path><path fill="currentColor" d="M16 17V2h1v15h-1Z" opacity=".05"></path></g>' },
15186
- "9v": { viewBox: "0 0 21 19", body: '<g fill="none"><rect width="18" height="16" stroke="currentColor" rx="2" x="1.5" y="1.5"></rect><path fill="currentColor" d="M1.5 4h18v1h-18V4Z"></path><path fill="currentColor" d="M2 7h18v1H2V7Z" opacity=".65"></path><path fill="currentColor" d="M1.5 10h18v1h-18v-1Z" opacity=".25"></path><path fill="currentColor" d="M1.5 13h18v1h-18v-1Z" opacity=".05"></path></g>' },
15187
- "10c5": { viewBox: "0 0 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M2 3.5C2 2.67 2.67 2 3.5 2H4v7H2V3.5ZM2 10v5.5c0 .83.67 1.5 1.5 1.5H4v-7H2Zm3 7h3v-7H5v7Zm4 0h3v-7H9v7Zm4 0h3v-7h-3v7Zm4 0h.5c.83 0 1.5-.67 1.5-1.5V10h-2v7Zm2-8V3.5c0-.83-.67-1.5-1.5-1.5H17v7h2Zm-3-7h-3v7h3V2Zm-4 0H9v7h3V2ZM8 2H5v7h3V2ZM3.5 1A2.5 2.5 0 0 0 1 3.5v12A2.5 2.5 0 0 0 3.5 18h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 17.5 1h-14Z"></path>' },
15188
- "10h": { viewBox: "0 0 21 19", body: '<g fill="none"><rect width="18" height="16" stroke="currentColor" rx="2" x="1.5" y="1.5"></rect><path fill="currentColor" d="M4 17V2h1v15H4Z"></path><path fill="currentColor" d="M7 17V2h1v15H7Z" opacity=".85"></path><path fill="currentColor" d="M10 17V2h1v15h-1Z" opacity=".65"></path><path fill="currentColor" d="M13 17V2h1v15h-1Z" opacity=".25"></path><path fill="currentColor" d="M16 17V2h1v15h-1Z" opacity=".05"></path></g>' },
15189
- "10v": { viewBox: "0 0 21 19", body: '<g fill="none"><rect width="18" height="16" stroke="currentColor" rx="2" x="1.5" y="1.5"></rect><path fill="currentColor" d="M1.5 4h18v1h-18V4Z"></path><path fill="currentColor" d="M2 7h18v1H2V7Z" opacity=".65"></path><path fill="currentColor" d="M1.5 10h18v1h-18v-1Z" opacity=".25"></path><path fill="currentColor" d="M1.5 13h18v1h-18v-1Z" opacity=".05"></path></g>' },
15190
- "12c6": { viewBox: "0 0 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M2 3.5C2 2.67 2.67 2 3.5 2H4v7H2V3.5ZM2 10v5.5c0 .83.67 1.5 1.5 1.5H4v-7H2Zm3 7h2v-7H5v7Zm3 0h2v-7H8v7Zm3 0h2v-7h-2v7Zm3 0h2v-7h-2v7Zm3 0h.5c.83 0 1.5-.67 1.5-1.5V10h-2v7Zm2-8V3.5c0-.83-.67-1.5-1.5-1.5H17v7h2Zm-3-7h-2v7h2V2Zm-3 0h-2v7h2V2Zm-3 0H8v7h2V2ZM7 2H5v7h2V2ZM3.5 1A2.5 2.5 0 0 0 1 3.5v12A2.5 2.5 0 0 0 3.5 18h14a2.5 2.5 0 0 0 2.5-2.5v-12A2.5 2.5 0 0 0 17.5 1h-14Z"></path>' },
15191
- "12c4": { viewBox: "0 0 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M2 3.5C2 2.67 2.67 2 3.5 2H7v3H2v1h5v3H2v1h5v3H2v1h5v3H3.5A1.5 1.5 0 0 1 2 15.5v-12ZM8 14v3h5v-3H8Zm6 0v3h3.5c.83 0 1.5-.67 1.5-1.5V14h-5Zm5-1h-5v-3h5v3Zm-6 0H8v-3h5v3ZM8 9h5V6H8v3Zm6 0h5V6h-5v3Zm-1-4H8V2h5v3Zm1 13H3.5A2.5 2.5 0 0 1 1 15.5v-12A2.5 2.5 0 0 1 3.5 1h14A2.5 2.5 0 0 1 20 3.5v12a2.5 2.5 0 0 1-2.5 2.5H14Zm0-13V2h3.5c.83 0 1.5.67 1.5 1.5V5h-5Z"></path>' },
15192
- "12h": { viewBox: "0 0 21 19", body: '<g fill="none"><rect width="18" height="16" stroke="currentColor" rx="2" x="1.5" y="1.5"></rect><path fill="currentColor" d="M4 17V2h1v15H4Z"></path><path fill="currentColor" d="M7 17V2h1v15H7Z" opacity=".85"></path><path fill="currentColor" d="M10 17V2h1v15h-1Z" opacity=".65"></path><path fill="currentColor" d="M13 17V2h1v15h-1Z" opacity=".25"></path><path fill="currentColor" d="M16 17V2h1v15h-1Z" opacity=".05"></path></g>' },
15193
- "14c7": { viewBox: "0 0 21 19", body: '<g fill="none"><rect width="18" height="16" stroke="currentColor" rx="2" x="1.5" y="1.5"></rect><path fill="currentColor" d="M19 10H2V9h17v1Z"></path><path fill="currentColor" d="M4 17V2h1v15H4Z"></path><path fill="currentColor" d="M7 17V2h1v15H7Z" opacity=".85"></path><path fill="currentColor" d="M10 17V2h1v15h-1Z" opacity=".65"></path><path fill="currentColor" d="M13 17V2h1v15h-1Z" opacity=".25"></path><path fill="currentColor" d="M16 18V2h1v16h-1Z" opacity=".05"></path></g>' },
15194
- "16c8": { viewBox: "0 0 21 19", body: '<g fill="none"><rect width="18" height="16" stroke="currentColor" rx="2" x="1.5" y="1.5"></rect><path fill="currentColor" d="M19 10H2V9h17v1Z"></path><path fill="currentColor" d="M4 17V2h1v15H4Z"></path><path fill="currentColor" d="M7 17V2h1v15H7Z" opacity=".85"></path><path fill="currentColor" d="M10 17V2h1v15h-1Z" opacity=".65"></path><path fill="currentColor" d="M13 17V2h1v15h-1Z" opacity=".25"></path><path fill="currentColor" d="M16 18V2h1v16h-1Z" opacity=".05"></path></g>' },
15195
- "16c4": { viewBox: "0 0 21 19", body: '<path fill="currentColor" fill-rule="evenodd" d="M3.5 2C2.67 2 2 2.67 2 3.5v12c0 .83.67 1.5 1.5 1.5H5v-3H2v-1h3v-3H2V9h3V6H2V5h3V2H3.5ZM6 14v3h4v-3H6Zm4-1H6v-3h4v3Zm1 1v3h4v-3h-4Zm4-1h-4v-3h4v3Zm1 1v3h1.5c.83 0 1.5-.67 1.5-1.5V14h-3Zm3-1h-3v-3h3v3Zm-8-4h4V6h-4v3Zm5-3v3h3V6h-3ZM6 9h4V6H6v3Zm0-4h4V2H6v3Zm10 13H3.5A2.5 2.5 0 0 1 1 15.5v-12A2.5 2.5 0 0 1 3.5 1h14A2.5 2.5 0 0 1 20 3.5v12a2.5 2.5 0 0 1-2.5 2.5H16Zm0-13V2h1.5c.83 0 1.5.67 1.5 1.5V5h-3Zm-1-3h-4v3h4V2Z"></path>' }
15196
- };
15204
+ observed.clear();
15205
+ deps.chart.unsubscribeCrosshairMove(onCrosshair);
15206
+ status2?.close();
15207
+ status2 = null;
15208
+ legend2?.destroy();
15209
+ legend2 = null;
15210
+ }
15211
+ };
15212
+ }
15197
15213
 
15198
- // src/ui/icons/catalog.ts
15199
- var byMeaning = (table) => table;
15200
- var CONTROL_ICONS = byMeaning({
15201
- // The top bar and the widget's menus.
15202
- compare: [ICONS.comparePlus],
15203
- indicators: [ICONS.indicators],
15204
- replay: [ICONS.replay],
15205
- undo: [ICONS.undo],
15206
- redo: [ICONS.redo],
15207
- settings: [ICONS.settings, ICONS.gear, ICONS.legendSettings],
15208
- fullscreen: [ICONS.fullscreen],
15209
- fullscreenExit: [ICONS.exitFullscreen],
15210
- image: [ICONS.camera],
15211
- download: [ICONS.download],
15212
- copy: [ICONS.copy],
15213
- caret: [ICONS.menuArrowWide],
15214
- info: [ICONS.info],
15215
- // The legend.
15216
- visible: [ICONS.legendEye],
15217
- hidden: [ICONS.legendEyeOff],
15218
- collapse: [ICONS.legendChevron],
15219
- paneCollapse: [ICONS.paneCollapse],
15220
- paneRestore: [ICONS.paneRestore],
15221
- paneMaximize: [ICONS.paneMaximize],
15222
- marketStatus: [ICONS.marketStatus],
15223
- replayStatus: [ICONS.replayStatus],
15224
- replayMark: [ICONS.replayMark],
15225
- replayCut: [ICONS.replayCut],
15226
- // The navigation cluster.
15227
- zoomIn: [ICONS.navZoomIn],
15228
- zoomOut: [ICONS.navZoomOut],
15229
- scroll: [ICONS.navScroll],
15230
- reset: [ICONS.navReset],
15231
- tileMaximize: [ICONS.tileMaximize],
15232
- tileRestore: [ICONS.tileRestore],
15233
- // Rows, lists and dialogs.
15234
- check: [ICONS.check],
15235
- close: [ICONS.close, ICONS.closeThin, ICONS.dialogClose],
15236
- remove: [ICONS.close18, ICONS.removeRow],
15237
- delete: [ICONS.trash, ICONS.trash28],
15238
- add: [ICONS.plus, ICONS.plusThin, ICONS.plus24],
15239
- search: [ICONS.search, ICONS.search24],
15240
- clear: [ICONS.clear],
15241
- open: [ICONS.folder],
15242
- rename: [ICONS.pencil],
15243
- duplicate: [ICONS.clone],
15244
- favorite: [ICONS.star, ICONS.pickerStar],
15245
- favorited: [ICONS.starFilled, ICONS.pickerStarFilled],
15246
- sortAscending: [ICONS.sortUp, ICONS.sortUpRow],
15247
- sortDescending: [ICONS.sortDown, ICONS.sortDownRow],
15248
- chevronUp: [ICONS.chevronUp],
15249
- chevronDown: [ICONS.chevronDown, ICONS.chevronDown18],
15250
- chevronLeft: [ICONS.chevronLeft],
15251
- chevronRight: [ICONS.chevronRight],
15252
- // The drawing toolbar's arrow, pointing where the flyout it opens will stand.
15253
- flyout: [ICONS.chevronRight16],
15254
- submenu: [ICONS.submenuArrow],
15255
- more: [ICONS.kebab],
15256
- grip: [ICONS.grip],
15257
- emptySearch: [SEARCH_EMPTY_MARK],
15258
- emptyCompare: [COMPARE_EMPTY_MARK],
15259
- // The symbol search's spread builder.
15260
- operatorsShow: [ICONS.spreadOpsShow],
15261
- operatorsHide: [ICONS.spreadOpsHide],
15262
- operatorAdd: [OPERATOR_GLYPHS.addition],
15263
- operatorSubtract: [OPERATOR_GLYPHS.subtraction],
15264
- operatorMultiply: [OPERATOR_GLYPHS.multiplication],
15265
- operatorDivide: [OPERATOR_GLYPHS.division],
15266
- operatorPower: [OPERATOR_GLYPHS.exponentiation],
15267
- operatorReciprocal: [OPERATOR_GLYPHS.reciprocal],
15268
- // The replay transport.
15269
- play: [ICONS.play],
15270
- pause: [ICONS.pause],
15271
- stepForward: [ICONS.stepForward],
15272
- stepBack: [ICONS.stepBack],
15273
- goLive: [ICONS.goLive],
15274
- selectBar: [ICONS.selectBar],
15275
- selectDate: [ICONS.calendar],
15276
- firstAvailable: [ICONS.firstAvailable],
15277
- randomBar: [ICONS.randomBar],
15278
- // The drawing toolbar, its menus, the favorites bar and the drawing settings.
15279
- cursorCross: [ICONS.cursorCross],
15280
- cursorDot: [ICONS.cursorDot],
15281
- cursorArrow: [ICONS.cursorArrow],
15282
- eraser: [ICONS.eraser],
15283
- measure: [ICONS.ruler],
15284
- zoomTool: [ICONS.zoomIn],
15285
- magnet: [ICONS.magnet],
15286
- magnetStrong: [ICONS.magnetStrong],
15287
- stayInMode: [ICONS.pin],
15288
- stayInModeOn: [ICONS.pinOn],
15289
- locked: [ICONS.lockClosed],
15290
- unlocked: [ICONS.lockOpen],
15291
- drawingsShown: [ICONS.drawingsShown],
15292
- drawingsHidden: [ICONS.drawingsHidden],
15293
- indicatorsShown: [ICONS.indicatorsShown],
15294
- indicatorsHidden: [ICONS.indicatorsHidden],
15295
- allShown: [ICONS.allShown],
15296
- allHidden: [ICONS.allHidden],
15297
- hide: [ICONS.eyeCrossed],
15298
- sync: [ICONS.sync],
15299
- glyphTools: [ICONS.groupGlyphs],
15300
- favoritesBar: [ICONS.favoritesBar],
15301
- template: [ICONS.template],
15302
- visualOrder: [ICONS.layers],
15303
- lineColor: [ICONS.pencil16],
15304
- fillColor: [ICONS.bucket],
15305
- textColor: [ICONS.textTee],
15306
- lineSolid: [ICONS.lineSolid],
15307
- lineDashed: [ICONS.lineDashed],
15308
- lineDotted: [ICONS.lineDotted],
15309
- lineThickness1: [ICONS.lineThickness1],
15310
- lineThickness2: [ICONS.lineThickness2],
15311
- lineThickness3: [ICONS.lineThickness3],
15312
- lineThickness4: [ICONS.lineThickness4],
15313
- // Drawn for a line's left end; the right end wears the same drawing mirrored.
15314
- lineEndNormal: [ICONS.lineEndNormal],
15315
- lineEndArrow: [ICONS.lineEndArrow]
15316
- });
15317
- var MIRRORED_ICONS = /* @__PURE__ */ new Set(["flyout"]);
15318
- var MINIATURE_TOOLS = Object.keys(TOOL_ICONS);
15319
- var ARRANGEMENT_CODES = Object.keys(ARRANGEMENT_ICONS);
15320
- var toolGlyphs = new Map(MINIATURE_TOOLS.map((type) => [type, { viewBox: "0 0 28 28", body: TOOL_ICONS[type] }]));
15321
- var arrangementGlyphs = new Map(ARRANGEMENT_CODES.map((code) => [code, { viewBox: ARRANGEMENT_ICONS[code].viewBox, body: ARRANGEMENT_ICONS[code].body }]));
15322
- var toolGlyph = (type) => toolGlyphs.get(type);
15323
- var arrangementGlyphOf = (code) => arrangementGlyphs.get(code);
15324
- var CHART_ICON_IDS = [
15325
- ...Object.keys(CONTROL_ICONS),
15326
- ...CHART_STYLES.map((style) => `style.${style}`),
15327
- ...MINIATURE_TOOLS.map((type) => `tool.${type}`),
15328
- ...ARRANGEMENT_CODES.map((code) => `layout.${code}`)
15329
- ];
15330
- var PUBLISHED = new Set(CHART_ICON_IDS);
15331
- var ICON_OF = /* @__PURE__ */ new WeakMap();
15332
- for (const [id, glyphs] of Object.entries(CONTROL_ICONS)) for (const mark of glyphs) ICON_OF.set(mark, id);
15333
- for (const style of CHART_STYLES) ICON_OF.set(STYLE_ICONS[style], `style.${style}`);
15334
- for (const type of MINIATURE_TOOLS) ICON_OF.set(toolGlyphs.get(type), `tool.${type}`);
15335
- for (const code of ARRANGEMENT_CODES) ICON_OF.set(arrangementGlyphs.get(code), `layout.${code}`);
15336
- var iconOf = (mark) => ICON_OF.get(mark);
15337
- var GLYPHS_OF = new Map([
15338
- ...Object.entries(CONTROL_ICONS),
15339
- ...CHART_STYLES.map((style) => [`style.${style}`, [STYLE_ICONS[style]]]),
15340
- ...MINIATURE_TOOLS.map((type) => [`tool.${type}`, [toolGlyphs.get(type)]]),
15341
- ...ARRANGEMENT_CODES.map((code) => [`layout.${code}`, [arrangementGlyphs.get(code)]])
15342
- ]);
15343
- var standsAlone = (mark) => !/var\(--|class=/.test(mark.body);
15344
- function chartIconArtwork(id) {
15345
- const glyphs = GLYPHS_OF.get(id) ?? [];
15346
- if (!glyphs.every(standsAlone)) return [];
15347
- return glyphs.map((mark) => ({
15348
- viewBox: mark.viewBox,
15349
- body: mark.body,
15350
- svg: `<svg xmlns="http://www.w3.org/2000/svg" viewBox="${mark.viewBox}" fill="none">${mark.body}</svg>`
15351
- }));
15214
+ // src/widget/fling.ts
15215
+ function attachFling(deps) {
15216
+ const scale = () => deps.chart.timeScale();
15217
+ let samples = [];
15218
+ let movedAt = null;
15219
+ let oneFinger = false;
15220
+ let frame = null;
15221
+ const stop = () => {
15222
+ if (frame !== null && typeof cancelAnimationFrame === "function") cancelAnimationFrame(frame);
15223
+ frame = null;
15224
+ };
15225
+ const record3 = (t) => {
15226
+ samples.push({ t, position: scale().scrollPosition() });
15227
+ while (samples.length > 2 && samples[0].t < t - 2 * FLING_SAMPLE_MS) samples.shift();
15228
+ };
15229
+ const coast = (speed) => {
15230
+ if (typeof requestAnimationFrame !== "function") return;
15231
+ let last = performance.now();
15232
+ let travelling = speed;
15233
+ let position = null;
15234
+ const step = (now) => {
15235
+ if (frame === null) return;
15236
+ const s = scale();
15237
+ position ??= s.scrollPosition();
15238
+ const next = flingStep(travelling, Math.max(0, now - last));
15239
+ last = now;
15240
+ travelling = next.speed;
15241
+ position += next.moved;
15242
+ s.scrollToPosition(position, false);
15243
+ if (Math.abs(travelling) * s.options().barSpacing < FLING_REST_PX_PER_MS) {
15244
+ frame = null;
15245
+ return;
15246
+ }
15247
+ frame = requestAnimationFrame(step);
15248
+ };
15249
+ frame = requestAnimationFrame(step);
15250
+ };
15251
+ const onStart = (event) => {
15252
+ stop();
15253
+ samples = [];
15254
+ movedAt = null;
15255
+ oneFinger = event.touches.length === 1;
15256
+ if (oneFinger) record3(performance.now());
15257
+ };
15258
+ const onMove = (event) => {
15259
+ if (event.touches.length !== 1) oneFinger = false;
15260
+ if (!oneFinger) return;
15261
+ if (movedAt !== null) record3(movedAt);
15262
+ movedAt = performance.now();
15263
+ };
15264
+ const onEnd = (event) => {
15265
+ const thrown = oneFinger && event.touches.length === 0;
15266
+ oneFinger = false;
15267
+ if (!thrown) return;
15268
+ if (movedAt !== null) record3(movedAt);
15269
+ const spacing = scale().options().barSpacing;
15270
+ const speed = flingSpeed(samples, performance.now(), spacing);
15271
+ samples = [];
15272
+ movedAt = null;
15273
+ if (Math.abs(speed) * spacing >= FLING_REST_PX_PER_MS) coast(speed);
15274
+ };
15275
+ const onCancel = () => {
15276
+ oneFinger = false;
15277
+ samples = [];
15278
+ movedAt = null;
15279
+ };
15280
+ deps.target.addEventListener("touchstart", onStart, { passive: true });
15281
+ deps.target.addEventListener("touchmove", onMove, { passive: true });
15282
+ deps.target.addEventListener("touchend", onEnd, { passive: true });
15283
+ deps.target.addEventListener("touchcancel", onCancel, { passive: true });
15284
+ return {
15285
+ stop,
15286
+ destroy() {
15287
+ stop();
15288
+ deps.target.removeEventListener("touchstart", onStart);
15289
+ deps.target.removeEventListener("touchmove", onMove);
15290
+ deps.target.removeEventListener("touchend", onEnd);
15291
+ deps.target.removeEventListener("touchcancel", onCancel);
15292
+ }
15293
+ };
15352
15294
  }
15353
- function checkIcons(icons) {
15354
- if (icons === void 0) return;
15355
- if (typeof icons !== "object" || icons === null || Array.isArray(icons)) throw new TypeError("icons must be an object");
15356
- for (const [id, factory] of Object.entries(icons)) {
15357
- if (!PUBLISHED.has(id)) throw new TypeError(`icons.${id} is not an icon the chart draws; CHART_ICON_IDS lists every one`);
15358
- if (factory !== void 0 && typeof factory !== "function") throw new TypeError(`icons.${id} must be a function that draws the icon`);
15359
- }
15295
+
15296
+ // src/widget/pinch.ts
15297
+ function attachPinch(deps) {
15298
+ const scale = () => deps.chart.timeScale();
15299
+ let pinch = null;
15300
+ let panned = false;
15301
+ const read = (touches) => {
15302
+ const a = touches[0];
15303
+ const b = touches[1];
15304
+ const left = deps.chart.chartElement().getBoundingClientRect().left + deps.chart.priceScale("left").width();
15305
+ return { distance: Math.hypot(a.clientX - b.clientX, a.clientY - b.clientY), x: (a.clientX + b.clientX) / 2 - left };
15306
+ };
15307
+ const begin = (event) => {
15308
+ pinch = null;
15309
+ if (event.touches.length === 1) panned = false;
15310
+ if (event.touches.length !== 2 || panned || !scalingOpen(deps.chart.options().handleScale)) return;
15311
+ const range2 = scale().getVisibleLogicalRange();
15312
+ if (range2 === null) return;
15313
+ const { distance, x } = read(event.touches);
15314
+ pinch = pinchStart(range2, scale().width(), x, distance);
15315
+ };
15316
+ const move = (event) => {
15317
+ if (event.touches.length === 1 && pinch === null) panned = true;
15318
+ if (pinch === null || event.touches.length !== 2) return;
15319
+ if (!scalingOpen(deps.chart.options().handleScale)) {
15320
+ pinch = null;
15321
+ return;
15322
+ }
15323
+ const { distance, x } = read(event.touches);
15324
+ const s = scale();
15325
+ const width = s.width();
15326
+ const options = s.options();
15327
+ const plot = { width, minSpacing: options.minBarSpacing, maxSpacing: options.maxBarSpacing > 0 ? options.maxBarSpacing : width / 2 };
15328
+ s.setVisibleLogicalRange(pinchRange(pinch, x, distance, plot));
15329
+ };
15330
+ const end = (event) => {
15331
+ if (event.touches.length === 1) panned = false;
15332
+ if (event.touches.length === 2) begin(event);
15333
+ else pinch = null;
15334
+ };
15335
+ deps.target.addEventListener("touchstart", begin, { passive: true });
15336
+ deps.target.addEventListener("touchmove", move, { passive: true });
15337
+ deps.target.addEventListener("touchend", end, { passive: true });
15338
+ deps.target.addEventListener("touchcancel", end, { passive: true });
15339
+ return {
15340
+ destroy() {
15341
+ pinch = null;
15342
+ deps.target.removeEventListener("touchstart", begin);
15343
+ deps.target.removeEventListener("touchmove", move);
15344
+ deps.target.removeEventListener("touchend", end);
15345
+ deps.target.removeEventListener("touchcancel", end);
15346
+ }
15347
+ };
15360
15348
  }
15361
15349
 
15362
- // src/ui/icons/resolver.ts
15363
- function createIconResolver(deps) {
15364
- checkIcons(deps.icons);
15365
- const icons = deps.icons ?? {};
15366
- const standing = /* @__PURE__ */ new Set();
15367
- const forget = new FinalizationRegistry((record3) => standing.delete(record3));
15368
- const draw = (factory, box, icon) => {
15369
- const direction = deps.direction();
15370
- const drawn = drawHostIcon(factory, { document: deps.document, width: box.width, height: box.height, direction });
15371
- if ("failure" in drawn) {
15372
- deps.diagnostics.report(icon, drawn.failure);
15373
- return null;
15374
- }
15375
- const record3 = { element: new WeakRef(drawn.element), factory, box, icon, direction };
15376
- standing.add(record3);
15377
- forget.register(drawn.element, record3, record3);
15378
- return drawn.element;
15350
+ // src/widget/freePan.ts
15351
+ function attachFreePan(deps) {
15352
+ let landed = null;
15353
+ const onPlot = (clientX, clientY) => {
15354
+ const box = deps.chart.chartElement().getBoundingClientRect();
15355
+ const left = box.left + deps.chart.priceScale("left").width();
15356
+ const right = left + deps.chart.timeScale().width();
15357
+ return clientX >= left && clientX <= right && clientY >= box.top && clientY <= box.bottom - deps.chart.timeScale().height();
15379
15358
  };
15380
- const host2 = (id, box) => {
15381
- const factory = icons[id];
15382
- return factory ? draw(factory, box, id) : null;
15359
+ const release = () => {
15360
+ if (deps.framing()) deps.release();
15383
15361
  };
15384
- const redraw = () => {
15385
- const direction = deps.direction();
15386
- for (const record3 of [...standing]) {
15387
- if (record3.direction === direction) continue;
15388
- const element = record3.element.deref();
15389
- if (!element) {
15390
- standing.delete(record3);
15391
- continue;
15392
- }
15393
- if (!element.parentNode) continue;
15394
- const fresh = draw(record3.factory, record3.box, record3.icon);
15395
- if (!fresh) continue;
15396
- element.replaceWith(fresh);
15397
- standing.delete(record3);
15398
- forget.unregister(record3);
15362
+ const onStart = (event) => {
15363
+ landed = null;
15364
+ if (event.touches.length === 2) {
15365
+ if (scalingOpen(deps.chart.options().handleScale)) release();
15366
+ return;
15399
15367
  }
15368
+ const touch = event.touches[0];
15369
+ if (event.touches.length !== 1 || !touch || !onPlot(touch.clientX, touch.clientY)) return;
15370
+ landed = { x: touch.clientX, y: touch.clientY, at: performance.now() };
15400
15371
  };
15401
- const glyph2 = (mark, options = {}) => {
15402
- const id = iconOf(mark);
15403
- if (id) {
15404
- const width = options.size ?? mark.size ?? 28;
15405
- const drawn = host2(id, { width, height: options.height ?? width });
15406
- if (drawn) {
15407
- const span = deps.document.createElement("span");
15408
- span.className = `qc-icon${options.className ? ` ${options.className}` : ""}`;
15409
- span.setAttribute("aria-hidden", "true");
15410
- span.append(drawn);
15411
- return span;
15412
- }
15372
+ const onMove = (event) => {
15373
+ if (landed === null) return;
15374
+ const touch = event.touches[0];
15375
+ if (event.touches.length !== 1 || !touch) {
15376
+ landed = null;
15377
+ return;
15413
15378
  }
15414
- return glyph(mark, options);
15379
+ if (Math.abs(touch.clientX - landed.x) + Math.abs(touch.clientY - landed.y) < RENDERER_DRAG_START_PX) return;
15380
+ const started = landed;
15381
+ landed = null;
15382
+ if (performance.now() - started.at >= RENDERER_LONG_TAP_MS) return;
15383
+ if (scrollOpen(deps.chart.options().handleScroll)) release();
15415
15384
  };
15416
- const widthFor = (mark, height) => mark.aspect === void 0 ? height : Math.round(height * mark.aspect * 1e3) / 1e3;
15417
- const ownSvg = (mark, width, height) => {
15418
- const holder = deps.document.createElement("span");
15419
- holder.innerHTML = `<svg width="${width}" height="${height}" viewBox="${mark.viewBox}" fill="none" aria-hidden="true">${mark.body}</svg>`;
15420
- return holder.firstElementChild;
15385
+ const onEnd = () => {
15386
+ landed = null;
15421
15387
  };
15422
- const bare = (mark, width, height) => {
15423
- const id = iconOf(mark);
15424
- return (id ? host2(id, { width, height }) : null) ?? ownSvg(mark, width, height);
15388
+ deps.target.addEventListener("touchstart", onStart, { passive: true });
15389
+ deps.target.addEventListener("touchmove", onMove, { passive: true });
15390
+ deps.target.addEventListener("touchend", onEnd, { passive: true });
15391
+ deps.target.addEventListener("touchcancel", onEnd, { passive: true });
15392
+ return {
15393
+ destroy() {
15394
+ landed = null;
15395
+ deps.target.removeEventListener("touchstart", onStart);
15396
+ deps.target.removeEventListener("touchmove", onMove);
15397
+ deps.target.removeEventListener("touchend", onEnd);
15398
+ deps.target.removeEventListener("touchcancel", onEnd);
15399
+ }
15425
15400
  };
15401
+ }
15402
+
15403
+ // src/widget/plotArea.ts
15404
+ function measurePlotArea(chart, host2) {
15405
+ const row2 = chart.panes()[0]?.getHTMLElement();
15406
+ if (!row2) return null;
15407
+ const size = chart.paneSize(0);
15408
+ if (!(size.width > 0) || !(size.height > 0)) return null;
15409
+ const outer = host2.getBoundingClientRect();
15410
+ const top = row2.getBoundingClientRect().top;
15411
+ const left = chart.chartElement().getBoundingClientRect().left + chart.priceScale("left").width();
15412
+ const round = (n) => Math.round(n * 100) / 100;
15426
15413
  return {
15427
- glyph: glyph2,
15428
- icon(name2, requested) {
15429
- const mark = ICONS[name2];
15430
- const height = requested ?? mark.size ?? 28;
15431
- return bare(mark, widthFor(mark, height), height);
15432
- },
15433
- tool(type, size = 28) {
15434
- const mark = toolGlyph(type);
15435
- return mark ? bare(mark, size, size) : null;
15414
+ top: round(top - outer.top),
15415
+ right: round(outer.right - (left + size.width)),
15416
+ bottom: round(outer.bottom - (top + size.height)),
15417
+ left: round(left - outer.left),
15418
+ width: round(size.width),
15419
+ height: round(size.height)
15420
+ };
15421
+ }
15422
+ var sameArea = (a, b) => b !== null && a.top === b.top && a.right === b.right && a.bottom === b.bottom && a.left === b.left && a.width === b.width && a.height === b.height;
15423
+ function watchPlotArea(deps) {
15424
+ let area = null;
15425
+ let frame = null;
15426
+ let destroyed = false;
15427
+ let row2 = null;
15428
+ const resize = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(() => schedule());
15429
+ const measure2 = () => {
15430
+ frame = null;
15431
+ if (destroyed) return;
15432
+ const nextRow = deps.chart.panes()[0]?.getHTMLElement() ?? null;
15433
+ if (nextRow !== row2) {
15434
+ if (row2) resize?.unobserve(row2);
15435
+ if (nextRow) resize?.observe(nextRow);
15436
+ row2 = nextRow;
15437
+ }
15438
+ const next = measurePlotArea(deps.chart, deps.host);
15439
+ if (next === null || sameArea(next, area)) return;
15440
+ area = next;
15441
+ deps.changed(next);
15442
+ };
15443
+ function schedule() {
15444
+ if (destroyed || frame !== null) return;
15445
+ if (typeof requestAnimationFrame !== "function") {
15446
+ measure2();
15447
+ return;
15448
+ }
15449
+ frame = requestAnimationFrame(measure2);
15450
+ }
15451
+ deps.chart.timeScale().subscribeSizeChange(schedule);
15452
+ resize?.observe(deps.host);
15453
+ resize?.observe(deps.chart.chartElement());
15454
+ schedule();
15455
+ return {
15456
+ current() {
15457
+ if (destroyed) return null;
15458
+ return area ?? measurePlotArea(deps.chart, deps.host);
15436
15459
  },
15437
- host: host2,
15438
- draw,
15439
- redraw
15460
+ destroy() {
15461
+ if (destroyed) return;
15462
+ destroyed = true;
15463
+ if (frame !== null && typeof cancelAnimationFrame === "function") cancelAnimationFrame(frame);
15464
+ frame = null;
15465
+ resize?.disconnect();
15466
+ try {
15467
+ deps.chart.timeScale().unsubscribeSizeChange(schedule);
15468
+ } catch {
15469
+ }
15470
+ }
15440
15471
  };
15441
15472
  }
15442
15473
 
15474
+ // src/contextMenu.ts
15475
+ function chartContextMenuGroups(c) {
15476
+ const t = c.t ?? englishChartStrings();
15477
+ const clipboard2 = [{ kind: "item", id: "copy-price", label: t("menu.copyPrice", { price: c.priceText }) }];
15478
+ if (c.canPaste !== false) clipboard2.push({ kind: "item", id: "paste", label: t("menu.paste"), shortcut: t("drawing.hintPaste", { modifier: t(isApplePlatform() ? "drawing.modifierCommand" : "drawing.modifierControl") }) });
15479
+ const remove = [];
15480
+ if (c.indicatorCount > 0) remove.push({ kind: "item", id: "remove-indicators", label: t("menu.removeIndicators", { count: c.indicatorCount }) });
15481
+ if (c.drawingCount > 0) remove.push({ kind: "item", id: "remove-drawings", label: t("menu.removeDrawings", { count: c.drawingCount }) });
15482
+ return [
15483
+ { slot: "view", rows: [{ kind: "item", id: "reset-view", label: t("menu.resetView"), shortcut: "Alt + R", icon: "reset" }] },
15484
+ { slot: "clipboard", rows: clipboard2 },
15485
+ { slot: "remove", rows: remove },
15486
+ { slot: "settings", rows: c.canSettings !== false ? [{ kind: "item", id: "settings", label: t("menu.settings"), icon: "settings" }] : [] }
15487
+ ];
15488
+ }
15489
+ function flattenMenuGroups(groups) {
15490
+ const rows2 = [];
15491
+ for (const g of groups.filter((g2) => g2.length > 0)) {
15492
+ if (rows2.length) rows2.push({ kind: "separator" });
15493
+ rows2.push(...g);
15494
+ }
15495
+ return rows2;
15496
+ }
15497
+ function chartContextMenu(c) {
15498
+ return flattenMenuGroups(chartContextMenuGroups(c).map((g) => g.rows));
15499
+ }
15500
+
15443
15501
  // src/contextMenuUi.ts
15444
15502
  var MENU_W = 327;
15445
15503
  var ICONS2 = {
@@ -19660,7 +19718,7 @@ function openIndicatorSettings(deps) {
19660
19718
  const overrides = cloneOverrides(instance.overrides);
19661
19719
  let hidden = chart.indicators.hidden().includes(instance.id);
19662
19720
  const inputs2 = manifest2.inputs ?? {};
19663
- const fields = buildInputFields(inputs2, { ...manifestInputDefaults(manifest2), ...instance.inputs }, builtIn.inputTitles);
19721
+ const fields = buildInputFields(deps.icons, inputs2, { ...manifestInputDefaults(manifest2), ...instance.inputs }, builtIn.inputTitles);
19664
19722
  const tabs = [...Object.keys(inputs2).length > 0 ? [{ id: "inputs", label: t("settings.tabInputs") }] : [], { id: "style", label: t("settings.tabStyle") }, { id: "visibility", label: t("settings.tabVisibility") }];
19665
19723
  let tab = tabs[0].id;
19666
19724
  const plotOverride = (key) => (overrides.plots ??= {})[key] ??= {};
@@ -19687,7 +19745,7 @@ function openIndicatorSettings(deps) {
19687
19745
  const el2 = h("select", { class: "qc-field", "aria-label": label2 });
19688
19746
  for (const o of options) el2.appendChild(h("option", { value: o.value, selected: o.value === current }, o.text));
19689
19747
  el2.addEventListener("change", () => onChange(el2.value));
19690
- return el2;
19748
+ return selectField(el2, deps.icons);
19691
19749
  };
19692
19750
  const lineStyleOptions = () => [
19693
19751
  { value: "solid", text: t("settings.lineStyleSolid") },
@@ -20294,7 +20352,12 @@ function buildSearchSurface(deps, box, frame) {
20294
20352
  const chart = request.chart ?? null;
20295
20353
  const scope = chart ? chart.id : `pick-${picks += 1}`;
20296
20354
  const listId = `qc-search-${scope}-list`;
20297
- const search2 = deps.search.controller;
20355
+ const searchScope = compare || mode === "change-symbol" ? null : deps.scope?.() ?? null;
20356
+ const feedSession = deps.search;
20357
+ const scopeSession = searchScope ? feedSession.over(searchScope) : null;
20358
+ let scoped = scopeSession !== null && searchScope?.on !== false;
20359
+ const session2 = () => scoped && scopeSession ? scopeSession : feedSession;
20360
+ const search2 = () => session2().controller;
20298
20361
  if (mode === "search" || mode === "pick") box.classList.add("qc-search-table");
20299
20362
  let query = request.changeFrom ?? "";
20300
20363
  const display = deps.display ?? {};
@@ -20363,7 +20426,7 @@ function buildSearchSurface(deps, box, frame) {
20363
20426
  for (const { row: row2, top } of narrower) row2.hidden = !selection.has(top);
20364
20427
  cls = selection.filter();
20365
20428
  active = -1;
20366
- search2.search(serverQuery(), cls);
20429
+ search2().search(serverQuery(), cls);
20367
20430
  render();
20368
20431
  };
20369
20432
  const classChip = (label2, pressed, pick) => {
@@ -20371,18 +20434,31 @@ function buildSearchSurface(deps, box, frame) {
20371
20434
  chips.push({ chip, pressed });
20372
20435
  return chip;
20373
20436
  };
20374
- const searchScope = deps.scope?.() ?? null;
20437
+ let scopeChip = null;
20438
+ const setScoped = (on) => {
20439
+ if (on === scoped) return;
20440
+ session2().cancelPending();
20441
+ scoped = on;
20442
+ scopeChip?.setAttribute("aria-pressed", String(on));
20443
+ active = -1;
20444
+ search2().search(serverQuery(), cls);
20445
+ render();
20446
+ };
20375
20447
  if (branches.length > 0 || searchScope) {
20376
- strip = h("div", { class: "qc-search-classes", role: "group", "aria-label": t("search.classFilter") });
20377
- if (allShown && branches.length > 0) strip.appendChild(classChip(allLabel, () => selection.isAll(), () => selection.clear()));
20378
- for (const branch of branches) {
20379
- strip.appendChild(classChip(labelOf(branch.id), () => selection.has(branch.id), () => selection.pickTop(branch.id)));
20380
- if (branch.children.length === 0) continue;
20381
- const row2 = h("div", { class: "qc-search-classes qc-search-subclasses", role: "group", "aria-label": labelOf(branch.id) });
20382
- row2.appendChild(classChip(allLabel, () => selection.has(branch.id) && !selection.narrowed(branch.id), () => selection.clearChildren(branch.id)));
20383
- for (const child of branch.children) row2.appendChild(classChip(labelOf(child), () => selection.hasChild(branch.id, child), () => selection.pickChild(branch.id, child)));
20384
- row2.hidden = !selection.has(branch.id);
20385
- narrower.push({ row: row2, top: branch.id });
20448
+ strip = h("div", { class: "qc-search-classes" });
20449
+ if (branches.length > 0) {
20450
+ const group = h("div", { class: "qc-search-class-group", role: "group", "aria-label": t("search.classFilter") });
20451
+ if (allShown) group.appendChild(classChip(allLabel, () => selection.isAll(), () => selection.clear()));
20452
+ for (const branch of branches) {
20453
+ group.appendChild(classChip(labelOf(branch.id), () => selection.has(branch.id), () => selection.pickTop(branch.id)));
20454
+ if (branch.children.length === 0) continue;
20455
+ const row2 = h("div", { class: "qc-search-classes qc-search-subclasses", role: "group", "aria-label": labelOf(branch.id) });
20456
+ row2.appendChild(classChip(allLabel, () => selection.has(branch.id) && !selection.narrowed(branch.id), () => selection.clearChildren(branch.id)));
20457
+ for (const child of branch.children) row2.appendChild(classChip(labelOf(child), () => selection.hasChild(branch.id, child), () => selection.pickChild(branch.id, child)));
20458
+ row2.hidden = !selection.has(branch.id);
20459
+ narrower.push({ row: row2, top: branch.id });
20460
+ }
20461
+ strip.appendChild(group);
20386
20462
  }
20387
20463
  if (searchScope) {
20388
20464
  const mark = h("span", { class: "qc-search-scope-mark", "aria-hidden": "true" });
@@ -20391,7 +20467,8 @@ function buildSearchSurface(deps, box, frame) {
20391
20467
  mark.dataset.qcHost = "true";
20392
20468
  scopeMarkDisposer = drop;
20393
20469
  } else if (mark.childNodes.length === 0) mark.textContent = searchScope.label.charAt(0).toUpperCase();
20394
- strip.appendChild(h("span", { class: "qc-search-scope", "aria-label": searchScope.label }, mark, h("span", {}, searchScope.label)));
20470
+ scopeChip = button2({ label: t("search.limitToScope", { scope: searchScope.label }), text: searchScope.label, icon: mark, className: "qc-chip qc-search-scope", pressed: scoped, onClick: () => setScoped(!scoped) });
20471
+ strip.appendChild(scopeChip);
20395
20472
  }
20396
20473
  }
20397
20474
  const list = h("div", { class: "qc-search-list", role: "listbox", id: listId, "aria-label": t("search.results") });
@@ -20405,11 +20482,16 @@ function buildSearchSurface(deps, box, frame) {
20405
20482
  input.value = next;
20406
20483
  showClear(next !== "");
20407
20484
  active = -1;
20408
- if (compare && next.trim() === "") deps.search.cancelPending();
20409
- else search2.search(serverQuery(), cls);
20485
+ if (compare && next.trim() === "") session2().cancelPending();
20486
+ else search2().search(serverQuery(), cls);
20410
20487
  render();
20411
20488
  };
20412
- const remember = (row2) => deps.recents.promote(row2);
20489
+ const recentRows = () => scoped ? searchScope?.recents?.list() ?? [] : deps.recents.list();
20490
+ const remember = (row2) => {
20491
+ deps.recents.promote(row2);
20492
+ const own = scoped ? searchScope?.recents : void 0;
20493
+ if (own && own !== deps.recents) own.promote(row2);
20494
+ };
20413
20495
  const act = (entry, placement = "same-percent") => {
20414
20496
  const row2 = entry.row;
20415
20497
  if (compare) {
@@ -20439,9 +20521,9 @@ function buildSearchSurface(deps, box, frame) {
20439
20521
  };
20440
20522
  const render = () => {
20441
20523
  releaseMarks();
20442
- const state = search2.state();
20524
+ const state = search2().state();
20443
20525
  const settled = state.query.trim() === serverQuery().trim();
20444
- rows2 = dialogRows({ mode, query, hits: settled ? state.hits : [], loading: state.loading || !settled, recents: deps.recents.list(), curated: deps.curated ?? [], added: chart?.compare.list() ?? [], spreads });
20526
+ rows2 = dialogRows({ mode, query, hits: settled ? state.hits : [], loading: state.loading || !settled, recents: recentRows(), curated: deps.curated ?? [], added: chart?.compare.list() ?? [], spreads });
20445
20527
  active = Math.min(active, rows2.length - 1);
20446
20528
  const emptyStack = compare && query.trim() === "";
20447
20529
  const addedCount = emptyStack ? chart?.compare.list().length ?? 0 : 0;
@@ -20541,7 +20623,7 @@ function buildSearchSurface(deps, box, frame) {
20541
20623
  if (e.key === "ArrowDown") {
20542
20624
  e.preventDefault();
20543
20625
  if (rows2.length === 0) return;
20544
- if (search2.state().hasMore && active >= rows2.length - PREFETCH_MARGIN) search2.loadMore();
20626
+ if (search2().state().hasMore && active >= rows2.length - PREFETCH_MARGIN) search2().loadMore();
20545
20627
  setActive(Math.min(active + 1, rows2.length - 1));
20546
20628
  } else if (e.key === "ArrowUp") {
20547
20629
  e.preventDefault();
@@ -20552,10 +20634,15 @@ function buildSearchSurface(deps, box, frame) {
20552
20634
  if (entry) act(entry);
20553
20635
  }
20554
20636
  });
20555
- observer = typeof IntersectionObserver === "function" ? new IntersectionObserver((entries) => entries.some((en2) => en2.isIntersecting) && search2.loadMore(), { root: list }) : null;
20556
- search2.subscribe(render);
20637
+ observer = typeof IntersectionObserver === "function" ? new IntersectionObserver((entries) => entries.some((en2) => en2.isIntersecting) && search2().loadMore(), { root: list }) : null;
20638
+ for (const own of [feedSession, scopeSession]) own?.controller.subscribe(() => {
20639
+ if (session2() === own) render();
20640
+ });
20557
20641
  render();
20558
- if (!compare || query.trim() !== "") search2.search(serverQuery(), cls);
20642
+ if (!compare || query.trim() !== "") {
20643
+ if (scoped) session2().searchNow(serverQuery(), cls);
20644
+ else search2().search(serverQuery(), cls);
20645
+ }
20559
20646
  if (request.changeFrom) input.select();
20560
20647
  setDisabled(clear, false);
20561
20648
  return {
@@ -20563,7 +20650,8 @@ function buildSearchSurface(deps, box, frame) {
20563
20650
  scopeMarkDisposer?.();
20564
20651
  scopeMarkDisposer = null;
20565
20652
  releaseMarks();
20566
- search2.dispose();
20653
+ feedSession.controller.dispose();
20654
+ scopeSession?.controller.dispose();
20567
20655
  observer?.disconnect();
20568
20656
  }
20569
20657
  };