@trdrs/quickcharts 5.2.0 → 5.3.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 (55) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +55 -17
  3. package/dist/{ar-TG26ZCCE.js → ar-BBRV6CC4.js} +5 -1
  4. package/dist/{ar-TG26ZCCE.js.map → ar-BBRV6CC4.js.map} +1 -1
  5. package/dist/{assets-DF3nozNV.d.ts → assets-B_JlJaHF.d.ts} +4 -0
  6. package/dist/{ca_ES-WJWH5BXU.js → ca_ES-OF2NGA3A.js} +5 -1
  7. package/dist/{ca_ES-WJWH5BXU.js.map → ca_ES-OF2NGA3A.js.map} +1 -1
  8. package/dist/{chunk-Q3DCXQDW.js → chunk-FRZFOTMO.js} +42 -39
  9. package/dist/chunk-FRZFOTMO.js.map +1 -0
  10. package/dist/{de-SUDTTPQ3.js → de-D5WWQLT5.js} +5 -1
  11. package/dist/{de-SUDTTPQ3.js.map → de-D5WWQLT5.js.map} +1 -1
  12. package/dist/drawings.d.ts +2 -2
  13. package/dist/drawings.js +1 -1
  14. package/dist/{es-FOBXUK2X.js → es-6TM3Z6CQ.js} +5 -1
  15. package/dist/{es-FOBXUK2X.js.map → es-6TM3Z6CQ.js.map} +1 -1
  16. package/dist/feature-manifest.json +6 -1
  17. package/dist/{fr-7KQC4IJH.js → fr-L5EPUMNA.js} +5 -1
  18. package/dist/{fr-7KQC4IJH.js.map → fr-L5EPUMNA.js.map} +1 -1
  19. package/dist/{he_IL-2T6XBA6D.js → he_IL-PXH4KNDC.js} +5 -1
  20. package/dist/{he_IL-2T6XBA6D.js.map → he_IL-PXH4KNDC.js.map} +1 -1
  21. package/dist/{id_ID-SI25N57C.js → id_ID-MMY4EQSL.js} +5 -1
  22. package/dist/{id_ID-SI25N57C.js.map → id_ID-MMY4EQSL.js.map} +1 -1
  23. package/dist/index.d.ts +27 -4
  24. package/dist/index.js +204 -101
  25. package/dist/index.js.map +1 -1
  26. package/dist/{it-PMSTWZDL.js → it-TUILRXJ5.js} +5 -1
  27. package/dist/{it-PMSTWZDL.js.map → it-TUILRXJ5.js.map} +1 -1
  28. package/dist/{ja-PABDRAXV.js → ja-7QY2FLXF.js} +5 -1
  29. package/dist/{ja-PABDRAXV.js.map → ja-7QY2FLXF.js.map} +1 -1
  30. package/dist/{ko-JHRYYFCV.js → ko-RWI5JOO2.js} +5 -1
  31. package/dist/{ko-JHRYYFCV.js.map → ko-RWI5JOO2.js.map} +1 -1
  32. package/dist/{ms_MY-U4EE5Q4V.js → ms_MY-ABJSZCPH.js} +5 -1
  33. package/dist/{ms_MY-U4EE5Q4V.js.map → ms_MY-ABJSZCPH.js.map} +1 -1
  34. package/dist/{pl-4HCG3T3J.js → pl-XLOQLQVW.js} +5 -1
  35. package/dist/{pl-4HCG3T3J.js.map → pl-XLOQLQVW.js.map} +1 -1
  36. package/dist/{pt-6LTNN653.js → pt-TZWQOZ5P.js} +5 -1
  37. package/dist/{pt-6LTNN653.js.map → pt-TZWQOZ5P.js.map} +1 -1
  38. package/dist/quickcharts.css +278 -199
  39. package/dist/{ru-LFHCSDBV.js → ru-2KVG2H7U.js} +5 -1
  40. package/dist/{ru-LFHCSDBV.js.map → ru-2KVG2H7U.js.map} +1 -1
  41. package/dist/{sv-4XVUXYK6.js → sv-3JTSBHQN.js} +5 -1
  42. package/dist/{sv-4XVUXYK6.js.map → sv-3JTSBHQN.js.map} +1 -1
  43. package/dist/{th-WM2PVA24.js → th-O3CHCMEU.js} +5 -1
  44. package/dist/{th-WM2PVA24.js.map → th-O3CHCMEU.js.map} +1 -1
  45. package/dist/theme-manifest.json +51 -40
  46. package/dist/{tr-HMAZXSJM.js → tr-RWKHFLUS.js} +5 -1
  47. package/dist/{tr-HMAZXSJM.js.map → tr-RWKHFLUS.js.map} +1 -1
  48. package/dist/{vi-ITFBV5B7.js → vi-D2CXSN5R.js} +5 -1
  49. package/dist/{vi-ITFBV5B7.js.map → vi-D2CXSN5R.js.map} +1 -1
  50. package/dist/{zh-ZGU2RI7K.js → zh-KBHIBNWP.js} +5 -1
  51. package/dist/{zh-ZGU2RI7K.js.map → zh-KBHIBNWP.js.map} +1 -1
  52. package/dist/{zh_TW-PNINSQ6F.js → zh_TW-474AC5C4.js} +5 -1
  53. package/dist/{zh_TW-PNINSQ6F.js.map → zh_TW-474AC5C4.js.map} +1 -1
  54. package/package.json +1 -1
  55. package/dist/chunk-Q3DCXQDW.js.map +0 -1
package/dist/index.js CHANGED
@@ -25,6 +25,7 @@ import {
25
25
  IMAGE_ERROR_MESSAGES,
26
26
  INERT_PROPS,
27
27
  INPUT_PROPS,
28
+ LIGHT_THEME,
28
29
  MAGNET_LABELS,
29
30
  MAGNET_STRENGTHS,
30
31
  MIXED_LEVEL_COLORS,
@@ -113,7 +114,7 @@ import {
113
114
  withRow,
114
115
  withoutColumn,
115
116
  withoutRow
116
- } from "./chunk-Q3DCXQDW.js";
117
+ } from "./chunk-FRZFOTMO.js";
117
118
  import {
118
119
  ResourceAbortError,
119
120
  memorySaveLoadAdapter
@@ -1552,8 +1553,16 @@ var picker = {
1552
1553
  "picker.noMatches": "No matching indicators.",
1553
1554
  "picker.collections": "Indicator collections",
1554
1555
  "picker.personal": "Personal",
1556
+ /** The rail's heading over the shipped definitions. */
1555
1557
  "picker.builtin": "Built-in",
1558
+ /** The rail's collection of shipped technical indicators, under Built-in. */
1559
+ "picker.technicals": "Technicals",
1556
1560
  "picker.favorites": "Favorites",
1561
+ /** The kind filters: their group's name, the filter that shows every kind, and the chart's own
1562
+ * kind beside the kinds a host declares. */
1563
+ "picker.kindFilter": "Type",
1564
+ "picker.allKinds": "All",
1565
+ "picker.indicators": "Indicators",
1557
1566
  "picker.thousands": " K",
1558
1567
  "picker.name": "Name",
1559
1568
  "picker.author": "Author",
@@ -1789,26 +1798,26 @@ function readingDirection(i18n) {
1789
1798
  return BUILT_IN_LOCALES.find((l) => l.code === i18n.locale())?.dir ?? "ltr";
1790
1799
  }
1791
1800
  var chartDictionaries = createDictionaryLoader(en, {
1792
- de: () => import("./de-SUDTTPQ3.js"),
1793
- fr: () => import("./fr-7KQC4IJH.js"),
1794
- es: () => import("./es-FOBXUK2X.js"),
1795
- it: () => import("./it-PMSTWZDL.js"),
1796
- ca_ES: () => import("./ca_ES-WJWH5BXU.js"),
1797
- pl: () => import("./pl-4HCG3T3J.js"),
1798
- sv: () => import("./sv-4XVUXYK6.js"),
1799
- tr: () => import("./tr-HMAZXSJM.js"),
1800
- ru: () => import("./ru-LFHCSDBV.js"),
1801
- pt: () => import("./pt-6LTNN653.js"),
1802
- id_ID: () => import("./id_ID-SI25N57C.js"),
1803
- ms_MY: () => import("./ms_MY-U4EE5Q4V.js"),
1804
- th: () => import("./th-WM2PVA24.js"),
1805
- vi: () => import("./vi-ITFBV5B7.js"),
1806
- ja: () => import("./ja-PABDRAXV.js"),
1807
- ko: () => import("./ko-JHRYYFCV.js"),
1808
- zh: () => import("./zh-ZGU2RI7K.js"),
1809
- zh_TW: () => import("./zh_TW-PNINSQ6F.js"),
1810
- ar: () => import("./ar-TG26ZCCE.js"),
1811
- he_IL: () => import("./he_IL-2T6XBA6D.js")
1801
+ de: () => import("./de-D5WWQLT5.js"),
1802
+ fr: () => import("./fr-L5EPUMNA.js"),
1803
+ es: () => import("./es-6TM3Z6CQ.js"),
1804
+ it: () => import("./it-TUILRXJ5.js"),
1805
+ ca_ES: () => import("./ca_ES-OF2NGA3A.js"),
1806
+ pl: () => import("./pl-XLOQLQVW.js"),
1807
+ sv: () => import("./sv-3JTSBHQN.js"),
1808
+ tr: () => import("./tr-RWKHFLUS.js"),
1809
+ ru: () => import("./ru-2KVG2H7U.js"),
1810
+ pt: () => import("./pt-TZWQOZ5P.js"),
1811
+ id_ID: () => import("./id_ID-MMY4EQSL.js"),
1812
+ ms_MY: () => import("./ms_MY-ABJSZCPH.js"),
1813
+ th: () => import("./th-O3CHCMEU.js"),
1814
+ vi: () => import("./vi-D2CXSN5R.js"),
1815
+ ja: () => import("./ja-7QY2FLXF.js"),
1816
+ ko: () => import("./ko-RWI5JOO2.js"),
1817
+ zh: () => import("./zh-KBHIBNWP.js"),
1818
+ zh_TW: () => import("./zh_TW-474AC5C4.js"),
1819
+ ar: () => import("./ar-BBRV6CC4.js"),
1820
+ he_IL: () => import("./he_IL-PXH4KNDC.js")
1812
1821
  });
1813
1822
  var dynamic = (t) => t;
1814
1823
  var source = null;
@@ -1989,7 +1998,8 @@ var THEME_ROLES = [
1989
1998
  // rows it runs beside.
1990
1999
  { id: "chrome.scrollThumb", family: "chrome", kind: "color", description: "The thumb of the thin bar beside a list the viewer scrolls, such as the search results or the indicator list." },
1991
2000
  { id: "chrome.radius", family: "chrome", kind: "length", description: "Corner radius of a control." },
1992
- { id: "chrome.radiusLarge", family: "chrome", kind: "length", description: "Corner radius of a panel, dialog, or menu." },
2001
+ { id: "chrome.radiusLarge", family: "chrome", kind: "length", description: "Corner radius of a panel or menu." },
2002
+ { id: "chrome.radiusDialog", family: "chrome", kind: "length", description: "Corner radius of a dialog." },
1993
2003
  // ── overlay: menus, dialogs, popovers, and what sits behind them ────────────────────────────
1994
2004
  { id: "overlay.surface", family: "overlay", kind: "color", description: "The fill of a floating menu, dialog, or popover." },
1995
2005
  { id: "overlay.separator", family: "overlay", kind: "color", description: "The rule between groups inside a menu or panel." },
@@ -5199,6 +5209,27 @@ function mergePartialChartSettings(first, second) {
5199
5209
  function copyPartialChartSettings(partial) {
5200
5210
  return mergePartialChartSettings({}, partial);
5201
5211
  }
5212
+ var MODE_LEAVES = (() => {
5213
+ const light = chartSettingsDefaults(LIGHT_THEME);
5214
+ const dark = SHAPE;
5215
+ const paths = /* @__PURE__ */ new Set();
5216
+ for (const [section, leaves] of Object.entries(dark)) {
5217
+ for (const [leaf, value] of Object.entries(leaves)) if (light[section]?.[leaf] !== value) paths.add(`${section}.${leaf}`);
5218
+ }
5219
+ return paths;
5220
+ })();
5221
+ function hasModeLeaves(partial) {
5222
+ return Object.entries(partial).some(([section, leaves]) => Object.keys(leaves ?? {}).some((leaf) => MODE_LEAVES.has(`${section}.${leaf}`)));
5223
+ }
5224
+ function withoutModeLeaves(partial) {
5225
+ const out = {};
5226
+ for (const [section, leaves] of Object.entries(partial)) {
5227
+ for (const [leaf, value] of Object.entries(leaves ?? {})) {
5228
+ if (!MODE_LEAVES.has(`${section}.${leaf}`)) (out[section] ??= {})[leaf] = value;
5229
+ }
5230
+ }
5231
+ return out;
5232
+ }
5202
5233
  function settingsFromAppearance(appearance, isColor) {
5203
5234
  if (!appearance || typeof appearance !== "object" || Array.isArray(appearance)) return { settings: {}, rejected: [] };
5204
5235
  const old = appearance;
@@ -10285,11 +10316,13 @@ var ICONS = {
10285
10316
  textItalic: { viewBox: "0 0 28 28", body: '<path fill="none" stroke="currentColor" d="M12 6.5h7M9 21.5h7M15.5 6.5l-3 15"/>' },
10286
10317
  close18: { viewBox: "0 0 18 18", body: '<path d="M4.5 4.5l9 9M13.5 4.5l-9 9" stroke="currentColor" stroke-width="1.4" stroke-linecap="round"/>' },
10287
10318
  chevronDown18: { viewBox: "0 0 18 18", body: solid(polyline([[4.4, 7.25], [9, 11.3], [13.6, 7.25]], 1.5)) },
10288
- // The indicator picker's marks, on the grids its rows were drawn for.
10289
- pickerStar: { viewBox: "0 0 18 18", body: '<path fill="none" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round" d="M9 2.13L11.057 6.168L15.534 6.877L12.329 10.082L13.038 14.558L9 12.5L4.962 14.558L5.671 10.082L2.466 6.877L6.943 6.168z"/>' },
10290
- pickerStarFilled: { viewBox: "0 0 18 18", body: '<path fill="currentColor" stroke="currentColor" stroke-width="1.2" stroke-linejoin="round" d="M9 2.13L11.057 6.168L15.534 6.877L12.329 10.082L13.038 14.558L9 12.5L4.962 14.558L5.671 10.082L2.466 6.877L6.943 6.168z"/>' },
10291
- plus24: { viewBox: "0 0 24 24", body: '<path d="M12 5v14M5 12h14" stroke="currentColor" stroke-width="2" stroke-linecap="round"/>' },
10292
- search24: { viewBox: "0 0 24 24", body: '<circle cx="11" cy="11" r="7" stroke="currentColor" stroke-width="1.8"/><path d="M20 20l-3.5-3.5" stroke="currentColor" stroke-width="1.8" stroke-linecap="round"/>' },
10319
+ // The indicator picker's marks. A row's star on the 18 grid, a one-unit outline or the filled
10320
+ // shape; the rail's Favorites, an outlined star on the 28 grid; and the rail's built-in indicators,
10321
+ // a trend line over a run of columns.
10322
+ pickerStar: { viewBox: "0 0 18 18", body: '<path stroke="currentColor" d="M9 2.13l1.903 3.855.116.236.26.038 4.255.618-3.079 3.001-.188.184.044.259.727 4.237-3.805-2L9 12.434l-.233.122-3.805 2.001.727-4.237.044-.26-.188-.183-3.079-3.001 4.255-.618.26-.038.116-.236L9 2.13z"/>' },
10323
+ pickerStarFilled: { viewBox: "0 0 18 18", body: '<path fill="currentColor" d="M9 1l2.35 4.76 5.26.77-3.8 3.7.9 5.24L9 13l-4.7 2.47.9-5.23-3.8-3.71 5.25-.77L9 1z"/>' },
10324
+ pickerFavorites: { viewBox: "0 0 28 28", body: '<path fill="currentColor" fill-rule="evenodd" d="m17.13 9.74 7.37.9-5.44 5.06L20.4 23 14 19.38 7.6 23l1.34-7.3-5.44-5.06 7.37-.9L14 3l3.13 6.74Zm3.99 2-3.68 3.42.9 4.96L14 17.66l-4.34 2.46.9-4.96-3.68-3.42 5-.6L14 6.56l2.12 4.56 5 .61Z"/>' },
10325
+ pickerTechnicals: { viewBox: "0 0 28 28", body: '<path fill="currentColor" d="m22.85 7.85-4.58 4.59a2.5 2.5 0 0 1-3.54 0l-3.17-3.17a1.5 1.5 0 0 0-2.12 0l-4.59 4.58-.7-.7 4.58-4.59a2.5 2.5 0 0 1 3.54 0l3.17 3.17a1.5 1.5 0 0 0 2.12 0l4.59-4.58.7.7ZM11 22h-1v-8h1v8Zm12 0h-1v-8h1v8ZM8 22H7v-6h1v6Zm6 0h-1v-6h1v6Zm6 0h-1v-6h1v6Zm-3 0h-1v-4h1v4ZM5 22H4v-3h1v3Z"/>' },
10293
10326
  // The note beside a switch that needs a sentence.
10294
10327
  info: { viewBox: "0 0 18 18", body: solid(disc(9, 9, 8) + disc(9, 5, 1, true) + polygon([[7, 8], [10, 8], [10, 14], [8.5, 14], [8.5, 9.5], [7, 9.5]], true)) },
10295
10328
  // The short tip beside a setting's label: a disc with a question mark cut through it, its hook
@@ -10398,7 +10431,6 @@ function openDialog(options2) {
10398
10431
  scrim.appendChild(box2);
10399
10432
  const motion = options2.motion !== false;
10400
10433
  if (options2.veil === false) scrim.dataset.qcVeil = "none";
10401
- if (options2.passThrough) scrim.dataset.qcPass = "true";
10402
10434
  if (motion) scrim.dataset.state = "opening";
10403
10435
  let isOpen = true;
10404
10436
  const previouslyFocused = document.activeElement;
@@ -11527,7 +11559,6 @@ function openDialog2(options2) {
11527
11559
  ...options2.width === void 0 ? {} : { width: options2.width },
11528
11560
  ...options2.veil === void 0 ? {} : { veil: options2.veil },
11529
11561
  ...options2.motion === void 0 ? {} : { motion: options2.motion },
11530
- ...options2.passThrough === void 0 ? {} : { passThrough: options2.passThrough },
11531
11562
  build(element, dialog) {
11532
11563
  box2 = element;
11533
11564
  closeBox = () => dialog.close();
@@ -15143,6 +15174,7 @@ function serializeChartContent(content) {
15143
15174
  axis: content.priceAxis,
15144
15175
  indicators: content.indicators.map(savedIndicatorFields),
15145
15176
  settings: content.settings,
15177
+ ...content.settingsMode ? { settingsMode: content.settingsMode } : {},
15146
15178
  compares: content.compares,
15147
15179
  panes: content.panes,
15148
15180
  ...content.drawings ? { drawings: content.drawings } : {},
@@ -15165,6 +15197,7 @@ function parseChartContent(content) {
15165
15197
  indicators: indicators2,
15166
15198
  settings: read?.settings,
15167
15199
  settingsRejected: read?.rejected,
15200
+ settingsMode: raw.settingsMode === "light" || raw.settingsMode === "dark" ? raw.settingsMode : void 0,
15168
15201
  drawings: Array.isArray(raw.drawings) ? raw.drawings : void 0,
15169
15202
  compares: raw.compares,
15170
15203
  // An earlier blob carries no order of its own, and its panes stand in the order it stores what
@@ -18125,7 +18158,7 @@ var byMeaning = (table) => table;
18125
18158
  var CONTROL_ICONS = byMeaning({
18126
18159
  // The top bar and the widget's menus.
18127
18160
  compare: [ICONS.comparePlus],
18128
- indicators: [ICONS.indicators],
18161
+ indicators: [ICONS.indicators, ICONS.pickerTechnicals],
18129
18162
  replay: [ICONS.replay],
18130
18163
  undo: [ICONS.undo],
18131
18164
  redo: [ICONS.redo],
@@ -18162,15 +18195,15 @@ var CONTROL_ICONS = byMeaning({
18162
18195
  close: [ICONS.close, ICONS.closeThin, ICONS.dialogClose],
18163
18196
  remove: [ICONS.close18, ICONS.removeRow],
18164
18197
  delete: [ICONS.trash, ICONS.trash28],
18165
- add: [ICONS.plus, ICONS.plusThin, ICONS.plus24],
18198
+ add: [ICONS.plus, ICONS.plusThin],
18166
18199
  bold: [ICONS.textBold],
18167
18200
  italic: [ICONS.textItalic],
18168
- search: [ICONS.search, ICONS.search24],
18201
+ search: [ICONS.search],
18169
18202
  clear: [ICONS.clear],
18170
18203
  open: [ICONS.folder],
18171
18204
  rename: [ICONS.pencil],
18172
18205
  duplicate: [ICONS.clone],
18173
- favorite: [ICONS.star, ICONS.pickerStar],
18206
+ favorite: [ICONS.star, ICONS.pickerStar, ICONS.pickerFavorites],
18174
18207
  favorited: [ICONS.starFilled, ICONS.pickerStarFilled],
18175
18208
  sortAscending: [ICONS.sortUp, ICONS.sortUpRow],
18176
18209
  sortDescending: [ICONS.sortDown, ICONS.sortDownRow],
@@ -20386,9 +20419,9 @@ function mountScaleControls(deps) {
20386
20419
  stopPointer(modes);
20387
20420
  const unit = h("div", { class: "qc-scale-unit", "data-role": "scale-unit" });
20388
20421
  deps.chrome.appendChild(unit);
20389
- const plus2 = h("button", { type: "button", class: "qc-scale-plus", "data-role": "scale-plus" });
20390
- plus2.hidden = true;
20391
- deps.chrome.appendChild(plus2);
20422
+ const plus = h("button", { type: "button", class: "qc-scale-plus", "data-role": "scale-plus" });
20423
+ plus.hidden = true;
20424
+ deps.chrome.appendChild(plus);
20392
20425
  let placed = null;
20393
20426
  let pressing = null;
20394
20427
  let releasing = false;
@@ -20403,7 +20436,7 @@ function mountScaleControls(deps) {
20403
20436
  const at2 = anchor();
20404
20437
  return at2 !== null && clientX >= at2.left && clientX < at2.right && clientY >= at2.top && clientY < at2.bottom;
20405
20438
  };
20406
- plus2.addEventListener("click", (event) => {
20439
+ plus.addEventListener("click", (event) => {
20407
20440
  const at2 = anchor();
20408
20441
  if (at2) deps.openPriceMenu(at2, event.detail === 0);
20409
20442
  });
@@ -20444,19 +20477,19 @@ function mountScaleControls(deps) {
20444
20477
  const scale = box2 ? deps.box() : null;
20445
20478
  if (!box2 || !scale) {
20446
20479
  placed = null;
20447
- plus2.hidden = true;
20480
+ plus.hidden = true;
20448
20481
  return;
20449
20482
  }
20450
20483
  const plotLeft = scale.side === "right" ? scale.left - box2.paneWidth : scale.left + scale.width;
20451
20484
  const left = plotLeft + box2.left;
20452
20485
  const was = placed;
20453
20486
  placed = { left, top: scale.top + box2.top, width: box2.width, height: box2.height, y: scale.top + box2.y, side: scale.side };
20454
- if (was && !plus2.hidden && was.left === placed.left && was.top === placed.top && was.width === placed.width && was.height === placed.height) return;
20455
- plus2.hidden = false;
20456
- plus2.style.left = `${placed.left}px`;
20457
- plus2.style.top = `${placed.top}px`;
20458
- plus2.style.width = `${placed.width}px`;
20459
- plus2.style.height = `${placed.height}px`;
20487
+ if (was && !plus.hidden && was.left === placed.left && was.top === placed.top && was.width === placed.width && was.height === placed.height) return;
20488
+ plus.hidden = false;
20489
+ plus.style.left = `${placed.left}px`;
20490
+ plus.style.top = `${placed.top}px`;
20491
+ plus.style.width = `${placed.width}px`;
20492
+ plus.style.height = `${placed.height}px`;
20460
20493
  };
20461
20494
  auto.addEventListener("click", () => {
20462
20495
  deps.toggleAutoScale();
@@ -20475,7 +20508,7 @@ function mountScaleControls(deps) {
20475
20508
  name(auto, t("chrome.autoScale"));
20476
20509
  log.textContent = t("chrome.logScaleMark");
20477
20510
  name(log, t("chrome.logScale"));
20478
- name(plus2, t("chrome.priceLevelMenu"));
20511
+ name(plus, t("chrome.priceLevelMenu"));
20479
20512
  };
20480
20513
  const sync = () => {
20481
20514
  const box2 = deps.box();
@@ -20561,7 +20594,7 @@ function mountScaleControls(deps) {
20561
20594
  deps.gestures.removeEventListener("click", onClick, true);
20562
20595
  modes.remove();
20563
20596
  unit.remove();
20564
- plus2.remove();
20597
+ plus.remove();
20565
20598
  }
20566
20599
  };
20567
20600
  }
@@ -21977,6 +22010,7 @@ function createChartInstance(deps) {
21977
22010
  let menuLevel = null;
21978
22011
  let drawingPrefs = readDrawingPreferences();
21979
22012
  let viewerPartial = {};
22013
+ let leavesMode = deps.theme.mode();
21980
22014
  const canvas = () => canvasTheme(deps.theme.get());
21981
22015
  const hostPartial = (() => {
21982
22016
  const named2 = readPartialChartSettings(deps.settings ?? {}, paintableColor).settings;
@@ -23417,6 +23451,9 @@ function createChartInstance(deps) {
23417
23451
  // factory colors and the host's brand as though a viewer had chosen every one of them, and a
23418
23452
  // reopen under another theme or another brand would then be stuck with the old ones.
23419
23453
  settings: copyPartialChartSettings(viewerPartial),
23454
+ // The mode a leaf that follows the mode was chosen in, so a reopen in the other mode lets the
23455
+ // mode in effect paint it.
23456
+ ...hasModeLeaves(viewerPartial) ? { settingsMode: leavesMode } : {},
23420
23457
  compares: compare?.serialize() ?? [],
23421
23458
  // The order the panes stand in, top to bottom, those waiting to be drawn included.
23422
23459
  panes: paneOps.order(),
@@ -23437,16 +23474,19 @@ function createChartInstance(deps) {
23437
23474
  const { dropped } = indicators2.restore(parsed.indicators);
23438
23475
  writeHidden();
23439
23476
  if (dropped > 0) deps.doors.notify("info", i18n.t("toast.indicatorsNotCarried", { count: dropped }));
23440
- if (parsed.settings) handle.applySettings(parsed.settings);
23477
+ if (parsed.settings) handle.applySettings(inMode(parsed.settings, parsed.settingsMode));
23441
23478
  compare?.restore(parsed.compares);
23442
23479
  paneOps.arrange(parsed.panes);
23443
23480
  if (deps.drawings.mode === "combined" && parsed.drawings) drawings2.handle?.restore(parsed.drawings);
23444
23481
  const extensionsComplete = extensions.host.restore(parsed.ext);
23445
23482
  return dropped === 0 && extensionsComplete;
23446
23483
  }
23484
+ function inMode(settings2, mode) {
23485
+ return mode && mode !== leavesMode ? withoutModeLeaves(settings2) : settings2;
23486
+ }
23447
23487
  function applyHistoryContent(next) {
23448
23488
  if (disposed) return;
23449
- viewerPartial = copyPartialChartSettings(next.settings);
23489
+ viewerPartial = copyPartialChartSettings(inMode(next.settings, next.settingsMode));
23450
23490
  applyLook();
23451
23491
  applyContent({
23452
23492
  symbol: next.symbol,
@@ -23773,8 +23813,16 @@ function createChartInstance(deps) {
23773
23813
  setLegendRows: (rows2) => legend2.setHostRows(rows2),
23774
23814
  screenshot: () => extensions.host.capture(() => chart.takeScreenshot(), () => ({ width: chart.chartElement().clientWidth, height: chart.chartElement().clientHeight })),
23775
23815
  repaintTheme() {
23816
+ const mode = deps.theme.mode();
23817
+ const switched = mode !== leavesMode && hasModeLeaves(viewerPartial);
23818
+ leavesMode = mode;
23819
+ if (switched) viewerPartial = withoutModeLeaves(viewerPartial);
23776
23820
  applyLook();
23777
23821
  legend2.setDot(session2.state());
23822
+ if (switched) {
23823
+ deps.contentChanged?.();
23824
+ history2.changed();
23825
+ }
23778
23826
  },
23779
23827
  relabel() {
23780
23828
  applyTimezone();
@@ -25479,6 +25527,7 @@ function openIndicatorSettings(deps) {
25479
25527
  }
25480
25528
 
25481
25529
  // src/ui/chrome/indicatorPickerData.ts
25530
+ var INDICATOR_KIND = "indicator";
25482
25531
  var record2 = (value) => !!value && typeof value === "object" && !Array.isArray(value);
25483
25532
  var text = (value) => typeof value === "string" && value.trim().length > 0;
25484
25533
  var builtinIds = new Set(BUILT_IN_INDICATORS2.map((d) => d.id));
@@ -25507,12 +25556,26 @@ function pickerCollections(value) {
25507
25556
  return null;
25508
25557
  }
25509
25558
  }
25510
- function pickerRows(value) {
25559
+ function pickerKinds(value) {
25560
+ try {
25561
+ if (value === void 0) return [];
25562
+ if (!Array.isArray(value)) return null;
25563
+ const result = [];
25564
+ for (const row2 of value) {
25565
+ if (!record2(row2) || !text(row2.id) || row2.id === INDICATOR_KIND || !text(row2.label)) return null;
25566
+ result.push({ id: row2.id, label: row2.label });
25567
+ }
25568
+ return unique(result.map((row2) => row2.id)) ? result : null;
25569
+ } catch {
25570
+ return null;
25571
+ }
25572
+ }
25573
+ function pickerRows(value, kinds = []) {
25511
25574
  try {
25512
25575
  if (!record2(value) || value.kind !== "ok" || !Array.isArray(value.items) || value.builtIns !== void 0 && !Array.isArray(value.builtIns)) return null;
25513
25576
  const items2 = [];
25514
25577
  for (const row2 of value.items) {
25515
- if (!record2(row2) || !text(row2.id) || builtinIds.has(row2.id) || ["builtin", "favorites", "add", "favorite"].includes(row2.id) || !text(row2.title) || !optionalText(row2.description) || !optionalText(row2.author) || !count(row2.favoriteCount) || row2.favorite !== void 0 && typeof row2.favorite !== "boolean") return null;
25578
+ if (!record2(row2) || !text(row2.id) || builtinIds.has(row2.id) || ["builtin", "favorites", "add", "favorite"].includes(row2.id) || !text(row2.title) || !optionalText(row2.description) || !optionalText(row2.author) || !count(row2.favoriteCount) || row2.favorite !== void 0 && typeof row2.favorite !== "boolean" || row2.kind !== void 0 && (typeof row2.kind !== "string" || row2.kind !== INDICATOR_KIND && !kinds.includes(row2.kind))) return null;
25516
25579
  const verbs = actions(row2.actions);
25517
25580
  if (!verbs || !text(row2.primaryAction) || !verbs.some((a) => a.id === row2.primaryAction)) return null;
25518
25581
  items2.push({
@@ -25522,6 +25585,7 @@ function pickerRows(value) {
25522
25585
  actions: verbs,
25523
25586
  ...row2.description !== void 0 ? { description: row2.description } : {},
25524
25587
  ...row2.author !== void 0 ? { author: row2.author } : {},
25588
+ ...row2.kind !== void 0 ? { kind: row2.kind } : {},
25525
25589
  ...row2.favorite !== void 0 ? { favorite: row2.favorite } : {},
25526
25590
  ...row2.favoriteCount !== void 0 ? { favoriteCount: row2.favoriteCount } : {}
25527
25591
  });
@@ -25539,11 +25603,17 @@ function pickerRows(value) {
25539
25603
  }
25540
25604
  }
25541
25605
 
25606
+ // src/ui/chrome/searchField.ts
25607
+ function searchField(icons, input, ...trailing) {
25608
+ return h("div", { class: "qc-search-field" }, icons.glyph(ICONS.search, { size: 28, className: "qc-search-magnifier" }), input, h("span", { class: "qc-search-actions-field" }, ...trailing));
25609
+ }
25610
+ function searchClear(icons, label3, onClear) {
25611
+ return button2({ label: label3, icon: icons.glyph(ICONS.clear, { size: 18 }), className: "qc-search-op", onClick: onClear });
25612
+ }
25613
+
25542
25614
  // src/ui/chrome/indicatorPicker.ts
25543
25615
  var FAVORITES_KEY = "quickcharts.indicatorFavorites.v1";
25544
25616
  var star = (icons, filled) => icons.glyph(filled ? ICONS.pickerStarFilled : ICONS.pickerStar, { size: 18 });
25545
- var plus = (icons) => icons.glyph(ICONS.plus24, { size: 18 });
25546
- var searchGlyph = (icons) => icons.glyph(ICONS.search24, { size: 18 });
25547
25617
  function freshInstanceId(definitionId, existing) {
25548
25618
  const taken = new Set(existing.map((i) => i.id));
25549
25619
  let n = 1;
@@ -25559,12 +25629,20 @@ function openIndicatorPicker(deps) {
25559
25629
  const t = (key, ...args) => deps.i18n.t(key, ...args);
25560
25630
  const source3 = deps.indicatorPicker;
25561
25631
  let collections = null;
25632
+ let kinds = [];
25562
25633
  let hostValid = !source3;
25563
- try {
25564
- collections = source3 ? pickerCollections(source3.collections) : [];
25565
- hostValid = collections !== null && (!source3 || typeof source3.list === "function" && typeof source3.act === "function");
25566
- } catch {
25567
- }
25634
+ const readHost = () => {
25635
+ try {
25636
+ collections = source3 ? pickerCollections(source3.collections) : [];
25637
+ kinds = source3 ? pickerKinds(source3.kinds) : [];
25638
+ hostValid = collections !== null && kinds !== null && (!source3 || typeof source3.list === "function" && typeof source3.act === "function");
25639
+ } catch {
25640
+ collections = null;
25641
+ kinds = null;
25642
+ hostValid = false;
25643
+ }
25644
+ };
25645
+ readHost();
25568
25646
  let favorites = [];
25569
25647
  try {
25570
25648
  const stored = JSON.parse(deps.storage?.get(FAVORITES_KEY) ?? "[]");
@@ -25573,6 +25651,7 @@ function openIndicatorPicker(deps) {
25573
25651
  }
25574
25652
  let query = "";
25575
25653
  let collection = deps.initialCollection === "favorites" || collections?.some((row2) => row2.id === deps.initialCollection) ? deps.initialCollection : "builtin";
25654
+ let kind = null;
25576
25655
  let generation = 0;
25577
25656
  let controller = null;
25578
25657
  let busy = false;
@@ -25602,14 +25681,20 @@ function openIndicatorPicker(deps) {
25602
25681
  offLocale();
25603
25682
  },
25604
25683
  build(box2, dialog) {
25605
- const input = h("input", { type: "search", class: "qc-picker-search", role: "searchbox", "aria-label": t("picker.search"), placeholder: t("picker.search"), autocomplete: "off", spellcheck: "false" });
25684
+ const input = h("input", { type: "text", class: "qc-search-input qc-picker-search", role: "searchbox", "aria-label": t("picker.search"), placeholder: t("picker.search"), autocomplete: "off", spellcheck: "false" });
25685
+ const clear = searchClear(deps.icons, t("search.clear"), () => {
25686
+ input.value = "";
25687
+ setQuery("");
25688
+ input.focus();
25689
+ });
25690
+ clear.hidden = true;
25691
+ const strip = h("div", { class: "qc-search-classes" });
25606
25692
  const nav = h("nav", { class: "qc-picker-nav", "aria-label": t("picker.collections") });
25607
25693
  const list = h("div", { class: "qc-picker-list", role: "table", "aria-label": t("picker.title") });
25608
25694
  const status2 = h("div", { class: "qc-picker-status qc-secondary", role: "status", "aria-live": "polite" });
25609
- const close = button2({ label: t("search.close"), icon: deps.icons.glyph(ICONS.dialogClose, { size: 18 }), className: "qc-dialog-close", onClick: () => dialog.close() });
25610
25695
  let pendingFocus = null;
25611
- const actionButton = (label3, content, run, disabled = false, focusKey) => {
25612
- const button3 = h("button", { type: "button", class: "qc-picker-action", "aria-label": label3, title: label3, "data-picker-focus": focusKey }, content ?? h("span", {}, label3));
25696
+ const actionButton = (label3, content, run, disabled = false, focusKey, className = "qc-picker-action") => {
25697
+ const button3 = h("button", { type: "button", class: className, "aria-label": label3, title: label3, "data-picker-focus": focusKey }, content ?? h("span", {}, label3));
25613
25698
  button3.disabled = disabled;
25614
25699
  button3.addEventListener("click", (event) => {
25615
25700
  event.stopPropagation();
@@ -25654,9 +25739,9 @@ function openIndicatorPicker(deps) {
25654
25739
  render();
25655
25740
  }
25656
25741
  };
25657
- const toggle = (kind, id, favorite, hosted) => {
25742
+ const toggle = (kind2, id, favorite, hosted) => {
25658
25743
  if (hosted) {
25659
- void act({ kind, id }, "favorite", !favorite);
25744
+ void act({ kind: kind2, id }, "favorite", !favorite);
25660
25745
  return;
25661
25746
  }
25662
25747
  favorites = favorite ? favorites.filter((value) => value !== id) : [...favorites, id];
@@ -25669,8 +25754,12 @@ function openIndicatorPicker(deps) {
25669
25754
  const buildRow = (options2) => {
25670
25755
  const row2 = h("div", { class: "qc-picker-row", role: "row" });
25671
25756
  const key = (action) => JSON.stringify([options2.kind, options2.id, action]);
25672
- const favoriteCell = h("div", { role: "cell" });
25673
- if (options2.favorite !== void 0) favoriteCell.append(actionButton(t(options2.favorite ? "picker.unfavorite" : "picker.favorite", { name: options2.title }), star(deps.icons, options2.favorite), () => toggle(options2.kind, options2.id, options2.favorite, options2.hostedFavorite === true), options2.hostedFavorite === true && (busy || loading) || !!source3 && !available, key("favorite")));
25757
+ const favoriteCell = h("div", { role: "cell", class: "qc-picker-star-cell" });
25758
+ if (options2.favorite !== void 0) {
25759
+ const toggleStar = actionButton(t(options2.favorite ? "picker.unfavorite" : "picker.favorite", { name: options2.title }), star(deps.icons, options2.favorite), () => toggle(options2.kind, options2.id, options2.favorite, options2.hostedFavorite === true), options2.hostedFavorite === true && (busy || loading) || !!source3 && !available, key("favorite"), "qc-picker-star");
25760
+ toggleStar.setAttribute("aria-pressed", String(options2.favorite));
25761
+ favoriteCell.append(toggleStar);
25762
+ }
25674
25763
  const label3 = options2.permitted ? options2.title : t("picker.notPermitted", { name: options2.title });
25675
25764
  const name2 = h("button", { type: "button", class: "qc-picker-name", "data-qc-item": "", tabindex: "-1", ...options2.builtin ? { "data-indicator": options2.id } : { "data-picker-item": options2.id }, "aria-label": options2.builtin && options2.permitted ? t("picker.add", { name: options2.title }) : label3, title: options2.description ?? label3 }, options2.title);
25676
25765
  name2.disabled = !options2.permitted;
@@ -25685,11 +25774,6 @@ function openIndicatorPicker(deps) {
25685
25774
  if (personal && rows2.items.find((item) => item.id === options2.id)?.primaryAction === action.id) continue;
25686
25775
  actions2.append(actionButton(action.label, hostIcon(action.icon), () => void act({ kind: options2.kind, id: options2.id }, action.id), busy || loading || action.disabled === true, key("action:" + action.id)));
25687
25776
  }
25688
- if (options2.builtin) {
25689
- const button3 = actionButton(t("picker.add", { name: options2.title }), plus(deps.icons), options2.primary, !options2.permitted, key("add"));
25690
- button3.dataset.pickerAdd = options2.id;
25691
- actions2.append(button3);
25692
- }
25693
25777
  const total2 = options2.count;
25694
25778
  const compact2 = total2 === void 0 ? 0 : total2 < 1e3 ? total2 : total2 < 1e4 ? Math.round(total2 / 100) / 10 : Math.round(total2 / 1e3);
25695
25779
  const count2 = total2 === void 0 ? "" : new Intl.NumberFormat(deps.i18n.tag()).format(compact2) + (total2 >= 1e3 ? t("picker.thousands") : "");
@@ -25699,27 +25783,31 @@ function openIndicatorPicker(deps) {
25699
25783
  });
25700
25784
  return row2;
25701
25785
  };
25786
+ const admitted = (rowKind) => kind === null || kind === rowKind;
25702
25787
  const render = () => {
25703
25788
  const focused = document.activeElement;
25704
25789
  if (focused && list.contains(focused)) pendingFocus = focused.dataset.pickerFocus ?? null;
25705
25790
  else if (focused && focused !== document.body) pendingFocus = null;
25706
25791
  const selected = (collections ?? []).find((row2) => row2.id === collection);
25707
25792
  list.classList.toggle("qc-picker-list--personal", selected?.layout === "list");
25793
+ list.classList.toggle("qc-picker-list--catalog", collection === "builtin");
25708
25794
  for (const button3 of nav.querySelectorAll("[data-picker-collection]")) button3.setAttribute("aria-pressed", String(button3.getAttribute("data-picker-collection") === collection));
25795
+ for (const chip of strip.querySelectorAll("[data-picker-kind]")) chip.setAttribute("aria-pressed", String((chip.getAttribute("data-picker-kind") || null) === kind));
25709
25796
  const headings = h("div", { role: "row", class: "qc-picker-headings" }, ...["", t("picker.name"), t("picker.author"), t("picker.favorites"), ""].map((label3) => h("span", { role: "columnheader" }, label3)));
25710
25797
  const body = h("div", { role: "rowgroup" });
25711
- if (collection === "builtin" || collection === "favorites") {
25798
+ if ((collection === "builtin" || collection === "favorites") && admitted(INDICATOR_KIND)) {
25712
25799
  for (const definition of filterDefinitions(t, query)) {
25713
25800
  const metadata = rows2.builtIns.find((row2) => row2.id === definition.id);
25714
25801
  const favorite = metadata?.favorite ?? favorites.includes(definition.id);
25715
25802
  if (collection === "favorites" && !favorite) continue;
25716
25803
  if (!offered(definition)) continue;
25717
25804
  if (!indicatorShown(deps.access, definition) || !commandShown(deps.access, "chart.indicators.add")) continue;
25718
- body.append(buildRow({ id: definition.id, kind: "builtin", title: t(definition.nameKey), description: t(definition.descriptionKey), author: t("picker.builtin"), favorite, count: metadata?.favoriteCount, hostedFavorite: metadata?.favorite !== void 0 || !!source3 && loading, actions: metadata?.actions ?? [], primary: () => add(definition), permitted: indicatorPermitted(deps.access, definition) && deps.commands.available("chart.indicators.add"), builtin: definition }));
25805
+ body.append(buildRow({ id: definition.id, kind: "builtin", title: t(definition.nameKey), description: t(definition.descriptionKey), favorite, count: metadata?.favoriteCount, hostedFavorite: metadata?.favorite !== void 0 || !!source3 && loading, actions: metadata?.actions ?? [], primary: () => add(definition), permitted: indicatorPermitted(deps.access, definition) && deps.commands.available("chart.indicators.add"), builtin: definition }));
25719
25806
  }
25720
25807
  }
25721
25808
  if (collection !== "builtin") for (const item of rows2.items) {
25722
25809
  if (collection === "favorites" && item.favorite !== true) continue;
25810
+ if (!admitted(item.kind ?? INDICATOR_KIND)) continue;
25723
25811
  const primary = item.actions.find((action) => action.id === item.primaryAction);
25724
25812
  body.append(buildRow({ id: item.id, kind: "item", title: item.title, description: item.description, author: item.author, favorite: item.favorite, count: item.favoriteCount, hostedFavorite: true, actions: item.actions, primary: () => void act({ kind: "item", id: item.id }, primary.id), permitted: !busy && !loading && !primary.disabled }));
25725
25813
  }
@@ -25753,7 +25841,7 @@ function openIndicatorPicker(deps) {
25753
25841
  try {
25754
25842
  const result = await source3.list({ collection, query, builtInIds: BUILT_IN_INDICATORS2.filter(offered).map((d) => d.id) }, pending.signal);
25755
25843
  if (!dialog.open() || revision !== generation) return;
25756
- const parsed = pickerRows(result);
25844
+ const parsed = pickerRows(result, (kinds ?? []).map((row2) => row2.id));
25757
25845
  if (parsed) {
25758
25846
  rows2 = parsed;
25759
25847
  available = true;
@@ -25767,25 +25855,47 @@ function openIndicatorPicker(deps) {
25767
25855
  }
25768
25856
  }
25769
25857
  };
25858
+ const setQuery = (next) => {
25859
+ query = next;
25860
+ clear.hidden = next === "";
25861
+ void refresh();
25862
+ };
25770
25863
  const renderNavigation = () => {
25771
25864
  replace(nav);
25772
- const navigation = [{ id: "favorites", label: t("picker.favorites"), group: t("picker.personal"), icon: null }, ...(collections ?? []).map((row2) => ({ ...row2, icon: hostIcon(row2.icon) })), { id: "builtin", label: t("picker.builtin"), group: "", icon: deps.icons.glyph(ICONS.indicators, { size: 28 }) }];
25865
+ const personal = t("picker.personal");
25866
+ const navigation = [{ id: "favorites", label: t("picker.favorites"), group: personal, icon: deps.icons.glyph(ICONS.pickerFavorites, { size: 28 }) }, ...(collections ?? []).map((row2) => ({ ...row2, icon: hostIcon(row2.icon) })), { id: "builtin", label: t("picker.technicals"), group: t("picker.builtin"), icon: deps.icons.glyph(ICONS.pickerTechnicals, { size: 28 }) }];
25867
+ let section = null;
25773
25868
  let group;
25774
25869
  for (const item of navigation) {
25775
- if (item.group && item.group !== group) nav.append(h("div", { class: "qc-picker-group" }, item.group));
25776
- group = item.group;
25777
- const button3 = h("button", { type: "button", class: "qc-picker-collection", "data-picker-collection": item.id }, item.id === "favorites" ? star(deps.icons, false) : item.icon, h("span", {}, item.label));
25870
+ if (!section || !!item.group && item.group !== group) {
25871
+ section = h("div", { class: "qc-picker-section" }, item.group ? h("div", { class: "qc-picker-group" }, item.group) : null);
25872
+ nav.append(section);
25873
+ group = item.group;
25874
+ }
25875
+ const button3 = h("button", { type: "button", class: "qc-picker-collection", "data-picker-collection": item.id }, h("span", { class: "qc-picker-collection-icon" }, item.icon), h("span", { class: "qc-picker-collection-label" }, item.label));
25778
25876
  button3.addEventListener("click", () => {
25779
25877
  collection = item.id;
25780
25878
  void refresh();
25781
25879
  });
25782
- nav.append(button3);
25880
+ section.append(button3);
25783
25881
  }
25784
25882
  };
25785
- input.addEventListener("input", () => {
25786
- query = input.value;
25787
- void refresh();
25788
- });
25883
+ const renderKinds = () => {
25884
+ const declared = kinds ?? [];
25885
+ if (kind !== null && kind !== INDICATOR_KIND && !declared.some((row2) => row2.id === kind)) kind = null;
25886
+ const group = h("div", { class: "qc-search-class-group", role: "group", "aria-label": t("picker.kindFilter") });
25887
+ for (const entry of [{ id: "", label: t("picker.allKinds") }, { id: INDICATOR_KIND, label: t("picker.indicators") }, ...declared]) {
25888
+ const chip = button2({ label: entry.label, text: entry.label, className: "qc-chip qc-search-class", pressed: (entry.id || null) === kind, onClick: () => {
25889
+ kind = entry.id || null;
25890
+ render();
25891
+ } });
25892
+ chip.dataset.pickerKind = entry.id;
25893
+ group.append(chip);
25894
+ }
25895
+ replace(strip, group);
25896
+ strip.hidden = declared.length === 0;
25897
+ };
25898
+ input.addEventListener("input", () => setQuery(input.value));
25789
25899
  input.addEventListener("keydown", (event) => {
25790
25900
  if (event.key === "ArrowDown" && roveFocus(list, event)) event.preventDefault();
25791
25901
  });
@@ -25795,27 +25905,21 @@ function openIndicatorPicker(deps) {
25795
25905
  input.focus();
25796
25906
  } else if (roveFocus(list, event)) event.preventDefault();
25797
25907
  });
25798
- box2.append(h("div", { class: "qc-picker-header" }, h("span", { class: "qc-title" }, t("picker.title")), close), h("div", { class: "qc-picker-searchbar" }, searchGlyph(deps.icons), input), h("div", { class: "qc-picker-body" }, nav, h("div", { class: "qc-picker-content" }, h("div", { class: "qc-picker-tabs" }, h("span", { class: "qc-picker-tab" }, t("picker.title"))), list, status2)));
25908
+ box2.append(searchField(deps.icons, input, clear), strip, h("div", { class: "qc-picker-body" }, nav, h("div", { class: "qc-picker-content" }, list, status2)));
25909
+ renderKinds();
25799
25910
  renderNavigation();
25800
25911
  redraw = render;
25801
25912
  offLocale = deps.i18n.onChange(() => {
25802
25913
  if (!dialog.open()) return;
25803
25914
  box2.setAttribute("aria-label", t("picker.title"));
25804
- box2.querySelector(".qc-title").textContent = t("picker.title");
25805
- box2.querySelector(".qc-picker-tab").textContent = t("picker.title");
25806
25915
  input.placeholder = t("picker.search");
25807
25916
  input.setAttribute("aria-label", t("picker.search"));
25808
- name(close, t("search.close"));
25917
+ name(clear, t("search.clear"));
25809
25918
  nav.setAttribute("aria-label", t("picker.collections"));
25810
25919
  list.setAttribute("aria-label", t("picker.title"));
25811
- try {
25812
- collections = source3 ? pickerCollections(source3.collections) : [];
25813
- hostValid = collections !== null && (!source3 || typeof source3.list === "function" && typeof source3.act === "function");
25814
- } catch {
25815
- collections = null;
25816
- hostValid = false;
25817
- }
25920
+ readHost();
25818
25921
  if (!["builtin", "favorites", ...(collections ?? []).map((row2) => row2.id)].includes(collection)) collection = "builtin";
25922
+ renderKinds();
25819
25923
  renderNavigation();
25820
25924
  void refresh();
25821
25925
  });
@@ -25994,7 +26098,7 @@ function buildSearchSurface(deps, box2, frame2) {
25994
26098
  };
25995
26099
  let scopeMarkDisposer = null;
25996
26100
  const input = h("input", { type: "text", role: "combobox", class: "qc-search-input", "aria-label": t("search.placeholder"), placeholder: t("search.placeholder"), autocomplete: "off", "aria-autocomplete": "list", "aria-expanded": "true", "aria-controls": listId, spellcheck: "false", value: query });
25997
- const clear = button2({ label: t("search.clear"), icon: deps.icons.glyph(ICONS.clear, { size: 18 }), className: "qc-search-op", onClick: () => setQuery("") });
26101
+ const clear = searchClear(deps.icons, t("search.clear"), () => setQuery(""));
25998
26102
  const rule = offerOps ? h("span", { class: "qc-search-rule", "aria-hidden": "true" }) : null;
25999
26103
  const showClear = (shown2) => {
26000
26104
  clear.hidden = !shown2;
@@ -26027,8 +26131,7 @@ function buildSearchSurface(deps, box2, frame2) {
26027
26131
  }
26028
26132
  setOps(opsOpen);
26029
26133
  }
26030
- const actions2 = h("span", { class: "qc-search-actions-field" }, clear, rule, offerOps ? ops : null, offerOps ? opsToggle : null);
26031
- const field = h("div", { class: "qc-search-field" }, deps.icons.glyph(ICONS.search, { size: 28, className: "qc-search-magnifier" }), input, actions2);
26134
+ const field = searchField(deps.icons, input, clear, rule, offerOps ? ops : null, offerOps ? opsToggle : null);
26032
26135
  const classes = compare ? null : deps.classes();
26033
26136
  const branches = classes ? classBranches(classes) : [];
26034
26137
  const allShown = display.allClasses !== false;
@@ -26185,9 +26288,9 @@ function buildSearchSurface(deps, box2, frame2) {
26185
26288
  }
26186
26289
  option.appendChild(source3);
26187
26290
  if (compare) {
26188
- const actions3 = h("span", { class: "qc-search-actions" });
26291
+ const actions2 = h("span", { class: "qc-search-actions" });
26189
26292
  for (const p of PLACEMENTS2) {
26190
- actions3.appendChild(
26293
+ actions2.appendChild(
26191
26294
  button2({
26192
26295
  label: t(p.label),
26193
26296
  text: t(p.label),
@@ -26199,7 +26302,7 @@ function buildSearchSurface(deps, box2, frame2) {
26199
26302
  })
26200
26303
  );
26201
26304
  }
26202
- option.appendChild(actions3);
26305
+ option.appendChild(actions2);
26203
26306
  }
26204
26307
  }
26205
26308
  option.addEventListener("click", () => act(entry));
@@ -29881,8 +29984,8 @@ function createChartSettingsDialog(deps) {
29881
29984
  role: "chart-settings",
29882
29985
  width: 750,
29883
29986
  veil: false,
29884
- passThrough: true,
29885
- // Escape, the close and the host's teardown end the session as the dialog begins to close.
29987
+ // Escape, the close, a press outside the dialog and the host's teardown end the session as
29988
+ // the dialog begins to close.
29886
29989
  onClosing: () => {
29887
29990
  if (s && !s.settled) cancel(s);
29888
29991
  },