@trdrs/quickcharts 4.0.0 → 4.1.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 (76) hide show
  1. package/CHANGELOG.md +16 -0
  2. package/README.md +49 -20
  3. package/dist/adapters/rest.d.ts +1 -1
  4. package/dist/{ar-FXZ5QJUR.js → ar-VILLYPAA.js} +4 -1
  5. package/dist/ar-VILLYPAA.js.map +1 -0
  6. package/dist/{assets-Gg-UquDA.d.ts → assets-BF-NDyHl.d.ts} +7 -2
  7. package/dist/{ca_ES-3WVKFBIF.js → ca_ES-EJXLAXOA.js} +4 -1
  8. package/dist/ca_ES-EJXLAXOA.js.map +1 -0
  9. package/dist/{chunk-C4MEVUNK.js → chunk-TBOVLJAK.js} +908 -266
  10. package/dist/chunk-TBOVLJAK.js.map +1 -0
  11. package/dist/{de-V72Q3OI7.js → de-PHID4SVN.js} +4 -1
  12. package/dist/de-PHID4SVN.js.map +1 -0
  13. package/dist/drawings.d.ts +18 -7
  14. package/dist/drawings.js +7 -1
  15. package/dist/{es-CNQ3OJ6E.js → es-KD4FBLOP.js} +4 -1
  16. package/dist/es-KD4FBLOP.js.map +1 -0
  17. package/dist/feature-manifest.json +1 -1
  18. package/dist/{fr-5WQBCGR4.js → fr-KTTX3FF3.js} +4 -1
  19. package/dist/fr-KTTX3FF3.js.map +1 -0
  20. package/dist/{he_IL-WXKA77UE.js → he_IL-Z3DXMAKZ.js} +4 -1
  21. package/dist/he_IL-Z3DXMAKZ.js.map +1 -0
  22. package/dist/{id_ID-XPBAYSWK.js → id_ID-FFX6X4C5.js} +4 -1
  23. package/dist/id_ID-FFX6X4C5.js.map +1 -0
  24. package/dist/index.d.ts +94 -77
  25. package/dist/index.js +180 -84
  26. package/dist/index.js.map +1 -1
  27. package/dist/{it-DR2EBNWX.js → it-X2GFCLGU.js} +4 -1
  28. package/dist/it-X2GFCLGU.js.map +1 -0
  29. package/dist/{ja-URB2CPXO.js → ja-TG3WO2KH.js} +4 -1
  30. package/dist/ja-TG3WO2KH.js.map +1 -0
  31. package/dist/{ko-OE47NYVP.js → ko-4HHHO7KV.js} +4 -1
  32. package/dist/ko-4HHHO7KV.js.map +1 -0
  33. package/dist/{ms_MY-BKCFRK2K.js → ms_MY-HPVQKVPY.js} +4 -1
  34. package/dist/ms_MY-HPVQKVPY.js.map +1 -0
  35. package/dist/{pl-3IKQRG3Y.js → pl-2W2HP34O.js} +4 -1
  36. package/dist/pl-2W2HP34O.js.map +1 -0
  37. package/dist/{pt-PZHV5EZE.js → pt-XQUBSXO7.js} +4 -1
  38. package/dist/pt-XQUBSXO7.js.map +1 -0
  39. package/dist/quickcharts.css +41 -10
  40. package/dist/{resources-Le6flcEn.d.ts → resources-C0cYryO9.d.ts} +1 -1
  41. package/dist/{ru-BAL6RQUV.js → ru-XKFQPFDM.js} +4 -1
  42. package/dist/ru-XKFQPFDM.js.map +1 -0
  43. package/dist/{sv-Y6GBGDHM.js → sv-ZMEGAPCR.js} +4 -1
  44. package/dist/sv-ZMEGAPCR.js.map +1 -0
  45. package/dist/{th-MAMLMZKU.js → th-4735BUT4.js} +4 -1
  46. package/dist/th-4735BUT4.js.map +1 -0
  47. package/dist/{tr-3LQHINUZ.js → tr-PG3CW2L3.js} +4 -1
  48. package/dist/tr-PG3CW2L3.js.map +1 -0
  49. package/dist/{vi-GR4PSDKP.js → vi-YPRIAJ33.js} +4 -1
  50. package/dist/vi-YPRIAJ33.js.map +1 -0
  51. package/dist/{zh-2RJ5VNAI.js → zh-RVHEWNSW.js} +4 -1
  52. package/dist/zh-RVHEWNSW.js.map +1 -0
  53. package/dist/{zh_TW-XEBSACHU.js → zh_TW-ZFJMDA64.js} +4 -1
  54. package/dist/zh_TW-ZFJMDA64.js.map +1 -0
  55. package/package.json +1 -1
  56. package/dist/ar-FXZ5QJUR.js.map +0 -1
  57. package/dist/ca_ES-3WVKFBIF.js.map +0 -1
  58. package/dist/chunk-C4MEVUNK.js.map +0 -1
  59. package/dist/de-V72Q3OI7.js.map +0 -1
  60. package/dist/es-CNQ3OJ6E.js.map +0 -1
  61. package/dist/fr-5WQBCGR4.js.map +0 -1
  62. package/dist/he_IL-WXKA77UE.js.map +0 -1
  63. package/dist/id_ID-XPBAYSWK.js.map +0 -1
  64. package/dist/it-DR2EBNWX.js.map +0 -1
  65. package/dist/ja-URB2CPXO.js.map +0 -1
  66. package/dist/ko-OE47NYVP.js.map +0 -1
  67. package/dist/ms_MY-BKCFRK2K.js.map +0 -1
  68. package/dist/pl-3IKQRG3Y.js.map +0 -1
  69. package/dist/pt-PZHV5EZE.js.map +0 -1
  70. package/dist/ru-BAL6RQUV.js.map +0 -1
  71. package/dist/sv-Y6GBGDHM.js.map +0 -1
  72. package/dist/th-MAMLMZKU.js.map +0 -1
  73. package/dist/tr-3LQHINUZ.js.map +0 -1
  74. package/dist/vi-GR4PSDKP.js.map +0 -1
  75. package/dist/zh-2RJ5VNAI.js.map +0 -1
  76. package/dist/zh_TW-XEBSACHU.js.map +0 -1
package/dist/index.js CHANGED
@@ -106,7 +106,7 @@ import {
106
106
  withRow,
107
107
  withoutColumn,
108
108
  withoutRow
109
- } from "./chunk-C4MEVUNK.js";
109
+ } from "./chunk-TBOVLJAK.js";
110
110
  import {
111
111
  ResourceAbortError,
112
112
  memorySaveLoadAdapter
@@ -1611,26 +1611,26 @@ function readingDirection(i18n) {
1611
1611
  return BUILT_IN_LOCALES.find((l) => l.code === i18n.locale())?.dir ?? "ltr";
1612
1612
  }
1613
1613
  var chartDictionaries = createDictionaryLoader(en, {
1614
- de: () => import("./de-V72Q3OI7.js"),
1615
- fr: () => import("./fr-5WQBCGR4.js"),
1616
- es: () => import("./es-CNQ3OJ6E.js"),
1617
- it: () => import("./it-DR2EBNWX.js"),
1618
- ca_ES: () => import("./ca_ES-3WVKFBIF.js"),
1619
- pl: () => import("./pl-3IKQRG3Y.js"),
1620
- sv: () => import("./sv-Y6GBGDHM.js"),
1621
- tr: () => import("./tr-3LQHINUZ.js"),
1622
- ru: () => import("./ru-BAL6RQUV.js"),
1623
- pt: () => import("./pt-PZHV5EZE.js"),
1624
- id_ID: () => import("./id_ID-XPBAYSWK.js"),
1625
- ms_MY: () => import("./ms_MY-BKCFRK2K.js"),
1626
- th: () => import("./th-MAMLMZKU.js"),
1627
- vi: () => import("./vi-GR4PSDKP.js"),
1628
- ja: () => import("./ja-URB2CPXO.js"),
1629
- ko: () => import("./ko-OE47NYVP.js"),
1630
- zh: () => import("./zh-2RJ5VNAI.js"),
1631
- zh_TW: () => import("./zh_TW-XEBSACHU.js"),
1632
- ar: () => import("./ar-FXZ5QJUR.js"),
1633
- he_IL: () => import("./he_IL-WXKA77UE.js")
1614
+ de: () => import("./de-PHID4SVN.js"),
1615
+ fr: () => import("./fr-KTTX3FF3.js"),
1616
+ es: () => import("./es-KD4FBLOP.js"),
1617
+ it: () => import("./it-X2GFCLGU.js"),
1618
+ ca_ES: () => import("./ca_ES-EJXLAXOA.js"),
1619
+ pl: () => import("./pl-2W2HP34O.js"),
1620
+ sv: () => import("./sv-ZMEGAPCR.js"),
1621
+ tr: () => import("./tr-PG3CW2L3.js"),
1622
+ ru: () => import("./ru-XKFQPFDM.js"),
1623
+ pt: () => import("./pt-XQUBSXO7.js"),
1624
+ id_ID: () => import("./id_ID-FFX6X4C5.js"),
1625
+ ms_MY: () => import("./ms_MY-HPVQKVPY.js"),
1626
+ th: () => import("./th-4735BUT4.js"),
1627
+ vi: () => import("./vi-YPRIAJ33.js"),
1628
+ ja: () => import("./ja-TG3WO2KH.js"),
1629
+ ko: () => import("./ko-4HHHO7KV.js"),
1630
+ zh: () => import("./zh-RVHEWNSW.js"),
1631
+ zh_TW: () => import("./zh_TW-ZFJMDA64.js"),
1632
+ ar: () => import("./ar-VILLYPAA.js"),
1633
+ he_IL: () => import("./he_IL-Z3DXMAKZ.js")
1634
1634
  });
1635
1635
  var dynamic = (t) => t;
1636
1636
  var source = null;
@@ -1646,7 +1646,8 @@ function arrangementName(t, code, fallback) {
1646
1646
  function inventory(custom) {
1647
1647
  if (custom.length === 0) return { registry: BUILT_IN_LOCALE_REGISTRY, dictionaries: chartDictionaries };
1648
1648
  const registry = createLocaleRegistry([...BUILT_IN_LOCALES, ...custom], DEFAULT_LOCALE);
1649
- const own = createDictionaryLoader(en, Object.fromEntries(custom.map((l) => [l.code, l.dictionary])), DEFAULT_LOCALE);
1649
+ const asTranslation = (load) => load;
1650
+ const own = createDictionaryLoader(en, Object.fromEntries(custom.map((l) => [l.code, asTranslation(l.dictionary)])), DEFAULT_LOCALE);
1650
1651
  return {
1651
1652
  registry,
1652
1653
  dictionaries: {
@@ -6217,6 +6218,15 @@ function bindGestures(ctx) {
6217
6218
  }
6218
6219
  const hit = hitAt(p);
6219
6220
  if (hit) {
6221
+ const showsHandles = hit.handlesOnHover?.() === true;
6222
+ if (showsHandles && hit.id !== sel?.id && !e.ctrlKey && !e.metaKey && !editRefused("resize", hit.options, false)) {
6223
+ const ai = anchorHit(hit, p);
6224
+ if (ai !== null) {
6225
+ manager.select(hit.id);
6226
+ startDrag("anchor", hit, ai, p);
6227
+ return;
6228
+ }
6229
+ }
6220
6230
  if ((e.ctrlKey || e.metaKey) && !editRefused("cloneDrag", hit.options, false) && ctx.copies(hit.type)) {
6221
6231
  const copy = drawingTools.restore({ ...hit.toJSON(), id: ctx.nextId() });
6222
6232
  if (copy) {
@@ -6277,7 +6287,7 @@ function bindGestures(ctx) {
6277
6287
  return;
6278
6288
  }
6279
6289
  manager.add(drawing2);
6280
- if (required > 1 && inlineTextRules(drawing2)) drawing2.setState("editing");
6290
+ if (required > 1 && (inlineTextRules(drawing2) || toolRegistry.get(drawing2.type)?.category === "lines")) drawing2.setState("editing");
6281
6291
  ctx.draft = { drawing: drawing2, required, placed: 1, downX: p.x, downY: p.y, pendingDrag: true, hasText: !!def.hasText, mode, lastX: p.x, lastY: p.y };
6282
6292
  showPoint(anchor);
6283
6293
  if (mode === "fixed" && required === 1) completePlacement(ctx.draft, p);
@@ -6483,7 +6493,9 @@ function bindGestures(ctx) {
6483
6493
  if (hit && settingsOnDoubleClick(hit)) {
6484
6494
  ctx.endTextEdit();
6485
6495
  manager.select(hit.id);
6486
- ctx.openSettings();
6496
+ const vp = viewport();
6497
+ const cursor = vp ? hit.cursorFor?.(p, vp) : null;
6498
+ ctx.openSettings(cursor === "text" ? "Text" : void 0);
6487
6499
  return;
6488
6500
  }
6489
6501
  if (ctx.textEditOpen()) return;
@@ -6784,7 +6796,7 @@ function attachDrawings(options) {
6784
6796
  doubleClick: () => {
6785
6797
  if (textEdit !== session2 || openedBy !== "click" || !settingsOnDoubleClick(drawing2)) return false;
6786
6798
  commitTextEdit(drawing2.textDraft?.value ?? value);
6787
- openSettings();
6799
+ openSettings("Text");
6788
6800
  return true;
6789
6801
  },
6790
6802
  tab: (backward) => {
@@ -6804,8 +6816,9 @@ function attachDrawings(options) {
6804
6816
  }, 0);
6805
6817
  pendingEdit = { drawing: drawing2, timer };
6806
6818
  };
6807
- const openSettings = () => {
6808
- options.execute?.(SETTINGS_COMMAND);
6819
+ const openSettings = (page) => {
6820
+ if (page) options.execute?.(SETTINGS_COMMAND, page);
6821
+ else options.execute?.(SETTINGS_COMMAND);
6809
6822
  };
6810
6823
  const commitInline = (session2, value) => {
6811
6824
  const drawing2 = manager.get(session2.id);
@@ -9728,10 +9741,16 @@ var BAR_LAYOUTS = {
9728
9741
  arrow_up: ["line", "text"],
9729
9742
  arrow_down: ["line", "text"]
9730
9743
  };
9744
+ var NO_WORDS_INK = /* @__PURE__ */ new Set(["trend_angle"]);
9731
9745
  function widthBar(icons, width) {
9732
9746
  const h2 = Math.max(1, Math.min(4, Math.round(width)));
9733
9747
  return el("span", { class: "qc-drawing-width-bar", "aria-hidden": "true" }, icons.icon(THICKNESS_ICONS[h2]));
9734
9748
  }
9749
+ function pointAnchor(clientX, clientY) {
9750
+ const anchor = el("span", { "aria-hidden": "true" });
9751
+ anchor.getBoundingClientRect = () => new DOMRect(clientX, clientY, 0, 0);
9752
+ return anchor;
9753
+ }
9735
9754
  function mountSettingsBar(deps) {
9736
9755
  const { t } = deps;
9737
9756
  const shown2 = (command2) => deps.shown?.(command2) ?? true;
@@ -9869,7 +9888,37 @@ function mountSettingsBar(deps) {
9869
9888
  return face;
9870
9889
  };
9871
9890
  const modifier = () => t(isApplePlatform() ? "drawing.modifierCommand" : "drawing.modifierControl");
9872
- const moreMenu = () => {
9891
+ const templateItems = (type) => {
9892
+ const saved = deps.presets.templatesFor(type);
9893
+ const items2 = [
9894
+ menuRow(t("drawing.saveTemplateAs"), () => openTemplateNameDialog({ container: deps.chrome, t, icons: deps.icons }, (name2) => deps.run("chart.drawings.template.save", name2)), { command: "chart.drawings.template.save" }),
9895
+ menuRow(t("drawing.applyDefaultTemplate"), () => deps.run("chart.drawings.template.apply", null), { command: "chart.drawings.template.apply" })
9896
+ ];
9897
+ if (saved.length) items2.push(separator2());
9898
+ for (const template of saved) {
9899
+ const rowEl = el("div", { class: "qc-drawing-flyout-row" });
9900
+ rowEl.append(
9901
+ menuRow(template.name, () => deps.run("chart.drawings.template.apply", template.name), { command: "chart.drawings.template.apply" }),
9902
+ button({
9903
+ class: "qc-drawing-star",
9904
+ label: t("drawing.removeTemplateNamed", { name: template.name }),
9905
+ title: t("drawing.remove"),
9906
+ icon: deps.icons.icon("trash", 18),
9907
+ disabled: !deps.available("chart.drawings.template.remove"),
9908
+ onClick: () => {
9909
+ closeOpen();
9910
+ openTemplateDeleteDialog({ container: deps.chrome, t, icons: deps.icons }, template.name, () => deps.run("chart.drawings.template.remove", template.name));
9911
+ }
9912
+ })
9913
+ );
9914
+ const remove = rowEl.querySelector(".qc-drawing-star");
9915
+ if (remove) remove.hidden = !shown2("chart.drawings.template.remove");
9916
+ rowEl.hidden = !shown2("chart.drawings.template.apply");
9917
+ items2.push(rowEl);
9918
+ }
9919
+ return items2;
9920
+ };
9921
+ const drawingMenu = (kind, selected, extra = []) => {
9873
9922
  let sub = null;
9874
9923
  let timer = null;
9875
9924
  const cancelClose = () => {
@@ -9885,34 +9934,35 @@ function mountSettingsBar(deps) {
9885
9934
  cancelClose();
9886
9935
  timer = setTimeout(closeSub, SUBMENU_GRACE_MS);
9887
9936
  };
9888
- const submenuOf = (kind) => {
9889
- if (kind === "order") {
9937
+ const submenuOf = (kind2) => {
9938
+ if (kind2 === "template") return menuOf(t("drawing.drawingTemplates"), "wide", ...templateItems(selected.type));
9939
+ if (kind2 === "order") {
9890
9940
  const at2 = deps.stackPosition();
9891
9941
  return menuOf(t("drawing.visualOrder"), "narrow", ...ORDER_MOVES.map((move) => menuRow(t(move.label), () => deps.run(move.command), { disabled: move.dead(at2), command: move.command })));
9892
9942
  }
9893
9943
  return menuOf(t("drawing.visibilityOnTimeframes"), "wide", ...VISIBILITY_PRESETS.map((v) => menuRow(t(v.label), () => deps.run("chart.drawings.visibility", v.preset), { command: "chart.drawings.visibility" })));
9894
9944
  };
9895
- const arm = (kind, row2) => {
9945
+ const arm = (kind2, row2) => {
9896
9946
  cancelClose();
9897
- if (sub?.kind === kind) return;
9947
+ if (sub?.kind === kind2) return;
9898
9948
  sub?.close();
9899
9949
  sub = null;
9900
- if (!kind || !row2) return;
9901
- const panel = submenuOf(kind);
9950
+ if (!kind2 || !row2) return;
9951
+ const panel = submenuOf(kind2);
9902
9952
  panel.addEventListener("mouseenter", cancelClose);
9903
9953
  panel.addEventListener("mouseleave", scheduleClose);
9904
9954
  const close = openPopover(deps.chrome, row2, panel, "sidecar", () => {
9905
9955
  if (sub?.close === close) sub = null;
9906
9956
  });
9907
- sub = { kind, close };
9957
+ sub = { kind: kind2, close };
9908
9958
  };
9909
- const submenuRow = (kind, label3, icon) => {
9959
+ const submenuRow = (kind2, label3, icon) => {
9910
9960
  const row2 = menuRow(label3, () => void 0, { ...icon ? { icon: deps.icons.icon(icon) } : { spacer: true }, submenu: true });
9911
9961
  row2.setAttribute("aria-haspopup", "menu");
9912
- row2.addEventListener("mouseenter", () => arm(kind, row2));
9962
+ row2.addEventListener("mouseenter", () => arm(kind2, row2));
9913
9963
  row2.addEventListener("mouseleave", scheduleClose);
9914
- row2.addEventListener("click", () => arm(kind, row2));
9915
- const commands = kind === "order" ? ORDER_MOVES.map((move) => move.command) : ["chart.drawings.visibility"];
9964
+ row2.addEventListener("click", () => arm(kind2, row2));
9965
+ const commands = kind2 === "order" ? ORDER_MOVES.map((move) => move.command) : kind2 === "template" ? ["chart.drawings.template.apply", "chart.drawings.template.save"] : ["chart.drawings.visibility"];
9916
9966
  if (!commands.some(shown2)) row2.hidden = true;
9917
9967
  return row2;
9918
9968
  };
@@ -9920,16 +9970,51 @@ function mountSettingsBar(deps) {
9920
9970
  b.addEventListener("mouseenter", () => arm(null));
9921
9971
  return b;
9922
9972
  };
9973
+ const order = submenuRow("order", t("drawing.visualOrder"), "layers");
9974
+ const visibility = submenuRow("visibility", t("drawing.visibilityOnTimeframes"));
9975
+ const clone = plain(menuRow(t("drawing.clone"), () => deps.run("chart.drawings.clone"), { icon: deps.icons.icon("clone"), hint: t("drawing.hintClone", { modifier: modifier() }), command: "chart.drawings.clone" }));
9976
+ const copy = plain(menuRow(t("drawing.copy"), () => deps.run("chart.drawings.copy"), { spacer: true, hint: t("drawing.hintCopy", { modifier: modifier() }), command: "chart.drawings.copy" }));
9977
+ const hide = plain(menuRow(t("drawing.hide"), () => deps.run("chart.drawings.hideSelected"), { icon: deps.icons.icon("eyeCrossed"), command: "chart.drawings.hideSelected" }));
9978
+ if (kind === "more") return { element: menuOf(t("drawing.moreActions"), "wide", order, visibility, separator2(), clone, copy, separator2(), hide), closeSub };
9979
+ const table = [];
9980
+ if (selected.hasCells) {
9981
+ table.push(
9982
+ plain(menuRow(t("drawing.addColumnRight"), () => deps.run("chart.drawings.tableAddColumn"), { icon: deps.icons.icon("tableAddColumn"), command: "chart.drawings.tableAddColumn" })),
9983
+ plain(menuRow(t("drawing.addRowBelow"), () => deps.run("chart.drawings.tableAddRow"), { icon: deps.icons.icon("tableAddRow"), command: "chart.drawings.tableAddRow" }))
9984
+ );
9985
+ if (deps.tableCell?.()) {
9986
+ table.push(
9987
+ separator2(),
9988
+ plain(menuRow(t("drawing.removeRow"), () => deps.run("chart.drawings.tableRemoveRow"), { icon: deps.icons.icon("trash28"), command: "chart.drawings.tableRemoveRow" })),
9989
+ plain(menuRow(t("drawing.removeColumn"), () => deps.run("chart.drawings.tableRemoveColumn"), { icon: deps.icons.icon("trash28"), command: "chart.drawings.tableRemoveColumn" }))
9990
+ );
9991
+ }
9992
+ table.push(separator2());
9993
+ }
9994
+ const contributed = (row2) => {
9995
+ const glyph2 = row2.checked ? deps.icons.icon("check") : buildGlyph(row2.icon);
9996
+ return plain(menuRow(row2.label, () => row2.run(), { ...glyph2 ? { icon: glyph2 } : { spacer: true }, ...row2.shortcut ? { hint: row2.shortcut } : {} }));
9997
+ };
9998
+ const level = extra.filter((row2) => row2.group !== "view").map(contributed);
9999
+ const view = extra.filter((row2) => row2.group === "view").map(contributed);
9923
10000
  const element = menuOf(
9924
- t("drawing.moreActions"),
10001
+ t("drawing.drawingMenu"),
9925
10002
  "wide",
9926
- submenuRow("order", t("drawing.visualOrder"), "layers"),
9927
- submenuRow("visibility", t("drawing.visibilityOnTimeframes")),
10003
+ ...table,
10004
+ submenuRow("template", t("drawing.template")),
10005
+ order,
10006
+ visibility,
9928
10007
  separator2(),
9929
- plain(menuRow(t("drawing.clone"), () => deps.run("chart.drawings.clone"), { icon: deps.icons.icon("clone"), hint: t("drawing.hintClone", { modifier: modifier() }), command: "chart.drawings.clone" })),
9930
- plain(menuRow(t("drawing.copy"), () => deps.run("chart.drawings.copy"), { spacer: true, hint: t("drawing.hintCopy", { modifier: modifier() }), command: "chart.drawings.copy" })),
10008
+ clone,
10009
+ copy,
10010
+ ...level.length ? [separator2(), ...level] : [],
9931
10011
  separator2(),
9932
- plain(menuRow(t("drawing.hide"), () => deps.run("chart.drawings.hideSelected"), { icon: deps.icons.icon("eyeCrossed"), command: "chart.drawings.hideSelected" }))
10012
+ plain(menuRow(t(selected.locked ? "drawing.unlock" : "drawing.lock"), () => deps.run("chart.drawings.lock", !selected.locked), { icon: deps.icons.icon(selected.locked ? "lockOpen" : "lockClosed"), command: "chart.drawings.lock" })),
10013
+ hide,
10014
+ plain(menuRow(t("drawing.remove"), () => deps.run("chart.drawings.deleteSelected"), { icon: deps.icons.icon("trash28"), hint: t("drawing.hintRemove"), command: "chart.drawings.deleteSelected" })),
10015
+ ...view.length ? [separator2(), ...view] : [],
10016
+ separator2(),
10017
+ plain(menuRow(t("menu.settings"), () => deps.run("chart.drawings.settings"), { icon: deps.icons.icon("gear"), command: "chart.drawings.settings" }))
9933
10018
  );
9934
10019
  return { element, closeSub };
9935
10020
  };
@@ -9950,36 +10035,7 @@ function mountSettingsBar(deps) {
9950
10035
  templates.setAttribute("aria-haspopup", "menu");
9951
10036
  templates.setAttribute("aria-expanded", "false");
9952
10037
  templates.dataset.qcControl = "templates";
9953
- templates.addEventListener("click", () => {
9954
- const saved = deps.presets.templatesFor(type);
9955
- const items2 = [
9956
- menuRow(t("drawing.saveTemplateAs"), () => openTemplateNameDialog({ container: deps.chrome, t, icons: deps.icons }, (name2) => deps.run("chart.drawings.template.save", name2)), { command: "chart.drawings.template.save" }),
9957
- menuRow(t("drawing.applyDefaultTemplate"), () => deps.run("chart.drawings.template.apply", null), { command: "chart.drawings.template.apply" })
9958
- ];
9959
- if (saved.length) items2.push(separator2());
9960
- for (const template of saved) {
9961
- const rowEl = el("div", { class: "qc-drawing-flyout-row" });
9962
- rowEl.append(
9963
- menuRow(template.name, () => deps.run("chart.drawings.template.apply", template.name), { command: "chart.drawings.template.apply" }),
9964
- button({
9965
- class: "qc-drawing-star",
9966
- label: t("drawing.removeTemplateNamed", { name: template.name }),
9967
- title: t("drawing.remove"),
9968
- icon: deps.icons.icon("trash", 18),
9969
- disabled: !deps.available("chart.drawings.template.remove"),
9970
- onClick: () => {
9971
- closeOpen();
9972
- openTemplateDeleteDialog({ container: deps.chrome, t, icons: deps.icons }, template.name, () => deps.run("chart.drawings.template.remove", template.name));
9973
- }
9974
- })
9975
- );
9976
- const remove = rowEl.querySelector(".qc-drawing-star");
9977
- if (remove) remove.hidden = !shown2("chart.drawings.template.remove");
9978
- rowEl.hidden = !shown2("chart.drawings.template.apply");
9979
- items2.push(rowEl);
9980
- }
9981
- openPanel(templates, menuOf(t("drawing.drawingTemplates"), "wide", ...items2));
9982
- });
10038
+ templates.addEventListener("click", () => openPanel(templates, menuOf(t("drawing.drawingTemplates"), "wide", ...templateItems(type))));
9983
10039
  controls.appendChild(templates);
9984
10040
  const colorPanel = (control, spec) => {
9985
10041
  openPanel(
@@ -10113,7 +10169,7 @@ function mountSettingsBar(deps) {
10113
10169
  }
10114
10170
  if (hasStroke) build.line();
10115
10171
  if (FILLABLE.has(type)) build.fill();
10116
- if (selected.hasText || FONT_TOOLS.has(type) || OWN_WORDS_TOOLS.has(type)) build.text();
10172
+ if (selected.hasText && !NO_WORDS_INK.has(type) || FONT_TOOLS.has(type) || OWN_WORDS_TOOLS.has(type)) build.text();
10117
10173
  for (const channel of TOOL_COLOR_CHANNELS[type] ?? []) propColor(channel);
10118
10174
  if (FONT_TOOLS.has(type) && type !== "table") build.size();
10119
10175
  if (hasStroke && !NO_LINE_DECOR.has(type)) {
@@ -10165,7 +10221,7 @@ function mountSettingsBar(deps) {
10165
10221
  more.setAttribute("aria-expanded", "false");
10166
10222
  more.dataset.qcControl = "more";
10167
10223
  more.addEventListener("click", () => {
10168
- const menu2 = moreMenu();
10224
+ const menu2 = drawingMenu("more", selected);
10169
10225
  openPanel(more, menu2.element, "below-end", menu2.closeSub);
10170
10226
  });
10171
10227
  controls.appendChild(more);
@@ -10175,6 +10231,23 @@ function mountSettingsBar(deps) {
10175
10231
  render();
10176
10232
  return {
10177
10233
  render,
10234
+ openMenuAt(clientX, clientY, extra = []) {
10235
+ const selected = deps.selected();
10236
+ if (!selected) return false;
10237
+ closeOpen();
10238
+ const menu2 = drawingMenu("context", selected, extra);
10239
+ const close = openPopover(deps.chrome, pointAnchor(clientX, clientY), menu2.element, "below", () => {
10240
+ menu2.closeSub();
10241
+ if (closePanel === close) {
10242
+ closePanel = null;
10243
+ panelFor = null;
10244
+ }
10245
+ });
10246
+ closePanel = close;
10247
+ panelFor = selected.id;
10248
+ focusFirst(menu2.element);
10249
+ return true;
10250
+ },
10178
10251
  destroy() {
10179
10252
  closeOpen();
10180
10253
  unfollow();
@@ -11083,6 +11156,7 @@ function openImagePicker(deps) {
11083
11156
  }
11084
11157
 
11085
11158
  // src/ui/drawings/settingsRows.ts
11159
+ var isSettingsTab = (value) => value === "Inputs" || value === "Style" || value === "Text" || value === "Coordinates" || value === "Visibility";
11086
11160
  var TAB_LABEL = {
11087
11161
  Inputs: "drawing.tabInputs",
11088
11162
  Style: "drawing.tabStyle",
@@ -11301,6 +11375,7 @@ var STATS = [
11301
11375
  { key: "showPipsChange", label: "drawing.changeInPips" },
11302
11376
  { key: "showBarsRange", label: "drawing.barsRange" },
11303
11377
  { key: "showDateTimeRange", label: "drawing.dateTimeRange" },
11378
+ { key: "showDistance", label: "drawing.distance" },
11304
11379
  { key: "showAngle", label: "drawing.angle" }
11305
11380
  ];
11306
11381
  var STATS_POSITION_LABEL = { left: "drawing.left", center: "drawing.center", right: "drawing.right", auto: "drawing.auto" };
@@ -12377,7 +12452,7 @@ function openSettingsDialog(deps) {
12377
12452
  const def = drawingTools.get(drawing2.type);
12378
12453
  const toolTitle = def ? toolName(t, def.type, def.name) : drawing2.type;
12379
12454
  const nameOf2 = () => drawing2.options.name || toolTitle;
12380
- let tab = firstTabFor(drawing2);
12455
+ let tab = deps.tab && tabsFor(drawing2).includes(deps.tab) ? deps.tab : firstTabFor(drawing2);
12381
12456
  let settled = false;
12382
12457
  const dialog = openDialog2({
12383
12458
  container: deps.chrome,
@@ -12647,6 +12722,7 @@ function attachDrawingsPlane(deps) {
12647
12722
  setCurrency: () => void 0,
12648
12723
  relabel: () => void 0,
12649
12724
  refresh: () => void 0,
12725
+ openMenuAt: () => false,
12650
12726
  applyToolIntent: () => void 0,
12651
12727
  rebindIdentity: () => void 0,
12652
12728
  destroy: () => void 0
@@ -12795,7 +12871,8 @@ function attachDrawingsPlane(deps) {
12795
12871
  position: () => prefs().settingsBarPosition,
12796
12872
  onMove: (position) => write({ settingsBarPosition: position }),
12797
12873
  recentColors: colors.list,
12798
- onMixColor: colors.add
12874
+ onMixColor: colors.add,
12875
+ tableCell: () => !!selectedTable()?.editingCell
12799
12876
  });
12800
12877
  const renderAll = () => {
12801
12878
  toolbar?.render();
@@ -12934,7 +13011,7 @@ function attachDrawingsPlane(deps) {
12934
13011
  setRemoveLocked: (on) => write({ removeLocked: on }),
12935
13012
  toggleFavorite: (tool) => write({ favorites: toggleFavorite(prefs().favorites, tool) }),
12936
13013
  setFavoritesBar: (on) => write({ favorites: { ...prefs().favorites, visible: on } }),
12937
- openSettings() {
13014
+ openSettings(page) {
12938
13015
  const drawing2 = handle.selectedDrawing();
12939
13016
  if (!drawing2 || dialog) return;
12940
13017
  handle.beginPreview();
@@ -12950,6 +13027,7 @@ function attachDrawingsPlane(deps) {
12950
13027
  available,
12951
13028
  shown: shown2,
12952
13029
  colors,
13030
+ ...page ? { tab: page } : {},
12953
13031
  onClose: () => {
12954
13032
  handle.endPreview();
12955
13033
  dialog = null;
@@ -13057,6 +13135,12 @@ function attachDrawingsPlane(deps) {
13057
13135
  settingsBar?.render();
13058
13136
  },
13059
13137
  refresh,
13138
+ openMenuAt: (clientX, clientY, extras) => {
13139
+ const target = menuDrawing(handle);
13140
+ if (!target || !settingsBar) return false;
13141
+ const table = target instanceof TableNote ? { cell: !!target.editingCell } : null;
13142
+ return settingsBar.openMenuAt(clientX, clientY, extras?.(table) ?? []);
13143
+ },
13060
13144
  syncHideLayers,
13061
13145
  applyToolIntent: (arg) => verbs.arm(arg),
13062
13146
  rebindIdentity(id) {
@@ -18032,6 +18116,9 @@ var MENU_COMMAND = {
18032
18116
  "remove-indicators": "chart.indicators.removeAll",
18033
18117
  "remove-drawings": "chart.drawings.removeAll"
18034
18118
  };
18119
+ function raiseMenuAt(drawings2, menu2, clientX, clientY) {
18120
+ return drawings2.openMenuAt(clientX, clientY, (table) => menu2.itemsAt(clientX, clientY, table)) || menu2.raiseAt(clientX, clientY);
18121
+ }
18035
18122
  function attachMenuPlane(deps) {
18036
18123
  const menu2 = mountMenu(
18037
18124
  deps.host,
@@ -18058,8 +18145,8 @@ function attachMenuPlane(deps) {
18058
18145
  if (price == null) return false;
18059
18146
  deps.setLevel(price);
18060
18147
  const priceText = deps.formatter().format(price);
18061
- const extra = deps.extensions()?.menuItems({ price, priceText, symbol: deps.symbol(), name: deps.symbolName(), timeframe: deps.timeframe(), clientX, clientY }) ?? [];
18062
18148
  const table = deps.table?.() ?? null;
18149
+ const extra = deps.extensions()?.menuItems({ price, priceText, symbol: deps.symbol(), name: deps.symbolName(), timeframe: deps.timeframe(), clientX, clientY, ...table ? { table } : {} }) ?? [];
18063
18150
  menu2.open(
18064
18151
  { clientX, clientY },
18065
18152
  {
@@ -18097,8 +18184,17 @@ function attachMenuPlane(deps) {
18097
18184
  }
18098
18185
  return true;
18099
18186
  };
18187
+ const itemsAt = (clientX, clientY, table) => {
18188
+ const host2 = deps.extensions();
18189
+ if (!host2) return [];
18190
+ const price = priceAt(clientY);
18191
+ if (price == null) return [];
18192
+ const priceText = deps.formatter().format(price);
18193
+ return host2.menuItems({ price, priceText, symbol: deps.symbol(), name: deps.symbolName(), timeframe: deps.timeframe(), clientX, clientY, ...table ? { table } : {} });
18194
+ };
18100
18195
  return {
18101
18196
  raiseAt,
18197
+ itemsAt,
18102
18198
  runShortcutAt,
18103
18199
  close: () => menu2.close(),
18104
18200
  refresh: () => menu2.refresh(),
@@ -18725,7 +18821,7 @@ function registerChartCommands(deps) {
18725
18821
  if (arg === "current-and-above" || arg === "current-and-below" || arg === "current-only" || arg === "all") drawings2()?.setVisibilityPreset(arg);
18726
18822
  }
18727
18823
  });
18728
- add({ id: "chart.drawings.settings", scope: "chart", label: "command.drawingSettings", available: withSelection, execute: () => verbs()?.openSettings() });
18824
+ add({ id: "chart.drawings.settings", scope: "chart", label: "command.drawingSettings", available: withSelection, execute: (page) => verbs()?.openSettings(isSettingsTab(page) ? page : void 0) });
18729
18825
  add({ id: "chart.drawings.commitEdit", scope: "chart", label: "command.drawingCommitEdit", available: withSelection, execute: () => verbs()?.commitEdit() });
18730
18826
  add({
18731
18827
  id: "chart.drawings.template.apply",
@@ -19702,7 +19798,7 @@ function createChartInstance(deps) {
19702
19798
  gestures,
19703
19799
  toolArmed: () => drawings2.handle?.activeTool() != null,
19704
19800
  disposed: disposedFn,
19705
- raiseAt: (x, y) => menu2.raiseAt(x, y),
19801
+ raiseAt: (x, y) => raiseMenuAt(drawings2, menu2, x, y),
19706
19802
  // The plot spans the time scale's width, beside the left price scale and above the time
19707
19803
  // scale, so whatever lies outside it is a scale.
19708
19804
  plotArea: () => {
@@ -19714,7 +19810,7 @@ function createChartInstance(deps) {
19714
19810
  }) : null;
19715
19811
  if (menu2) {
19716
19812
  gestures.addEventListener("contextmenu", (e) => {
19717
- if (menu2.raiseAt(e.clientX, e.clientY)) e.preventDefault();
19813
+ if (raiseMenuAt(drawings2, menu2, e.clientX, e.clientY)) e.preventDefault();
19718
19814
  });
19719
19815
  }
19720
19816
  const nav = deps.ui.navigation ? mountNavControls({ chrome: chrome2, gestures, commands: deps.commands, i18n, icons: deps.icons, maximized: () => deps.layoutMaximized(), shown: (id) => commandShown(deps.access, id) }) : null;