@tradecanvas/chart 2.0.5 → 2.1.1

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 (88) hide show
  1. package/README.md +8 -6
  2. package/dist/{LayoutSession-Bo_I2x2W.cjs → LayoutSession-Ct9HkdF0.cjs} +2 -2
  3. package/dist/{LayoutSession-Bo_I2x2W.cjs.map → LayoutSession-Ct9HkdF0.cjs.map} +1 -1
  4. package/dist/{LayoutSession-CBhEZlOj.js → LayoutSession-DHPcgkw6.js} +2 -2
  5. package/dist/{LayoutSession-CBhEZlOj.js.map → LayoutSession-DHPcgkw6.js.map} +1 -1
  6. package/dist/{WidgetCommandPalette-DpP-lG1A.js → WidgetCommandPalette-BVctM_8J.js} +2 -2
  7. package/dist/{WidgetCommandPalette-DpP-lG1A.js.map → WidgetCommandPalette-BVctM_8J.js.map} +1 -1
  8. package/dist/{WidgetCommandPalette-CASDu1gu.cjs → WidgetCommandPalette-JODJV4O0.cjs} +2 -2
  9. package/dist/{WidgetCommandPalette-CASDu1gu.cjs.map → WidgetCommandPalette-JODJV4O0.cjs.map} +1 -1
  10. package/dist/{WidgetDrawingSettings-BpX4Cdys.cjs → WidgetDrawingSettings-C_xRMbdJ.cjs} +2 -2
  11. package/dist/{WidgetDrawingSettings-BpX4Cdys.cjs.map → WidgetDrawingSettings-C_xRMbdJ.cjs.map} +1 -1
  12. package/dist/{WidgetDrawingSettings-Cwds8CdJ.js → WidgetDrawingSettings-yGBoDk96.js} +2 -2
  13. package/dist/{WidgetDrawingSettings-Cwds8CdJ.js.map → WidgetDrawingSettings-yGBoDk96.js.map} +1 -1
  14. package/dist/{WidgetIndicatorPicker-DsFCT2xZ.js → WidgetIndicatorPicker-CRT8UrQM.js} +2 -2
  15. package/dist/{WidgetIndicatorPicker-DsFCT2xZ.js.map → WidgetIndicatorPicker-CRT8UrQM.js.map} +1 -1
  16. package/dist/{WidgetIndicatorPicker-CTK-2QvV.cjs → WidgetIndicatorPicker-Gk_Y8HzN.cjs} +2 -2
  17. package/dist/{WidgetIndicatorPicker-CTK-2QvV.cjs.map → WidgetIndicatorPicker-Gk_Y8HzN.cjs.map} +1 -1
  18. package/dist/{WidgetIndicatorSettings-DRt-E8Y_.cjs → WidgetIndicatorSettings-BWcklt1J.cjs} +2 -2
  19. package/dist/{WidgetIndicatorSettings-DRt-E8Y_.cjs.map → WidgetIndicatorSettings-BWcklt1J.cjs.map} +1 -1
  20. package/dist/{WidgetIndicatorSettings-D3W40Nud.js → WidgetIndicatorSettings-DRex0IML.js} +3 -3
  21. package/dist/{WidgetIndicatorSettings-D3W40Nud.js.map → WidgetIndicatorSettings-DRex0IML.js.map} +1 -1
  22. package/dist/{WidgetSettings-D0fnEBqC.cjs → WidgetSettings-Db2q4_8R.cjs} +2 -2
  23. package/dist/{WidgetSettings-D0fnEBqC.cjs.map → WidgetSettings-Db2q4_8R.cjs.map} +1 -1
  24. package/dist/{WidgetSettings-BsjEg-Dj.js → WidgetSettings-Dv0kLVtb.js} +2 -2
  25. package/dist/{WidgetSettings-BsjEg-Dj.js.map → WidgetSettings-Dv0kLVtb.js.map} +1 -1
  26. package/dist/{WidgetSymbolSearch-Cxxq4SrK.js → WidgetSymbolSearch-Bc5hW4Aa.js} +2 -2
  27. package/dist/{WidgetSymbolSearch-Cxxq4SrK.js.map → WidgetSymbolSearch-Bc5hW4Aa.js.map} +1 -1
  28. package/dist/{WidgetSymbolSearch-CTfNYC_m.cjs → WidgetSymbolSearch-GNc3wK8z.cjs} +2 -2
  29. package/dist/{WidgetSymbolSearch-CTfNYC_m.cjs.map → WidgetSymbolSearch-GNc3wK8z.cjs.map} +1 -1
  30. package/dist/i18n-CMgnJ3BI.cjs +2 -0
  31. package/dist/i18n-CMgnJ3BI.cjs.map +1 -0
  32. package/dist/{i18n-COYPJUtF.js → i18n-kIZPrAaD.js} +3 -1
  33. package/dist/i18n-kIZPrAaD.js.map +1 -0
  34. package/dist/index.cjs +1 -1
  35. package/dist/index.js +1 -1
  36. package/dist/{indicatorInputWords-DFmWy8Ah.js → indicatorInputWords-CaDGFQbW.js} +2 -2
  37. package/dist/{indicatorInputWords-DFmWy8Ah.js.map → indicatorInputWords-CaDGFQbW.js.map} +1 -1
  38. package/dist/{indicatorInputWords-hVKLYuVB.cjs → indicatorInputWords-DeBTBHV5.cjs} +2 -2
  39. package/dist/{indicatorInputWords-hVKLYuVB.cjs.map → indicatorInputWords-DeBTBHV5.cjs.map} +1 -1
  40. package/dist/widget/ChartWidget.d.ts +2 -0
  41. package/dist/widget/ChartWidget.d.ts.map +1 -1
  42. package/dist/widget/WidgetStatusBar.d.ts +1 -0
  43. package/dist/widget/WidgetStatusBar.d.ts.map +1 -1
  44. package/dist/widget/connectionStatus.d.ts +15 -0
  45. package/dist/widget/connectionStatus.d.ts.map +1 -0
  46. package/dist/widget/index.cjs +9 -3
  47. package/dist/widget/index.cjs.map +1 -1
  48. package/dist/widget/index.js +249 -232
  49. package/dist/widget/index.js.map +1 -1
  50. package/dist/widget/locales/ar.d.ts.map +1 -1
  51. package/dist/widget/locales/cs.d.ts.map +1 -1
  52. package/dist/widget/locales/da.d.ts.map +1 -1
  53. package/dist/widget/locales/de.d.ts.map +1 -1
  54. package/dist/widget/locales/el.d.ts.map +1 -1
  55. package/dist/widget/locales/en.d.ts +1 -0
  56. package/dist/widget/locales/en.d.ts.map +1 -1
  57. package/dist/widget/locales/es.d.ts.map +1 -1
  58. package/dist/widget/locales/et.d.ts.map +1 -1
  59. package/dist/widget/locales/fa.d.ts.map +1 -1
  60. package/dist/widget/locales/fr.d.ts.map +1 -1
  61. package/dist/widget/locales/he.d.ts.map +1 -1
  62. package/dist/widget/locales/hu.d.ts.map +1 -1
  63. package/dist/widget/locales/id.d.ts.map +1 -1
  64. package/dist/widget/locales/index.cjs +1 -1
  65. package/dist/widget/locales/index.cjs.map +1 -1
  66. package/dist/widget/locales/index.js +29 -1
  67. package/dist/widget/locales/index.js.map +1 -1
  68. package/dist/widget/locales/it.d.ts.map +1 -1
  69. package/dist/widget/locales/ja.d.ts.map +1 -1
  70. package/dist/widget/locales/ko.d.ts.map +1 -1
  71. package/dist/widget/locales/ms.d.ts.map +1 -1
  72. package/dist/widget/locales/nb.d.ts.map +1 -1
  73. package/dist/widget/locales/nl.d.ts.map +1 -1
  74. package/dist/widget/locales/pl.d.ts.map +1 -1
  75. package/dist/widget/locales/pt.d.ts.map +1 -1
  76. package/dist/widget/locales/ro.d.ts.map +1 -1
  77. package/dist/widget/locales/ru.d.ts.map +1 -1
  78. package/dist/widget/locales/sk.d.ts.map +1 -1
  79. package/dist/widget/locales/sv.d.ts.map +1 -1
  80. package/dist/widget/locales/th.d.ts.map +1 -1
  81. package/dist/widget/locales/tr.d.ts.map +1 -1
  82. package/dist/widget/locales/vi.d.ts.map +1 -1
  83. package/dist/widget/locales/zh.d.ts.map +1 -1
  84. package/dist/widget/locales/zhHant.d.ts.map +1 -1
  85. package/package.json +3 -3
  86. package/dist/i18n-COYPJUtF.js.map +0 -1
  87. package/dist/i18n-Q4mxL2mj.cjs +0 -2
  88. package/dist/i18n-Q4mxL2mj.cjs.map +0 -1
@@ -1,5 +1,5 @@
1
1
  import { i as e, n as t } from "./focusTrap-Br9Zfje0.js";
2
- import { t as n } from "./i18n-COYPJUtF.js";
2
+ import { t as n } from "./i18n-kIZPrAaD.js";
3
3
  import { n as r } from "./platformKeys-Dd1qOCjF.js";
4
4
  //#region src/widget/WidgetCommandPalette.ts
5
5
  var i = 5, a = 229, o = [
@@ -174,4 +174,4 @@ var u = 0, d = class {
174
174
  //#endregion
175
175
  export { d as WidgetCommandPalette };
176
176
 
177
- //# sourceMappingURL=WidgetCommandPalette-DpP-lG1A.js.map
177
+ //# sourceMappingURL=WidgetCommandPalette-BVctM_8J.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"WidgetCommandPalette-DpP-lG1A.js","names":[],"sources":["../src/widget/WidgetCommandPalette.ts"],"sourcesContent":["import type { ChartType, DrawingToolType, TimeFrame } from '@tradecanvas/commons';\nimport { EN_TRANSLATOR, type Translator } from './i18n.js';\nimport { createIcon } from './icons.js';\nimport { keepTabInside } from './focusTrap.js';\nimport { searchForm } from './platformKeys.js';\n\nexport interface CommandItem {\n id: string;\n label: string;\n category: CommandCategory;\n /** Its keys, written at the row's end (\"Alt+T\"). */\n shortcut?: string;\n /** On now (an indicator on the chart, the chart type in use): ticked. */\n active?: boolean;\n}\n\nexport type CommandCategory = 'indicator' | 'chartType' | 'drawing' | 'timeframe' | 'action';\n\nexport interface CommandPaletteCallbacks {\n onIndicator: (id: string) => void;\n onChartType: (type: ChartType) => void;\n onDrawingTool: (tool: DrawingToolType) => void;\n onTimeframe: (tf: TimeFrame) => void;\n onAction: (id: string) => void;\n onClose: () => void;\n}\n\n/** The commands used last, by `category:id`, newest first. */\nexport interface CommandRecents {\n list: () => readonly string[];\n add: (key: string) => void;\n}\n\n/** Commands used last, shown at the top before anything is typed. */\nconst RECENT_SHOWN = 5;\n/** The key code a browser gives a key an input method takes. */\nconst IME_KEY_CODE = 229;\n\n/** The widget's own commands first; the indicators, which have a dialog of their own, last. */\nconst CATEGORY_ORDER: readonly CommandCategory[] = ['action', 'drawing', 'chartType', 'timeframe', 'indicator'];\nconst CATEGORY_LABELS = {\n indicator: 'palette.group.indicator',\n chartType: 'palette.group.chartType',\n drawing: 'palette.group.drawing',\n timeframe: 'palette.group.timeframe',\n action: 'palette.group.action',\n} as const satisfies Record<CommandCategory, string>;\n\nconst keyOf = (item: CommandItem) => `${item.category}:${item.id}`;\n\n/**\n * How well `item` answers `query` (lower case, no spaces): its name or id\n * whole, then a name that starts with it, a word of the name that does, the\n * name holding it, its keys holding it (\"alt+t\"); 0 when nothing does.\n */\nfunction score(item: CommandItem, query: string): number {\n const label = item.label.toLowerCase();\n const flat = searchForm(label);\n if (item.id.toLowerCase() === query || flat === query) return 5;\n if (flat.startsWith(query)) return 4;\n if (label.split(/[\\s/()-]+/).some((word) => word.startsWith(query))) return 3;\n if (flat.includes(query) || item.id.toLowerCase().includes(query)) return 2;\n if (item.shortcut && searchForm(item.shortcut).includes(query)) return 1;\n return 0;\n}\n\ninterface Group {\n key: string;\n label: string;\n items: CommandItem[];\n}\n\nlet paletteSeq = 0;\n\n/**\n * The command palette (Ctrl+K): indicators, chart types, drawing tools,\n * intervals and the widget's own actions, in groups, with their keys. Before\n * anything is typed the commands used last come first. The keys stay in its\n * search: up and down move through the list, Enter runs a command.\n */\nexport class WidgetCommandPalette {\n private backdrop: HTMLDivElement | null = null;\n private input: HTMLInputElement | null = null;\n private list: HTMLDivElement | null = null;\n private emptyEl: HTMLDivElement | null = null;\n /** Says \"No results\" to a screen reader. */\n private liveEl: HTMLDivElement | null = null;\n private items: CommandItem[] = [];\n /** The rows on show, in order, for the keys. */\n private shown: CommandItem[] = [];\n private selectedIndex = 0;\n private returnFocus: HTMLElement | null = null;\n private readonly uid = ++paletteSeq;\n\n /** Where the overlay mounts (the widget's portal: themed, and inside it when fullscreen). */\n constructor(\n private readonly callbacks: CommandPaletteCallbacks,\n private readonly host: () => HTMLElement = () => document.body,\n private readonly t: Translator = EN_TRANSLATOR,\n private readonly recents?: CommandRecents,\n ) {}\n\n open(items: CommandItem[]): void {\n if (this.backdrop) return;\n this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n this.items = items;\n this.build();\n this.render();\n this.input?.focus();\n }\n\n close(): void {\n if (!this.backdrop) return;\n this.backdrop.remove();\n this.backdrop = this.input = this.list = this.emptyEl = this.liveEl = null;\n this.callbacks.onClose();\n const back = this.returnFocus;\n this.returnFocus = null;\n if (back?.isConnected) back.focus();\n }\n\n isOpen(): boolean {\n return this.backdrop !== null;\n }\n\n destroy(): void {\n this.close();\n }\n\n private build(): void {\n const backdrop = document.createElement('div');\n backdrop.className = 'tcw-modal-backdrop';\n // A press that starts in the palette and ends on the backdrop doesn't close it.\n let pressedBackdrop = false;\n backdrop.addEventListener('pointerdown', (e) => {\n pressedBackdrop = e.target === backdrop;\n });\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop && pressedBackdrop) this.close();\n pressedBackdrop = false;\n });\n\n const modal = document.createElement('div');\n modal.className = 'tcw-modal tcw-cp';\n modal.setAttribute('role', 'dialog');\n modal.setAttribute('aria-modal', 'true');\n modal.setAttribute('aria-label', this.t('hotkeys.commandPalette'));\n modal.tabIndex = -1;\n modal.addEventListener('keydown', (e) => this.onKeyDown(e, modal));\n\n const search = document.createElement('label');\n search.className = 'tcw-ss-search tcw-cp-search';\n search.innerHTML = createIcon('search', 16);\n const input = document.createElement('input');\n input.type = 'search';\n input.className = 'tcw-cp-input';\n input.placeholder = this.t('palette.placeholder');\n input.setAttribute('aria-label', this.t('palette.placeholder'));\n input.setAttribute('role', 'combobox');\n input.setAttribute('aria-expanded', 'true');\n input.setAttribute('aria-autocomplete', 'list');\n input.setAttribute('aria-controls', `tcw-cp-list-${this.uid}`);\n input.autocomplete = 'off';\n input.spellcheck = false;\n input.addEventListener('input', () => this.render());\n search.appendChild(input);\n\n const results = document.createElement('div');\n results.className = 'tcw-cp-results';\n const list = document.createElement('div');\n list.className = 'tcw-cp-list';\n list.id = `tcw-cp-list-${this.uid}`;\n list.setAttribute('role', 'listbox');\n list.setAttribute('aria-label', this.t('hotkeys.commandPalette'));\n const empty = document.createElement('div');\n empty.className = 'tcw-cp-empty';\n results.append(list, empty);\n // A press on a heading or between the rows keeps the keyboard in the search.\n results.addEventListener('mousedown', (e) => e.preventDefault());\n const live = document.createElement('div');\n live.className = 'tcw-cp-live tcw-visually-hidden';\n live.setAttribute('aria-live', 'polite');\n\n modal.append(search, results, live);\n backdrop.appendChild(modal);\n this.host().appendChild(backdrop);\n this.backdrop = backdrop;\n this.input = input;\n this.list = list;\n this.emptyEl = empty;\n this.liveEl = live;\n }\n\n /** The groups for what is typed: the commands used last first while nothing is, then each kind. */\n private groups(): Group[] {\n const query = searchForm((this.input?.value ?? '').trim());\n const groups: Group[] = [];\n if (!query) {\n const byKey = new Map(this.items.map((item) => [keyOf(item), item]));\n const recent = (this.recents?.list() ?? []).map((k) => byKey.get(k)).filter((i): i is CommandItem => !!i).slice(0, RECENT_SHOWN);\n if (recent.length > 0) groups.push({ key: 'recent', label: this.t('palette.group.recent'), items: recent });\n }\n for (const category of CATEGORY_ORDER) {\n let items = this.items.filter((item) => item.category === category);\n if (query) {\n items = items\n .map((item, at) => ({ item, at, s: score(item, query) }))\n .filter((r) => r.s > 0)\n .sort((a, b) => b.s - a.s || a.at - b.at)\n .map((r) => r.item);\n }\n if (items.length > 0) groups.push({ key: category, label: this.t(CATEGORY_LABELS[category]), items });\n }\n // Searching, the group with the best match comes first (the order above among equals).\n if (query) groups.sort((a, b) => score(b.items[0], query) - score(a.items[0], query));\n return groups;\n }\n\n private render(): void {\n const list = this.list;\n if (!list) return;\n const groups = this.groups();\n this.shown = groups.flatMap((g) => g.items);\n this.selectedIndex = 0;\n let index = 0;\n list.replaceChildren(...groups.map((group) => {\n const el = document.createElement('div');\n el.setAttribute('role', 'group');\n el.className = 'tcw-cp-group';\n const heading = document.createElement('div');\n heading.className = 'tcw-cp-heading';\n heading.id = `tcw-cp-${group.key}-${this.uid}`;\n heading.setAttribute('role', 'presentation');\n heading.textContent = group.label;\n el.setAttribute('aria-labelledby', heading.id);\n el.append(heading, ...group.items.map((item) => this.row(item, index++)));\n return el;\n }));\n const note = this.shown.length === 0 ? this.t('palette.empty') : '';\n if (this.emptyEl) this.emptyEl.textContent = note;\n this.emptyEl?.toggleAttribute('hidden', this.shown.length > 0);\n if (this.liveEl) this.liveEl.textContent = note;\n this.markSelection();\n }\n\n private row(item: CommandItem, index: number): HTMLDivElement {\n const row = document.createElement('div');\n row.className = 'tcw-cp-row';\n row.id = `tcw-cp-opt-${this.uid}-${index}`;\n row.dataset.id = item.id;\n row.setAttribute('role', 'option');\n row.classList.toggle('tcw-on', !!item.active);\n const label = document.createElement('span');\n label.className = 'tcw-cp-label';\n label.textContent = item.label;\n row.appendChild(label);\n if (item.shortcut) {\n const kbd = document.createElement('kbd');\n kbd.className = 'tcw-cp-key';\n // Keys read left to right in any widget: ⌘+P, never P+⌘.\n kbd.dir = 'ltr';\n kbd.textContent = item.shortcut;\n row.appendChild(kbd);\n }\n if (item.active) {\n const check = document.createElement('span');\n check.className = 'tcw-cp-check';\n check.innerHTML = createIcon('check', 14);\n row.appendChild(check);\n }\n row.addEventListener('click', () => this.run(index));\n row.addEventListener('mousemove', () => {\n if (this.selectedIndex === index) return;\n this.selectedIndex = index;\n this.markSelection();\n });\n return row;\n }\n\n private markSelection(): void {\n const rows = this.list?.querySelectorAll<HTMLElement>('.tcw-cp-row') ?? [];\n let active: HTMLElement | null = null;\n rows.forEach((el, i) => {\n const on = i === this.selectedIndex;\n el.setAttribute('aria-selected', String(on));\n el.classList.toggle('tcw-selected', on);\n if (on) active = el;\n });\n const row = active as HTMLElement | null;\n if (row) {\n this.input?.setAttribute('aria-activedescendant', row.id);\n row.scrollIntoView?.({ block: 'nearest' });\n } else {\n this.input?.removeAttribute('aria-activedescendant');\n }\n }\n\n private run(index: number): void {\n const item = this.shown[index];\n if (!item) return;\n this.recents?.add(keyOf(item));\n this.close();\n switch (item.category) {\n case 'indicator': this.callbacks.onIndicator(item.id); break;\n case 'chartType': this.callbacks.onChartType(item.id as ChartType); break;\n case 'drawing': this.callbacks.onDrawingTool(item.id as DrawingToolType); break;\n case 'timeframe': this.callbacks.onTimeframe(item.id as TimeFrame); break;\n case 'action': this.callbacks.onAction(item.id); break;\n }\n }\n\n private onKeyDown(e: KeyboardEvent, modal: HTMLElement): void {\n e.stopPropagation(); // keys here must not drive chart shortcuts\n // Enter, Escape and the arrows pick and close among an input method's candidates while it composes.\n if (e.isComposing || e.keyCode === IME_KEY_CODE) return;\n // Escape, and the key that opened it, shut it (the browser's own Ctrl+K kept away).\n const toggle = (e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'k';\n if (e.key === 'Escape' || toggle) {\n e.preventDefault();\n this.close();\n return;\n }\n keepTabInside(e, modal);\n if (e.target !== this.input) return;\n const count = this.shown.length;\n if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {\n e.preventDefault();\n if (count === 0) return;\n this.selectedIndex = (this.selectedIndex + (e.key === 'ArrowDown' ? 1 : -1) + count) % count;\n this.markSelection();\n } else if (e.key === 'Enter') {\n e.preventDefault();\n if (!e.repeat) this.run(this.selectedIndex);\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"WidgetCommandPalette-BVctM_8J.js","names":[],"sources":["../src/widget/WidgetCommandPalette.ts"],"sourcesContent":["import type { ChartType, DrawingToolType, TimeFrame } from '@tradecanvas/commons';\nimport { EN_TRANSLATOR, type Translator } from './i18n.js';\nimport { createIcon } from './icons.js';\nimport { keepTabInside } from './focusTrap.js';\nimport { searchForm } from './platformKeys.js';\n\nexport interface CommandItem {\n id: string;\n label: string;\n category: CommandCategory;\n /** Its keys, written at the row's end (\"Alt+T\"). */\n shortcut?: string;\n /** On now (an indicator on the chart, the chart type in use): ticked. */\n active?: boolean;\n}\n\nexport type CommandCategory = 'indicator' | 'chartType' | 'drawing' | 'timeframe' | 'action';\n\nexport interface CommandPaletteCallbacks {\n onIndicator: (id: string) => void;\n onChartType: (type: ChartType) => void;\n onDrawingTool: (tool: DrawingToolType) => void;\n onTimeframe: (tf: TimeFrame) => void;\n onAction: (id: string) => void;\n onClose: () => void;\n}\n\n/** The commands used last, by `category:id`, newest first. */\nexport interface CommandRecents {\n list: () => readonly string[];\n add: (key: string) => void;\n}\n\n/** Commands used last, shown at the top before anything is typed. */\nconst RECENT_SHOWN = 5;\n/** The key code a browser gives a key an input method takes. */\nconst IME_KEY_CODE = 229;\n\n/** The widget's own commands first; the indicators, which have a dialog of their own, last. */\nconst CATEGORY_ORDER: readonly CommandCategory[] = ['action', 'drawing', 'chartType', 'timeframe', 'indicator'];\nconst CATEGORY_LABELS = {\n indicator: 'palette.group.indicator',\n chartType: 'palette.group.chartType',\n drawing: 'palette.group.drawing',\n timeframe: 'palette.group.timeframe',\n action: 'palette.group.action',\n} as const satisfies Record<CommandCategory, string>;\n\nconst keyOf = (item: CommandItem) => `${item.category}:${item.id}`;\n\n/**\n * How well `item` answers `query` (lower case, no spaces): its name or id\n * whole, then a name that starts with it, a word of the name that does, the\n * name holding it, its keys holding it (\"alt+t\"); 0 when nothing does.\n */\nfunction score(item: CommandItem, query: string): number {\n const label = item.label.toLowerCase();\n const flat = searchForm(label);\n if (item.id.toLowerCase() === query || flat === query) return 5;\n if (flat.startsWith(query)) return 4;\n if (label.split(/[\\s/()-]+/).some((word) => word.startsWith(query))) return 3;\n if (flat.includes(query) || item.id.toLowerCase().includes(query)) return 2;\n if (item.shortcut && searchForm(item.shortcut).includes(query)) return 1;\n return 0;\n}\n\ninterface Group {\n key: string;\n label: string;\n items: CommandItem[];\n}\n\nlet paletteSeq = 0;\n\n/**\n * The command palette (Ctrl+K): indicators, chart types, drawing tools,\n * intervals and the widget's own actions, in groups, with their keys. Before\n * anything is typed the commands used last come first. The keys stay in its\n * search: up and down move through the list, Enter runs a command.\n */\nexport class WidgetCommandPalette {\n private backdrop: HTMLDivElement | null = null;\n private input: HTMLInputElement | null = null;\n private list: HTMLDivElement | null = null;\n private emptyEl: HTMLDivElement | null = null;\n /** Says \"No results\" to a screen reader. */\n private liveEl: HTMLDivElement | null = null;\n private items: CommandItem[] = [];\n /** The rows on show, in order, for the keys. */\n private shown: CommandItem[] = [];\n private selectedIndex = 0;\n private returnFocus: HTMLElement | null = null;\n private readonly uid = ++paletteSeq;\n\n /** Where the overlay mounts (the widget's portal: themed, and inside it when fullscreen). */\n constructor(\n private readonly callbacks: CommandPaletteCallbacks,\n private readonly host: () => HTMLElement = () => document.body,\n private readonly t: Translator = EN_TRANSLATOR,\n private readonly recents?: CommandRecents,\n ) {}\n\n open(items: CommandItem[]): void {\n if (this.backdrop) return;\n this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n this.items = items;\n this.build();\n this.render();\n this.input?.focus();\n }\n\n close(): void {\n if (!this.backdrop) return;\n this.backdrop.remove();\n this.backdrop = this.input = this.list = this.emptyEl = this.liveEl = null;\n this.callbacks.onClose();\n const back = this.returnFocus;\n this.returnFocus = null;\n if (back?.isConnected) back.focus();\n }\n\n isOpen(): boolean {\n return this.backdrop !== null;\n }\n\n destroy(): void {\n this.close();\n }\n\n private build(): void {\n const backdrop = document.createElement('div');\n backdrop.className = 'tcw-modal-backdrop';\n // A press that starts in the palette and ends on the backdrop doesn't close it.\n let pressedBackdrop = false;\n backdrop.addEventListener('pointerdown', (e) => {\n pressedBackdrop = e.target === backdrop;\n });\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop && pressedBackdrop) this.close();\n pressedBackdrop = false;\n });\n\n const modal = document.createElement('div');\n modal.className = 'tcw-modal tcw-cp';\n modal.setAttribute('role', 'dialog');\n modal.setAttribute('aria-modal', 'true');\n modal.setAttribute('aria-label', this.t('hotkeys.commandPalette'));\n modal.tabIndex = -1;\n modal.addEventListener('keydown', (e) => this.onKeyDown(e, modal));\n\n const search = document.createElement('label');\n search.className = 'tcw-ss-search tcw-cp-search';\n search.innerHTML = createIcon('search', 16);\n const input = document.createElement('input');\n input.type = 'search';\n input.className = 'tcw-cp-input';\n input.placeholder = this.t('palette.placeholder');\n input.setAttribute('aria-label', this.t('palette.placeholder'));\n input.setAttribute('role', 'combobox');\n input.setAttribute('aria-expanded', 'true');\n input.setAttribute('aria-autocomplete', 'list');\n input.setAttribute('aria-controls', `tcw-cp-list-${this.uid}`);\n input.autocomplete = 'off';\n input.spellcheck = false;\n input.addEventListener('input', () => this.render());\n search.appendChild(input);\n\n const results = document.createElement('div');\n results.className = 'tcw-cp-results';\n const list = document.createElement('div');\n list.className = 'tcw-cp-list';\n list.id = `tcw-cp-list-${this.uid}`;\n list.setAttribute('role', 'listbox');\n list.setAttribute('aria-label', this.t('hotkeys.commandPalette'));\n const empty = document.createElement('div');\n empty.className = 'tcw-cp-empty';\n results.append(list, empty);\n // A press on a heading or between the rows keeps the keyboard in the search.\n results.addEventListener('mousedown', (e) => e.preventDefault());\n const live = document.createElement('div');\n live.className = 'tcw-cp-live tcw-visually-hidden';\n live.setAttribute('aria-live', 'polite');\n\n modal.append(search, results, live);\n backdrop.appendChild(modal);\n this.host().appendChild(backdrop);\n this.backdrop = backdrop;\n this.input = input;\n this.list = list;\n this.emptyEl = empty;\n this.liveEl = live;\n }\n\n /** The groups for what is typed: the commands used last first while nothing is, then each kind. */\n private groups(): Group[] {\n const query = searchForm((this.input?.value ?? '').trim());\n const groups: Group[] = [];\n if (!query) {\n const byKey = new Map(this.items.map((item) => [keyOf(item), item]));\n const recent = (this.recents?.list() ?? []).map((k) => byKey.get(k)).filter((i): i is CommandItem => !!i).slice(0, RECENT_SHOWN);\n if (recent.length > 0) groups.push({ key: 'recent', label: this.t('palette.group.recent'), items: recent });\n }\n for (const category of CATEGORY_ORDER) {\n let items = this.items.filter((item) => item.category === category);\n if (query) {\n items = items\n .map((item, at) => ({ item, at, s: score(item, query) }))\n .filter((r) => r.s > 0)\n .sort((a, b) => b.s - a.s || a.at - b.at)\n .map((r) => r.item);\n }\n if (items.length > 0) groups.push({ key: category, label: this.t(CATEGORY_LABELS[category]), items });\n }\n // Searching, the group with the best match comes first (the order above among equals).\n if (query) groups.sort((a, b) => score(b.items[0], query) - score(a.items[0], query));\n return groups;\n }\n\n private render(): void {\n const list = this.list;\n if (!list) return;\n const groups = this.groups();\n this.shown = groups.flatMap((g) => g.items);\n this.selectedIndex = 0;\n let index = 0;\n list.replaceChildren(...groups.map((group) => {\n const el = document.createElement('div');\n el.setAttribute('role', 'group');\n el.className = 'tcw-cp-group';\n const heading = document.createElement('div');\n heading.className = 'tcw-cp-heading';\n heading.id = `tcw-cp-${group.key}-${this.uid}`;\n heading.setAttribute('role', 'presentation');\n heading.textContent = group.label;\n el.setAttribute('aria-labelledby', heading.id);\n el.append(heading, ...group.items.map((item) => this.row(item, index++)));\n return el;\n }));\n const note = this.shown.length === 0 ? this.t('palette.empty') : '';\n if (this.emptyEl) this.emptyEl.textContent = note;\n this.emptyEl?.toggleAttribute('hidden', this.shown.length > 0);\n if (this.liveEl) this.liveEl.textContent = note;\n this.markSelection();\n }\n\n private row(item: CommandItem, index: number): HTMLDivElement {\n const row = document.createElement('div');\n row.className = 'tcw-cp-row';\n row.id = `tcw-cp-opt-${this.uid}-${index}`;\n row.dataset.id = item.id;\n row.setAttribute('role', 'option');\n row.classList.toggle('tcw-on', !!item.active);\n const label = document.createElement('span');\n label.className = 'tcw-cp-label';\n label.textContent = item.label;\n row.appendChild(label);\n if (item.shortcut) {\n const kbd = document.createElement('kbd');\n kbd.className = 'tcw-cp-key';\n // Keys read left to right in any widget: ⌘+P, never P+⌘.\n kbd.dir = 'ltr';\n kbd.textContent = item.shortcut;\n row.appendChild(kbd);\n }\n if (item.active) {\n const check = document.createElement('span');\n check.className = 'tcw-cp-check';\n check.innerHTML = createIcon('check', 14);\n row.appendChild(check);\n }\n row.addEventListener('click', () => this.run(index));\n row.addEventListener('mousemove', () => {\n if (this.selectedIndex === index) return;\n this.selectedIndex = index;\n this.markSelection();\n });\n return row;\n }\n\n private markSelection(): void {\n const rows = this.list?.querySelectorAll<HTMLElement>('.tcw-cp-row') ?? [];\n let active: HTMLElement | null = null;\n rows.forEach((el, i) => {\n const on = i === this.selectedIndex;\n el.setAttribute('aria-selected', String(on));\n el.classList.toggle('tcw-selected', on);\n if (on) active = el;\n });\n const row = active as HTMLElement | null;\n if (row) {\n this.input?.setAttribute('aria-activedescendant', row.id);\n row.scrollIntoView?.({ block: 'nearest' });\n } else {\n this.input?.removeAttribute('aria-activedescendant');\n }\n }\n\n private run(index: number): void {\n const item = this.shown[index];\n if (!item) return;\n this.recents?.add(keyOf(item));\n this.close();\n switch (item.category) {\n case 'indicator': this.callbacks.onIndicator(item.id); break;\n case 'chartType': this.callbacks.onChartType(item.id as ChartType); break;\n case 'drawing': this.callbacks.onDrawingTool(item.id as DrawingToolType); break;\n case 'timeframe': this.callbacks.onTimeframe(item.id as TimeFrame); break;\n case 'action': this.callbacks.onAction(item.id); break;\n }\n }\n\n private onKeyDown(e: KeyboardEvent, modal: HTMLElement): void {\n e.stopPropagation(); // keys here must not drive chart shortcuts\n // Enter, Escape and the arrows pick and close among an input method's candidates while it composes.\n if (e.isComposing || e.keyCode === IME_KEY_CODE) return;\n // Escape, and the key that opened it, shut it (the browser's own Ctrl+K kept away).\n const toggle = (e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'k';\n if (e.key === 'Escape' || toggle) {\n e.preventDefault();\n this.close();\n return;\n }\n keepTabInside(e, modal);\n if (e.target !== this.input) return;\n const count = this.shown.length;\n if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {\n e.preventDefault();\n if (count === 0) return;\n this.selectedIndex = (this.selectedIndex + (e.key === 'ArrowDown' ? 1 : -1) + count) % count;\n this.markSelection();\n } else if (e.key === 'Enter') {\n e.preventDefault();\n if (!e.repeat) this.run(this.selectedIndex);\n }\n }\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require(`./focusTrap-DrhhmG0V.cjs`),t=require(`./i18n-Q4mxL2mj.cjs`),n=require(`./platformKeys-B82-j1Fs.cjs`);var r=5,i=229,a=[`action`,`drawing`,`chartType`,`timeframe`,`indicator`],o={indicator:`palette.group.indicator`,chartType:`palette.group.chartType`,drawing:`palette.group.drawing`,timeframe:`palette.group.timeframe`,action:`palette.group.action`},s=e=>`${e.category}:${e.id}`;function c(e,t){let r=e.label.toLowerCase(),i=n.n(r);return e.id.toLowerCase()===t||i===t?5:i.startsWith(t)?4:r.split(/[\s/()-]+/).some(e=>e.startsWith(t))?3:i.includes(t)||e.id.toLowerCase().includes(t)?2:e.shortcut&&n.n(e.shortcut).includes(t)?1:0}var l=0,u=class{backdrop=null;input=null;list=null;emptyEl=null;liveEl=null;items=[];shown=[];selectedIndex=0;returnFocus=null;uid=++l;constructor(e,n=()=>document.body,r=t.t,i){this.callbacks=e,this.host=n,this.t=r,this.recents=i}open(e){this.backdrop||(this.returnFocus=document.activeElement instanceof HTMLElement?document.activeElement:null,this.items=e,this.build(),this.render(),this.input?.focus())}close(){if(!this.backdrop)return;this.backdrop.remove(),this.backdrop=this.input=this.list=this.emptyEl=this.liveEl=null,this.callbacks.onClose();let e=this.returnFocus;this.returnFocus=null,e?.isConnected&&e.focus()}isOpen(){return this.backdrop!==null}destroy(){this.close()}build(){let t=document.createElement(`div`);t.className=`tcw-modal-backdrop`;let n=!1;t.addEventListener(`pointerdown`,e=>{n=e.target===t}),t.addEventListener(`click`,e=>{e.target===t&&n&&this.close(),n=!1});let r=document.createElement(`div`);r.className=`tcw-modal tcw-cp`,r.setAttribute(`role`,`dialog`),r.setAttribute(`aria-modal`,`true`),r.setAttribute(`aria-label`,this.t(`hotkeys.commandPalette`)),r.tabIndex=-1,r.addEventListener(`keydown`,e=>this.onKeyDown(e,r));let i=document.createElement(`label`);i.className=`tcw-ss-search tcw-cp-search`,i.innerHTML=e.i(`search`,16);let a=document.createElement(`input`);a.type=`search`,a.className=`tcw-cp-input`,a.placeholder=this.t(`palette.placeholder`),a.setAttribute(`aria-label`,this.t(`palette.placeholder`)),a.setAttribute(`role`,`combobox`),a.setAttribute(`aria-expanded`,`true`),a.setAttribute(`aria-autocomplete`,`list`),a.setAttribute(`aria-controls`,`tcw-cp-list-${this.uid}`),a.autocomplete=`off`,a.spellcheck=!1,a.addEventListener(`input`,()=>this.render()),i.appendChild(a);let o=document.createElement(`div`);o.className=`tcw-cp-results`;let s=document.createElement(`div`);s.className=`tcw-cp-list`,s.id=`tcw-cp-list-${this.uid}`,s.setAttribute(`role`,`listbox`),s.setAttribute(`aria-label`,this.t(`hotkeys.commandPalette`));let c=document.createElement(`div`);c.className=`tcw-cp-empty`,o.append(s,c),o.addEventListener(`mousedown`,e=>e.preventDefault());let l=document.createElement(`div`);l.className=`tcw-cp-live tcw-visually-hidden`,l.setAttribute(`aria-live`,`polite`),r.append(i,o,l),t.appendChild(r),this.host().appendChild(t),this.backdrop=t,this.input=a,this.list=s,this.emptyEl=c,this.liveEl=l}groups(){let e=n.n((this.input?.value??``).trim()),t=[];if(!e){let e=new Map(this.items.map(e=>[s(e),e])),n=(this.recents?.list()??[]).map(t=>e.get(t)).filter(e=>!!e).slice(0,r);n.length>0&&t.push({key:`recent`,label:this.t(`palette.group.recent`),items:n})}for(let n of a){let r=this.items.filter(e=>e.category===n);e&&(r=r.map((t,n)=>({item:t,at:n,s:c(t,e)})).filter(e=>e.s>0).sort((e,t)=>t.s-e.s||e.at-t.at).map(e=>e.item)),r.length>0&&t.push({key:n,label:this.t(o[n]),items:r})}return e&&t.sort((t,n)=>c(n.items[0],e)-c(t.items[0],e)),t}render(){let e=this.list;if(!e)return;let t=this.groups();this.shown=t.flatMap(e=>e.items),this.selectedIndex=0;let n=0;e.replaceChildren(...t.map(e=>{let t=document.createElement(`div`);t.setAttribute(`role`,`group`),t.className=`tcw-cp-group`;let r=document.createElement(`div`);return r.className=`tcw-cp-heading`,r.id=`tcw-cp-${e.key}-${this.uid}`,r.setAttribute(`role`,`presentation`),r.textContent=e.label,t.setAttribute(`aria-labelledby`,r.id),t.append(r,...e.items.map(e=>this.row(e,n++))),t}));let r=this.shown.length===0?this.t(`palette.empty`):``;this.emptyEl&&(this.emptyEl.textContent=r),this.emptyEl?.toggleAttribute(`hidden`,this.shown.length>0),this.liveEl&&(this.liveEl.textContent=r),this.markSelection()}row(t,n){let r=document.createElement(`div`);r.className=`tcw-cp-row`,r.id=`tcw-cp-opt-${this.uid}-${n}`,r.dataset.id=t.id,r.setAttribute(`role`,`option`),r.classList.toggle(`tcw-on`,!!t.active);let i=document.createElement(`span`);if(i.className=`tcw-cp-label`,i.textContent=t.label,r.appendChild(i),t.shortcut){let e=document.createElement(`kbd`);e.className=`tcw-cp-key`,e.dir=`ltr`,e.textContent=t.shortcut,r.appendChild(e)}if(t.active){let t=document.createElement(`span`);t.className=`tcw-cp-check`,t.innerHTML=e.i(`check`,14),r.appendChild(t)}return r.addEventListener(`click`,()=>this.run(n)),r.addEventListener(`mousemove`,()=>{this.selectedIndex!==n&&(this.selectedIndex=n,this.markSelection())}),r}markSelection(){let e=this.list?.querySelectorAll(`.tcw-cp-row`)??[],t=null;e.forEach((e,n)=>{let r=n===this.selectedIndex;e.setAttribute(`aria-selected`,String(r)),e.classList.toggle(`tcw-selected`,r),r&&(t=e)});let n=t;n?(this.input?.setAttribute(`aria-activedescendant`,n.id),n.scrollIntoView?.({block:`nearest`})):this.input?.removeAttribute(`aria-activedescendant`)}run(e){let t=this.shown[e];if(t)switch(this.recents?.add(s(t)),this.close(),t.category){case`indicator`:this.callbacks.onIndicator(t.id);break;case`chartType`:this.callbacks.onChartType(t.id);break;case`drawing`:this.callbacks.onDrawingTool(t.id);break;case`timeframe`:this.callbacks.onTimeframe(t.id);break;case`action`:this.callbacks.onAction(t.id);break}}onKeyDown(t,n){if(t.stopPropagation(),t.isComposing||t.keyCode===i)return;let r=(t.ctrlKey||t.metaKey)&&t.key.toLowerCase()===`k`;if(t.key===`Escape`||r){t.preventDefault(),this.close();return}if(e.n(t,n),t.target!==this.input)return;let a=this.shown.length;if(t.key===`ArrowDown`||t.key===`ArrowUp`){if(t.preventDefault(),a===0)return;this.selectedIndex=(this.selectedIndex+(t.key===`ArrowDown`?1:-1)+a)%a,this.markSelection()}else t.key===`Enter`&&(t.preventDefault(),t.repeat||this.run(this.selectedIndex))}};exports.WidgetCommandPalette=u;
2
- //# sourceMappingURL=WidgetCommandPalette-CASDu1gu.cjs.map
1
+ const e=require(`./focusTrap-DrhhmG0V.cjs`),t=require(`./i18n-CMgnJ3BI.cjs`),n=require(`./platformKeys-B82-j1Fs.cjs`);var r=5,i=229,a=[`action`,`drawing`,`chartType`,`timeframe`,`indicator`],o={indicator:`palette.group.indicator`,chartType:`palette.group.chartType`,drawing:`palette.group.drawing`,timeframe:`palette.group.timeframe`,action:`palette.group.action`},s=e=>`${e.category}:${e.id}`;function c(e,t){let r=e.label.toLowerCase(),i=n.n(r);return e.id.toLowerCase()===t||i===t?5:i.startsWith(t)?4:r.split(/[\s/()-]+/).some(e=>e.startsWith(t))?3:i.includes(t)||e.id.toLowerCase().includes(t)?2:e.shortcut&&n.n(e.shortcut).includes(t)?1:0}var l=0,u=class{backdrop=null;input=null;list=null;emptyEl=null;liveEl=null;items=[];shown=[];selectedIndex=0;returnFocus=null;uid=++l;constructor(e,n=()=>document.body,r=t.t,i){this.callbacks=e,this.host=n,this.t=r,this.recents=i}open(e){this.backdrop||(this.returnFocus=document.activeElement instanceof HTMLElement?document.activeElement:null,this.items=e,this.build(),this.render(),this.input?.focus())}close(){if(!this.backdrop)return;this.backdrop.remove(),this.backdrop=this.input=this.list=this.emptyEl=this.liveEl=null,this.callbacks.onClose();let e=this.returnFocus;this.returnFocus=null,e?.isConnected&&e.focus()}isOpen(){return this.backdrop!==null}destroy(){this.close()}build(){let t=document.createElement(`div`);t.className=`tcw-modal-backdrop`;let n=!1;t.addEventListener(`pointerdown`,e=>{n=e.target===t}),t.addEventListener(`click`,e=>{e.target===t&&n&&this.close(),n=!1});let r=document.createElement(`div`);r.className=`tcw-modal tcw-cp`,r.setAttribute(`role`,`dialog`),r.setAttribute(`aria-modal`,`true`),r.setAttribute(`aria-label`,this.t(`hotkeys.commandPalette`)),r.tabIndex=-1,r.addEventListener(`keydown`,e=>this.onKeyDown(e,r));let i=document.createElement(`label`);i.className=`tcw-ss-search tcw-cp-search`,i.innerHTML=e.i(`search`,16);let a=document.createElement(`input`);a.type=`search`,a.className=`tcw-cp-input`,a.placeholder=this.t(`palette.placeholder`),a.setAttribute(`aria-label`,this.t(`palette.placeholder`)),a.setAttribute(`role`,`combobox`),a.setAttribute(`aria-expanded`,`true`),a.setAttribute(`aria-autocomplete`,`list`),a.setAttribute(`aria-controls`,`tcw-cp-list-${this.uid}`),a.autocomplete=`off`,a.spellcheck=!1,a.addEventListener(`input`,()=>this.render()),i.appendChild(a);let o=document.createElement(`div`);o.className=`tcw-cp-results`;let s=document.createElement(`div`);s.className=`tcw-cp-list`,s.id=`tcw-cp-list-${this.uid}`,s.setAttribute(`role`,`listbox`),s.setAttribute(`aria-label`,this.t(`hotkeys.commandPalette`));let c=document.createElement(`div`);c.className=`tcw-cp-empty`,o.append(s,c),o.addEventListener(`mousedown`,e=>e.preventDefault());let l=document.createElement(`div`);l.className=`tcw-cp-live tcw-visually-hidden`,l.setAttribute(`aria-live`,`polite`),r.append(i,o,l),t.appendChild(r),this.host().appendChild(t),this.backdrop=t,this.input=a,this.list=s,this.emptyEl=c,this.liveEl=l}groups(){let e=n.n((this.input?.value??``).trim()),t=[];if(!e){let e=new Map(this.items.map(e=>[s(e),e])),n=(this.recents?.list()??[]).map(t=>e.get(t)).filter(e=>!!e).slice(0,r);n.length>0&&t.push({key:`recent`,label:this.t(`palette.group.recent`),items:n})}for(let n of a){let r=this.items.filter(e=>e.category===n);e&&(r=r.map((t,n)=>({item:t,at:n,s:c(t,e)})).filter(e=>e.s>0).sort((e,t)=>t.s-e.s||e.at-t.at).map(e=>e.item)),r.length>0&&t.push({key:n,label:this.t(o[n]),items:r})}return e&&t.sort((t,n)=>c(n.items[0],e)-c(t.items[0],e)),t}render(){let e=this.list;if(!e)return;let t=this.groups();this.shown=t.flatMap(e=>e.items),this.selectedIndex=0;let n=0;e.replaceChildren(...t.map(e=>{let t=document.createElement(`div`);t.setAttribute(`role`,`group`),t.className=`tcw-cp-group`;let r=document.createElement(`div`);return r.className=`tcw-cp-heading`,r.id=`tcw-cp-${e.key}-${this.uid}`,r.setAttribute(`role`,`presentation`),r.textContent=e.label,t.setAttribute(`aria-labelledby`,r.id),t.append(r,...e.items.map(e=>this.row(e,n++))),t}));let r=this.shown.length===0?this.t(`palette.empty`):``;this.emptyEl&&(this.emptyEl.textContent=r),this.emptyEl?.toggleAttribute(`hidden`,this.shown.length>0),this.liveEl&&(this.liveEl.textContent=r),this.markSelection()}row(t,n){let r=document.createElement(`div`);r.className=`tcw-cp-row`,r.id=`tcw-cp-opt-${this.uid}-${n}`,r.dataset.id=t.id,r.setAttribute(`role`,`option`),r.classList.toggle(`tcw-on`,!!t.active);let i=document.createElement(`span`);if(i.className=`tcw-cp-label`,i.textContent=t.label,r.appendChild(i),t.shortcut){let e=document.createElement(`kbd`);e.className=`tcw-cp-key`,e.dir=`ltr`,e.textContent=t.shortcut,r.appendChild(e)}if(t.active){let t=document.createElement(`span`);t.className=`tcw-cp-check`,t.innerHTML=e.i(`check`,14),r.appendChild(t)}return r.addEventListener(`click`,()=>this.run(n)),r.addEventListener(`mousemove`,()=>{this.selectedIndex!==n&&(this.selectedIndex=n,this.markSelection())}),r}markSelection(){let e=this.list?.querySelectorAll(`.tcw-cp-row`)??[],t=null;e.forEach((e,n)=>{let r=n===this.selectedIndex;e.setAttribute(`aria-selected`,String(r)),e.classList.toggle(`tcw-selected`,r),r&&(t=e)});let n=t;n?(this.input?.setAttribute(`aria-activedescendant`,n.id),n.scrollIntoView?.({block:`nearest`})):this.input?.removeAttribute(`aria-activedescendant`)}run(e){let t=this.shown[e];if(t)switch(this.recents?.add(s(t)),this.close(),t.category){case`indicator`:this.callbacks.onIndicator(t.id);break;case`chartType`:this.callbacks.onChartType(t.id);break;case`drawing`:this.callbacks.onDrawingTool(t.id);break;case`timeframe`:this.callbacks.onTimeframe(t.id);break;case`action`:this.callbacks.onAction(t.id);break}}onKeyDown(t,n){if(t.stopPropagation(),t.isComposing||t.keyCode===i)return;let r=(t.ctrlKey||t.metaKey)&&t.key.toLowerCase()===`k`;if(t.key===`Escape`||r){t.preventDefault(),this.close();return}if(e.n(t,n),t.target!==this.input)return;let a=this.shown.length;if(t.key===`ArrowDown`||t.key===`ArrowUp`){if(t.preventDefault(),a===0)return;this.selectedIndex=(this.selectedIndex+(t.key===`ArrowDown`?1:-1)+a)%a,this.markSelection()}else t.key===`Enter`&&(t.preventDefault(),t.repeat||this.run(this.selectedIndex))}};exports.WidgetCommandPalette=u;
2
+ //# sourceMappingURL=WidgetCommandPalette-JODJV4O0.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"WidgetCommandPalette-CASDu1gu.cjs","names":[],"sources":["../src/widget/WidgetCommandPalette.ts"],"sourcesContent":["import type { ChartType, DrawingToolType, TimeFrame } from '@tradecanvas/commons';\nimport { EN_TRANSLATOR, type Translator } from './i18n.js';\nimport { createIcon } from './icons.js';\nimport { keepTabInside } from './focusTrap.js';\nimport { searchForm } from './platformKeys.js';\n\nexport interface CommandItem {\n id: string;\n label: string;\n category: CommandCategory;\n /** Its keys, written at the row's end (\"Alt+T\"). */\n shortcut?: string;\n /** On now (an indicator on the chart, the chart type in use): ticked. */\n active?: boolean;\n}\n\nexport type CommandCategory = 'indicator' | 'chartType' | 'drawing' | 'timeframe' | 'action';\n\nexport interface CommandPaletteCallbacks {\n onIndicator: (id: string) => void;\n onChartType: (type: ChartType) => void;\n onDrawingTool: (tool: DrawingToolType) => void;\n onTimeframe: (tf: TimeFrame) => void;\n onAction: (id: string) => void;\n onClose: () => void;\n}\n\n/** The commands used last, by `category:id`, newest first. */\nexport interface CommandRecents {\n list: () => readonly string[];\n add: (key: string) => void;\n}\n\n/** Commands used last, shown at the top before anything is typed. */\nconst RECENT_SHOWN = 5;\n/** The key code a browser gives a key an input method takes. */\nconst IME_KEY_CODE = 229;\n\n/** The widget's own commands first; the indicators, which have a dialog of their own, last. */\nconst CATEGORY_ORDER: readonly CommandCategory[] = ['action', 'drawing', 'chartType', 'timeframe', 'indicator'];\nconst CATEGORY_LABELS = {\n indicator: 'palette.group.indicator',\n chartType: 'palette.group.chartType',\n drawing: 'palette.group.drawing',\n timeframe: 'palette.group.timeframe',\n action: 'palette.group.action',\n} as const satisfies Record<CommandCategory, string>;\n\nconst keyOf = (item: CommandItem) => `${item.category}:${item.id}`;\n\n/**\n * How well `item` answers `query` (lower case, no spaces): its name or id\n * whole, then a name that starts with it, a word of the name that does, the\n * name holding it, its keys holding it (\"alt+t\"); 0 when nothing does.\n */\nfunction score(item: CommandItem, query: string): number {\n const label = item.label.toLowerCase();\n const flat = searchForm(label);\n if (item.id.toLowerCase() === query || flat === query) return 5;\n if (flat.startsWith(query)) return 4;\n if (label.split(/[\\s/()-]+/).some((word) => word.startsWith(query))) return 3;\n if (flat.includes(query) || item.id.toLowerCase().includes(query)) return 2;\n if (item.shortcut && searchForm(item.shortcut).includes(query)) return 1;\n return 0;\n}\n\ninterface Group {\n key: string;\n label: string;\n items: CommandItem[];\n}\n\nlet paletteSeq = 0;\n\n/**\n * The command palette (Ctrl+K): indicators, chart types, drawing tools,\n * intervals and the widget's own actions, in groups, with their keys. Before\n * anything is typed the commands used last come first. The keys stay in its\n * search: up and down move through the list, Enter runs a command.\n */\nexport class WidgetCommandPalette {\n private backdrop: HTMLDivElement | null = null;\n private input: HTMLInputElement | null = null;\n private list: HTMLDivElement | null = null;\n private emptyEl: HTMLDivElement | null = null;\n /** Says \"No results\" to a screen reader. */\n private liveEl: HTMLDivElement | null = null;\n private items: CommandItem[] = [];\n /** The rows on show, in order, for the keys. */\n private shown: CommandItem[] = [];\n private selectedIndex = 0;\n private returnFocus: HTMLElement | null = null;\n private readonly uid = ++paletteSeq;\n\n /** Where the overlay mounts (the widget's portal: themed, and inside it when fullscreen). */\n constructor(\n private readonly callbacks: CommandPaletteCallbacks,\n private readonly host: () => HTMLElement = () => document.body,\n private readonly t: Translator = EN_TRANSLATOR,\n private readonly recents?: CommandRecents,\n ) {}\n\n open(items: CommandItem[]): void {\n if (this.backdrop) return;\n this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n this.items = items;\n this.build();\n this.render();\n this.input?.focus();\n }\n\n close(): void {\n if (!this.backdrop) return;\n this.backdrop.remove();\n this.backdrop = this.input = this.list = this.emptyEl = this.liveEl = null;\n this.callbacks.onClose();\n const back = this.returnFocus;\n this.returnFocus = null;\n if (back?.isConnected) back.focus();\n }\n\n isOpen(): boolean {\n return this.backdrop !== null;\n }\n\n destroy(): void {\n this.close();\n }\n\n private build(): void {\n const backdrop = document.createElement('div');\n backdrop.className = 'tcw-modal-backdrop';\n // A press that starts in the palette and ends on the backdrop doesn't close it.\n let pressedBackdrop = false;\n backdrop.addEventListener('pointerdown', (e) => {\n pressedBackdrop = e.target === backdrop;\n });\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop && pressedBackdrop) this.close();\n pressedBackdrop = false;\n });\n\n const modal = document.createElement('div');\n modal.className = 'tcw-modal tcw-cp';\n modal.setAttribute('role', 'dialog');\n modal.setAttribute('aria-modal', 'true');\n modal.setAttribute('aria-label', this.t('hotkeys.commandPalette'));\n modal.tabIndex = -1;\n modal.addEventListener('keydown', (e) => this.onKeyDown(e, modal));\n\n const search = document.createElement('label');\n search.className = 'tcw-ss-search tcw-cp-search';\n search.innerHTML = createIcon('search', 16);\n const input = document.createElement('input');\n input.type = 'search';\n input.className = 'tcw-cp-input';\n input.placeholder = this.t('palette.placeholder');\n input.setAttribute('aria-label', this.t('palette.placeholder'));\n input.setAttribute('role', 'combobox');\n input.setAttribute('aria-expanded', 'true');\n input.setAttribute('aria-autocomplete', 'list');\n input.setAttribute('aria-controls', `tcw-cp-list-${this.uid}`);\n input.autocomplete = 'off';\n input.spellcheck = false;\n input.addEventListener('input', () => this.render());\n search.appendChild(input);\n\n const results = document.createElement('div');\n results.className = 'tcw-cp-results';\n const list = document.createElement('div');\n list.className = 'tcw-cp-list';\n list.id = `tcw-cp-list-${this.uid}`;\n list.setAttribute('role', 'listbox');\n list.setAttribute('aria-label', this.t('hotkeys.commandPalette'));\n const empty = document.createElement('div');\n empty.className = 'tcw-cp-empty';\n results.append(list, empty);\n // A press on a heading or between the rows keeps the keyboard in the search.\n results.addEventListener('mousedown', (e) => e.preventDefault());\n const live = document.createElement('div');\n live.className = 'tcw-cp-live tcw-visually-hidden';\n live.setAttribute('aria-live', 'polite');\n\n modal.append(search, results, live);\n backdrop.appendChild(modal);\n this.host().appendChild(backdrop);\n this.backdrop = backdrop;\n this.input = input;\n this.list = list;\n this.emptyEl = empty;\n this.liveEl = live;\n }\n\n /** The groups for what is typed: the commands used last first while nothing is, then each kind. */\n private groups(): Group[] {\n const query = searchForm((this.input?.value ?? '').trim());\n const groups: Group[] = [];\n if (!query) {\n const byKey = new Map(this.items.map((item) => [keyOf(item), item]));\n const recent = (this.recents?.list() ?? []).map((k) => byKey.get(k)).filter((i): i is CommandItem => !!i).slice(0, RECENT_SHOWN);\n if (recent.length > 0) groups.push({ key: 'recent', label: this.t('palette.group.recent'), items: recent });\n }\n for (const category of CATEGORY_ORDER) {\n let items = this.items.filter((item) => item.category === category);\n if (query) {\n items = items\n .map((item, at) => ({ item, at, s: score(item, query) }))\n .filter((r) => r.s > 0)\n .sort((a, b) => b.s - a.s || a.at - b.at)\n .map((r) => r.item);\n }\n if (items.length > 0) groups.push({ key: category, label: this.t(CATEGORY_LABELS[category]), items });\n }\n // Searching, the group with the best match comes first (the order above among equals).\n if (query) groups.sort((a, b) => score(b.items[0], query) - score(a.items[0], query));\n return groups;\n }\n\n private render(): void {\n const list = this.list;\n if (!list) return;\n const groups = this.groups();\n this.shown = groups.flatMap((g) => g.items);\n this.selectedIndex = 0;\n let index = 0;\n list.replaceChildren(...groups.map((group) => {\n const el = document.createElement('div');\n el.setAttribute('role', 'group');\n el.className = 'tcw-cp-group';\n const heading = document.createElement('div');\n heading.className = 'tcw-cp-heading';\n heading.id = `tcw-cp-${group.key}-${this.uid}`;\n heading.setAttribute('role', 'presentation');\n heading.textContent = group.label;\n el.setAttribute('aria-labelledby', heading.id);\n el.append(heading, ...group.items.map((item) => this.row(item, index++)));\n return el;\n }));\n const note = this.shown.length === 0 ? this.t('palette.empty') : '';\n if (this.emptyEl) this.emptyEl.textContent = note;\n this.emptyEl?.toggleAttribute('hidden', this.shown.length > 0);\n if (this.liveEl) this.liveEl.textContent = note;\n this.markSelection();\n }\n\n private row(item: CommandItem, index: number): HTMLDivElement {\n const row = document.createElement('div');\n row.className = 'tcw-cp-row';\n row.id = `tcw-cp-opt-${this.uid}-${index}`;\n row.dataset.id = item.id;\n row.setAttribute('role', 'option');\n row.classList.toggle('tcw-on', !!item.active);\n const label = document.createElement('span');\n label.className = 'tcw-cp-label';\n label.textContent = item.label;\n row.appendChild(label);\n if (item.shortcut) {\n const kbd = document.createElement('kbd');\n kbd.className = 'tcw-cp-key';\n // Keys read left to right in any widget: ⌘+P, never P+⌘.\n kbd.dir = 'ltr';\n kbd.textContent = item.shortcut;\n row.appendChild(kbd);\n }\n if (item.active) {\n const check = document.createElement('span');\n check.className = 'tcw-cp-check';\n check.innerHTML = createIcon('check', 14);\n row.appendChild(check);\n }\n row.addEventListener('click', () => this.run(index));\n row.addEventListener('mousemove', () => {\n if (this.selectedIndex === index) return;\n this.selectedIndex = index;\n this.markSelection();\n });\n return row;\n }\n\n private markSelection(): void {\n const rows = this.list?.querySelectorAll<HTMLElement>('.tcw-cp-row') ?? [];\n let active: HTMLElement | null = null;\n rows.forEach((el, i) => {\n const on = i === this.selectedIndex;\n el.setAttribute('aria-selected', String(on));\n el.classList.toggle('tcw-selected', on);\n if (on) active = el;\n });\n const row = active as HTMLElement | null;\n if (row) {\n this.input?.setAttribute('aria-activedescendant', row.id);\n row.scrollIntoView?.({ block: 'nearest' });\n } else {\n this.input?.removeAttribute('aria-activedescendant');\n }\n }\n\n private run(index: number): void {\n const item = this.shown[index];\n if (!item) return;\n this.recents?.add(keyOf(item));\n this.close();\n switch (item.category) {\n case 'indicator': this.callbacks.onIndicator(item.id); break;\n case 'chartType': this.callbacks.onChartType(item.id as ChartType); break;\n case 'drawing': this.callbacks.onDrawingTool(item.id as DrawingToolType); break;\n case 'timeframe': this.callbacks.onTimeframe(item.id as TimeFrame); break;\n case 'action': this.callbacks.onAction(item.id); break;\n }\n }\n\n private onKeyDown(e: KeyboardEvent, modal: HTMLElement): void {\n e.stopPropagation(); // keys here must not drive chart shortcuts\n // Enter, Escape and the arrows pick and close among an input method's candidates while it composes.\n if (e.isComposing || e.keyCode === IME_KEY_CODE) return;\n // Escape, and the key that opened it, shut it (the browser's own Ctrl+K kept away).\n const toggle = (e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'k';\n if (e.key === 'Escape' || toggle) {\n e.preventDefault();\n this.close();\n return;\n }\n keepTabInside(e, modal);\n if (e.target !== this.input) return;\n const count = this.shown.length;\n if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {\n e.preventDefault();\n if (count === 0) return;\n this.selectedIndex = (this.selectedIndex + (e.key === 'ArrowDown' ? 1 : -1) + count) % count;\n this.markSelection();\n } else if (e.key === 'Enter') {\n e.preventDefault();\n if (!e.repeat) this.run(this.selectedIndex);\n }\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"WidgetCommandPalette-JODJV4O0.cjs","names":[],"sources":["../src/widget/WidgetCommandPalette.ts"],"sourcesContent":["import type { ChartType, DrawingToolType, TimeFrame } from '@tradecanvas/commons';\nimport { EN_TRANSLATOR, type Translator } from './i18n.js';\nimport { createIcon } from './icons.js';\nimport { keepTabInside } from './focusTrap.js';\nimport { searchForm } from './platformKeys.js';\n\nexport interface CommandItem {\n id: string;\n label: string;\n category: CommandCategory;\n /** Its keys, written at the row's end (\"Alt+T\"). */\n shortcut?: string;\n /** On now (an indicator on the chart, the chart type in use): ticked. */\n active?: boolean;\n}\n\nexport type CommandCategory = 'indicator' | 'chartType' | 'drawing' | 'timeframe' | 'action';\n\nexport interface CommandPaletteCallbacks {\n onIndicator: (id: string) => void;\n onChartType: (type: ChartType) => void;\n onDrawingTool: (tool: DrawingToolType) => void;\n onTimeframe: (tf: TimeFrame) => void;\n onAction: (id: string) => void;\n onClose: () => void;\n}\n\n/** The commands used last, by `category:id`, newest first. */\nexport interface CommandRecents {\n list: () => readonly string[];\n add: (key: string) => void;\n}\n\n/** Commands used last, shown at the top before anything is typed. */\nconst RECENT_SHOWN = 5;\n/** The key code a browser gives a key an input method takes. */\nconst IME_KEY_CODE = 229;\n\n/** The widget's own commands first; the indicators, which have a dialog of their own, last. */\nconst CATEGORY_ORDER: readonly CommandCategory[] = ['action', 'drawing', 'chartType', 'timeframe', 'indicator'];\nconst CATEGORY_LABELS = {\n indicator: 'palette.group.indicator',\n chartType: 'palette.group.chartType',\n drawing: 'palette.group.drawing',\n timeframe: 'palette.group.timeframe',\n action: 'palette.group.action',\n} as const satisfies Record<CommandCategory, string>;\n\nconst keyOf = (item: CommandItem) => `${item.category}:${item.id}`;\n\n/**\n * How well `item` answers `query` (lower case, no spaces): its name or id\n * whole, then a name that starts with it, a word of the name that does, the\n * name holding it, its keys holding it (\"alt+t\"); 0 when nothing does.\n */\nfunction score(item: CommandItem, query: string): number {\n const label = item.label.toLowerCase();\n const flat = searchForm(label);\n if (item.id.toLowerCase() === query || flat === query) return 5;\n if (flat.startsWith(query)) return 4;\n if (label.split(/[\\s/()-]+/).some((word) => word.startsWith(query))) return 3;\n if (flat.includes(query) || item.id.toLowerCase().includes(query)) return 2;\n if (item.shortcut && searchForm(item.shortcut).includes(query)) return 1;\n return 0;\n}\n\ninterface Group {\n key: string;\n label: string;\n items: CommandItem[];\n}\n\nlet paletteSeq = 0;\n\n/**\n * The command palette (Ctrl+K): indicators, chart types, drawing tools,\n * intervals and the widget's own actions, in groups, with their keys. Before\n * anything is typed the commands used last come first. The keys stay in its\n * search: up and down move through the list, Enter runs a command.\n */\nexport class WidgetCommandPalette {\n private backdrop: HTMLDivElement | null = null;\n private input: HTMLInputElement | null = null;\n private list: HTMLDivElement | null = null;\n private emptyEl: HTMLDivElement | null = null;\n /** Says \"No results\" to a screen reader. */\n private liveEl: HTMLDivElement | null = null;\n private items: CommandItem[] = [];\n /** The rows on show, in order, for the keys. */\n private shown: CommandItem[] = [];\n private selectedIndex = 0;\n private returnFocus: HTMLElement | null = null;\n private readonly uid = ++paletteSeq;\n\n /** Where the overlay mounts (the widget's portal: themed, and inside it when fullscreen). */\n constructor(\n private readonly callbacks: CommandPaletteCallbacks,\n private readonly host: () => HTMLElement = () => document.body,\n private readonly t: Translator = EN_TRANSLATOR,\n private readonly recents?: CommandRecents,\n ) {}\n\n open(items: CommandItem[]): void {\n if (this.backdrop) return;\n this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n this.items = items;\n this.build();\n this.render();\n this.input?.focus();\n }\n\n close(): void {\n if (!this.backdrop) return;\n this.backdrop.remove();\n this.backdrop = this.input = this.list = this.emptyEl = this.liveEl = null;\n this.callbacks.onClose();\n const back = this.returnFocus;\n this.returnFocus = null;\n if (back?.isConnected) back.focus();\n }\n\n isOpen(): boolean {\n return this.backdrop !== null;\n }\n\n destroy(): void {\n this.close();\n }\n\n private build(): void {\n const backdrop = document.createElement('div');\n backdrop.className = 'tcw-modal-backdrop';\n // A press that starts in the palette and ends on the backdrop doesn't close it.\n let pressedBackdrop = false;\n backdrop.addEventListener('pointerdown', (e) => {\n pressedBackdrop = e.target === backdrop;\n });\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop && pressedBackdrop) this.close();\n pressedBackdrop = false;\n });\n\n const modal = document.createElement('div');\n modal.className = 'tcw-modal tcw-cp';\n modal.setAttribute('role', 'dialog');\n modal.setAttribute('aria-modal', 'true');\n modal.setAttribute('aria-label', this.t('hotkeys.commandPalette'));\n modal.tabIndex = -1;\n modal.addEventListener('keydown', (e) => this.onKeyDown(e, modal));\n\n const search = document.createElement('label');\n search.className = 'tcw-ss-search tcw-cp-search';\n search.innerHTML = createIcon('search', 16);\n const input = document.createElement('input');\n input.type = 'search';\n input.className = 'tcw-cp-input';\n input.placeholder = this.t('palette.placeholder');\n input.setAttribute('aria-label', this.t('palette.placeholder'));\n input.setAttribute('role', 'combobox');\n input.setAttribute('aria-expanded', 'true');\n input.setAttribute('aria-autocomplete', 'list');\n input.setAttribute('aria-controls', `tcw-cp-list-${this.uid}`);\n input.autocomplete = 'off';\n input.spellcheck = false;\n input.addEventListener('input', () => this.render());\n search.appendChild(input);\n\n const results = document.createElement('div');\n results.className = 'tcw-cp-results';\n const list = document.createElement('div');\n list.className = 'tcw-cp-list';\n list.id = `tcw-cp-list-${this.uid}`;\n list.setAttribute('role', 'listbox');\n list.setAttribute('aria-label', this.t('hotkeys.commandPalette'));\n const empty = document.createElement('div');\n empty.className = 'tcw-cp-empty';\n results.append(list, empty);\n // A press on a heading or between the rows keeps the keyboard in the search.\n results.addEventListener('mousedown', (e) => e.preventDefault());\n const live = document.createElement('div');\n live.className = 'tcw-cp-live tcw-visually-hidden';\n live.setAttribute('aria-live', 'polite');\n\n modal.append(search, results, live);\n backdrop.appendChild(modal);\n this.host().appendChild(backdrop);\n this.backdrop = backdrop;\n this.input = input;\n this.list = list;\n this.emptyEl = empty;\n this.liveEl = live;\n }\n\n /** The groups for what is typed: the commands used last first while nothing is, then each kind. */\n private groups(): Group[] {\n const query = searchForm((this.input?.value ?? '').trim());\n const groups: Group[] = [];\n if (!query) {\n const byKey = new Map(this.items.map((item) => [keyOf(item), item]));\n const recent = (this.recents?.list() ?? []).map((k) => byKey.get(k)).filter((i): i is CommandItem => !!i).slice(0, RECENT_SHOWN);\n if (recent.length > 0) groups.push({ key: 'recent', label: this.t('palette.group.recent'), items: recent });\n }\n for (const category of CATEGORY_ORDER) {\n let items = this.items.filter((item) => item.category === category);\n if (query) {\n items = items\n .map((item, at) => ({ item, at, s: score(item, query) }))\n .filter((r) => r.s > 0)\n .sort((a, b) => b.s - a.s || a.at - b.at)\n .map((r) => r.item);\n }\n if (items.length > 0) groups.push({ key: category, label: this.t(CATEGORY_LABELS[category]), items });\n }\n // Searching, the group with the best match comes first (the order above among equals).\n if (query) groups.sort((a, b) => score(b.items[0], query) - score(a.items[0], query));\n return groups;\n }\n\n private render(): void {\n const list = this.list;\n if (!list) return;\n const groups = this.groups();\n this.shown = groups.flatMap((g) => g.items);\n this.selectedIndex = 0;\n let index = 0;\n list.replaceChildren(...groups.map((group) => {\n const el = document.createElement('div');\n el.setAttribute('role', 'group');\n el.className = 'tcw-cp-group';\n const heading = document.createElement('div');\n heading.className = 'tcw-cp-heading';\n heading.id = `tcw-cp-${group.key}-${this.uid}`;\n heading.setAttribute('role', 'presentation');\n heading.textContent = group.label;\n el.setAttribute('aria-labelledby', heading.id);\n el.append(heading, ...group.items.map((item) => this.row(item, index++)));\n return el;\n }));\n const note = this.shown.length === 0 ? this.t('palette.empty') : '';\n if (this.emptyEl) this.emptyEl.textContent = note;\n this.emptyEl?.toggleAttribute('hidden', this.shown.length > 0);\n if (this.liveEl) this.liveEl.textContent = note;\n this.markSelection();\n }\n\n private row(item: CommandItem, index: number): HTMLDivElement {\n const row = document.createElement('div');\n row.className = 'tcw-cp-row';\n row.id = `tcw-cp-opt-${this.uid}-${index}`;\n row.dataset.id = item.id;\n row.setAttribute('role', 'option');\n row.classList.toggle('tcw-on', !!item.active);\n const label = document.createElement('span');\n label.className = 'tcw-cp-label';\n label.textContent = item.label;\n row.appendChild(label);\n if (item.shortcut) {\n const kbd = document.createElement('kbd');\n kbd.className = 'tcw-cp-key';\n // Keys read left to right in any widget: ⌘+P, never P+⌘.\n kbd.dir = 'ltr';\n kbd.textContent = item.shortcut;\n row.appendChild(kbd);\n }\n if (item.active) {\n const check = document.createElement('span');\n check.className = 'tcw-cp-check';\n check.innerHTML = createIcon('check', 14);\n row.appendChild(check);\n }\n row.addEventListener('click', () => this.run(index));\n row.addEventListener('mousemove', () => {\n if (this.selectedIndex === index) return;\n this.selectedIndex = index;\n this.markSelection();\n });\n return row;\n }\n\n private markSelection(): void {\n const rows = this.list?.querySelectorAll<HTMLElement>('.tcw-cp-row') ?? [];\n let active: HTMLElement | null = null;\n rows.forEach((el, i) => {\n const on = i === this.selectedIndex;\n el.setAttribute('aria-selected', String(on));\n el.classList.toggle('tcw-selected', on);\n if (on) active = el;\n });\n const row = active as HTMLElement | null;\n if (row) {\n this.input?.setAttribute('aria-activedescendant', row.id);\n row.scrollIntoView?.({ block: 'nearest' });\n } else {\n this.input?.removeAttribute('aria-activedescendant');\n }\n }\n\n private run(index: number): void {\n const item = this.shown[index];\n if (!item) return;\n this.recents?.add(keyOf(item));\n this.close();\n switch (item.category) {\n case 'indicator': this.callbacks.onIndicator(item.id); break;\n case 'chartType': this.callbacks.onChartType(item.id as ChartType); break;\n case 'drawing': this.callbacks.onDrawingTool(item.id as DrawingToolType); break;\n case 'timeframe': this.callbacks.onTimeframe(item.id as TimeFrame); break;\n case 'action': this.callbacks.onAction(item.id); break;\n }\n }\n\n private onKeyDown(e: KeyboardEvent, modal: HTMLElement): void {\n e.stopPropagation(); // keys here must not drive chart shortcuts\n // Enter, Escape and the arrows pick and close among an input method's candidates while it composes.\n if (e.isComposing || e.keyCode === IME_KEY_CODE) return;\n // Escape, and the key that opened it, shut it (the browser's own Ctrl+K kept away).\n const toggle = (e.ctrlKey || e.metaKey) && e.key.toLowerCase() === 'k';\n if (e.key === 'Escape' || toggle) {\n e.preventDefault();\n this.close();\n return;\n }\n keepTabInside(e, modal);\n if (e.target !== this.input) return;\n const count = this.shown.length;\n if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {\n e.preventDefault();\n if (count === 0) return;\n this.selectedIndex = (this.selectedIndex + (e.key === 'ArrowDown' ? 1 : -1) + count) % count;\n this.markSelection();\n } else if (e.key === 'Enter') {\n e.preventDefault();\n if (!e.repeat) this.run(this.selectedIndex);\n }\n }\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require(`./focusTrap-DrhhmG0V.cjs`),t=require(`./settingsControls-Tn8_vJJv.cjs`),n=require(`./i18n-Q4mxL2mj.cjs`),r=require(`./indicatorSettingsTabs-B0liE3ST.cjs`);let i=require(`@tradecanvas/commons`);var a=[1,2,3,4],o=[`solid`,`dashed`,`dotted`],s=[10,11,13,14,16,18,20,24,28,32],c=14,l=12,u=48,d=.5,f=.12,p=[`leftEnd`,`rightEnd`];function m(e,t,n){let r=`drawingOption.${t}`,i=e(r);return i===r?n:i}function h(){let e=document.createElement(`div`);return e.className=`tcw-settings-section`,e}function g(e,...t){let n=document.createElement(`div`);n.className=`tcw-settings-row`;let r=document.createElement(`span`);r.className=`tcw-settings-label`,r.textContent=e;let i=document.createElement(`span`);return i.className=`tcw-indi-plot-controls`,i.append(...t),n.append(r,i),n}function _(e,t){return e.setAttribute(`aria-label`,t),e}function v(e,n,r,i){let a=[],o=h();o.appendChild(y(n.style(),r,a,i));let s=p.filter(e=>n.defs[e]?.kind===`choice`);s.length>0&&o.appendChild(g(i(`drawingSettings.lineEnds`),...s.map(e=>_(t.o([{value:`normal`,label:i(`drawingSettings.lineEnd.normal`)},{value:`arrow`,label:i(`drawingSettings.lineEnd.arrow`)}],String(n.options()[e]??`normal`),t=>r.options({[e]:t})),m(i,e,n.defs[e].label))))),n.fill&&o.appendChild(b(n.style(),r,a,i)),e.appendChild(o);let c=Object.entries(n.defs).filter(([e,t])=>t.kind!==`levels`&&!s.includes(e));if(c.length>0){let t=h();for(let[e,a]of c)t.appendChild(x(e,a,n.options(),r,i));e.appendChild(t)}for(let[t,o]of Object.entries(n.defs))o.kind===`levels`&&e.appendChild(S(t,o,n,r,a,i))}function y(e,n,r,i){let s=_(t.r(e.color,e=>{n.style({color:e});for(let t of r)t(e)}),i(`drawingSettings.color`)),c=_(t.o(a.map(e=>({value:String(e),label:`${e} px`})),String(e.lineWidth),e=>n.style({lineWidth:Number(e)})),i(`drawingSettings.lineWidth`)),l=_(t.o(o.map(e=>({value:e,label:i(`drawingSettings.lineStyle.${e}`)})),e.lineStyle,e=>n.style({lineStyle:e})),i(`drawingSettings.lineStyle`));return g(i(`drawingSettings.line`),s,c,l)}function b(e,n,r,a){let o=(0,i.ownFillColor)(e)??t.d(e.color,f),s=t.l(o),c=t.n(o),l=(0,i.ownFillColor)(e)!==void 0,u=()=>{l=!0,n.style({fillColor:t.d(s,c),fillOpacity:c})},d=_(t.r(s,e=>{s=e,u()}),a(`drawingSettings.fill`));r.push(e=>{l||(s=t.l(e),d.value=s)});let p=_(t.i(Math.round(c*100),{min:0,max:100,step:5},e=>{c=e/100,u()}),a(`drawingSettings.opacity`)),m=document.createElement(`span`);return m.className=`tcw-unit`,m.setAttribute(`aria-hidden`,`true`),m.textContent=`%`,g(a(`drawingSettings.fill`),d,p,m)}function x(e,n,r,i,a){let o=m(a,e,n.label),s=r[e];switch(n.kind){case`boolean`:return t.t(o,!!s,t=>i.options({[e]:t}));case`number`:return t.s(o,t.i(Number(s),{min:n.min,max:n.max,step:n.step},t=>i.options({[e]:t})));case`choice`:return t.s(o,t.o(n.choices.map(t=>({value:t.value,label:m(a,`${e}.${t.value}`,t.label)})),String(s),t=>i.options({[e]:t})));case`text`:{let n=document.createElement(`input`);return n.type=`text`,n.className=`tcw-indi-input`,n.value=String(s??``),n.addEventListener(`change`,()=>i.options({[e]:n.value})),t.s(o,n)}}}function S(n,r,i,a,o,s){let c=document.createElement(`div`);c.className=`tcw-settings-section tcw-levels-editor`;let l=document.createElement(`div`);l.className=`tcw-settings-section-title`,l.textContent=m(s,n,r.label),c.appendChild(l);let f=()=>{let e=i.options()[n];return Array.isArray(e)?e:[]},p=e=>a.options({[n]:e}),h=document.createElement(`div`);h.className=`tcw-levels-grid`,f().forEach((n,r)=>{let c=document.createElement(`div`);c.className=`tcw-level-row`;let l=` ${r+1}`,u=document.createElement(`input`);u.type=`checkbox`,u.checked=n.visible,u.setAttribute(`aria-label`,s(`drawingSettings.levelVisible`)+l),u.addEventListener(`change`,()=>p(f().map((e,t)=>t===r?{...e,visible:u.checked}:e)));let d=_(t.i(n.value,{step:.001},e=>p(f().map((t,n)=>n===r?{...t,value:e}:t))),s(`drawingSettings.levelValue`)+l),m=_(t.r(n.color??i.style().color,e=>p(f().map((t,n)=>n===r?{...t,color:e}:t))),s(`drawingSettings.levelColor`)+l);o.push(e=>{f()[r]?.color===void 0&&(m.value=t.l(e))});let g=document.createElement(`button`);g.type=`button`,g.className=`tcw-level-remove`,g.setAttribute(`aria-label`,s(`drawingSettings.removeLevel`)+l),g.innerHTML=e.i(`x`,12),g.addEventListener(`click`,()=>{p(f().filter((e,t)=>t!==r)),a.redraw([`.tcw-level-row:nth-child(${r+1}) .tcw-level-remove`,`.tcw-level-row:last-child .tcw-level-remove`,`.tcw-level-add`])}),c.append(u,d,m,g),h.appendChild(c)}),c.appendChild(h);let g=document.createElement(`button`);return g.type=`button`,g.className=`tcw-reset-link tcw-level-add`,g.textContent=s(`drawingSettings.addLevel`),g.disabled=f().length>=u,g.addEventListener(`click`,()=>{let e=f().at(-1)?.value??0;p([...f(),{value:Math.round((e+d)*1e3)/1e3,visible:!0}]),a.redraw([`.tcw-level-row:last-child input[type="number"]`])}),c.appendChild(g),c}var C=240,w=40,T=4e3,E=10,D=[`left`,`center`,`right`],O=[`top`,`middle`,`bottom`];function k(e,t,n,r=!1){let i=document.createElement(`label`);i.className=`tcw-inline-check`;let a=document.createElement(`input`);if(a.type=`checkbox`,a.checked=t,a.setAttribute(`aria-label`,e),a.addEventListener(`change`,()=>n(a.checked)),i.append(a),!r){let t=document.createElement(`span`);t.textContent=e,i.append(t)}return i}function A(e,n,r,i,a,o,u=!1){let d=h(),f=document.createElement(`textarea`);f.className=`tcw-indi-input tcw-drawing-text`,f.rows=3,f.value=n.text??``,f.addEventListener(`input`,()=>r({text:f.value}));let p=t.s(i(`drawingSettings.text`),f);p.classList.add(`tcw-text-row`),d.appendChild(p);let m=_(t.o(s.map(e=>({value:String(e),label:`${e} px`})),String((n.fontSize===l?void 0:n.fontSize)??a?.fontSize??c),e=>r({fontSize:Number(e)})),i(`drawingSettings.fontSize`));d.appendChild(g(i(`drawingSettings.fontSize`),m,k(i(`drawingSettings.bold`),n.bold===!0,e=>r({bold:e})),k(i(`drawingSettings.italic`),n.italic===!0,e=>r({italic:e})))),d.appendChild(g(i(`drawingSettings.textColor`),_(t.r(n.textColor??o??n.color,e=>r({textColor:e})),i(`drawingSettings.textColor`)))),e.appendChild(d),a&&e.appendChild(M(n,r,i,a)),u&&e.appendChild(j(n,r,i))}function j(e,n,r){let i=h();return i.appendChild(g(r(`drawingSettings.align`),_(t.o(D.map(e=>({value:e,label:r(`drawingSettings.align.${e}`)})),e.textAlign??`center`,e=>n({textAlign:e})),r(`drawingSettings.align`)))),i.appendChild(g(r(`drawingSettings.vAlign`),_(t.o(O.map(e=>({value:e,label:r(`drawingSettings.vAlign.${e}`)})),e.textVAlign??`top`,e=>n({textVAlign:e})),r(`drawingSettings.vAlign`)))),i}function M(e,n,r,a){let o=h();o.appendChild(g(r(`drawingSettings.align`),_(t.o(D.map(e=>({value:e,label:r(`drawingSettings.align.${e}`)})),e.textAlign??`left`,e=>n({textAlign:e})),r(`drawingSettings.align`))));let s=(0,i.ownFillColor)(e)??t.d(e.color,f);o.appendChild(g(r(`drawingSettings.background`),k(r(`drawingSettings.background`),e.textBackground??a.box,e=>n({textBackground:e}),!0),_(t.r(s,e=>n({fillColor:t.d(e,t.n(s))})),r(`drawingSettings.backgroundColor`)))),o.appendChild(g(r(`drawingSettings.border`),k(r(`drawingSettings.border`),e.textBorder??a.border,e=>n({textBorder:e}),!0),_(t.r(e.borderColor??e.color,e=>n({borderColor:e})),r(`drawingSettings.borderColor`))));let c=e.textWrap??a.wrap,l=c>0?c:a.wrap>0?a.wrap:C,u=c>0,d=_(t.i(l,{min:w,max:T,step:E},e=>{l=e,u&&n({textWrap:e})}),r(`drawingSettings.wrapWidth`));return d.disabled=!u,o.appendChild(g(r(`drawingSettings.wrap`),k(r(`drawingSettings.wrap`),u,e=>{u=e,d.disabled=!e,n({textWrap:e?l:0})},!0),d)),o}function N(e,t,r,i){let a=h();t.forEach((e,t)=>{let o=n.r(i(`drawingSettings.point`),{n:t+1}),s=r.toWallTime(e.time),c=document.createElement(`input`);c.type=`date`,c.className=`tcw-indi-input`,c.value=s.date;let l=document.createElement(`input`);l.type=`time`,l.className=`tcw-indi-input`,l.value=s.time;let u=()=>{let e=r.fromWallTime(c.value,l.value);e!==null&&r.move(t,{time:e})};c.addEventListener(`change`,u),l.addEventListener(`change`,u);let d=g(o,_(P(e.price,r,e=>r.move(t,{price:e})),`${o}: ${i(`drawingSettings.price`)}`),_(c,`${o}: ${i(`drawingSettings.date`)}`),_(l,`${o}: ${i(`drawingSettings.time`)}`));d.classList.add(`tcw-draw-point`),a.appendChild(d)}),e.appendChild(a)}function P(e,n,r){let i=n.roundPrice??(e=>e),a=n.priceStep?.(),o=t.i(i(e),{step:a!==void 0&&a>0?a:`any`},e=>{let t=i(e);o.value=String(t),r(t)});return o}var F=12,I=`t:`,L=1,R=class{backdrop;modal;titleEl;tabsEl;bodyEl;templateBtn;menu=null;tabButtons=[];target=null;style;options={};anchors=[];intervals=null;tab=`style`;returnFocus=null;uid=L++;constructor(t,r,i=n.t){this.callbacks=r,this.t=i,this.backdrop=document.createElement(`div`),this.backdrop.className=`tcw-modal-backdrop`,this.backdrop.hidden=!0;let a=!1;this.backdrop.addEventListener(`pointerdown`,e=>{a=e.target===this.backdrop}),this.backdrop.addEventListener(`click`,e=>{e.target===this.backdrop&&a&&this.close(!0),a=!1}),this.modal=document.createElement(`div`),this.modal.className=`tcw-modal tcw-modal-narrow tcw-drawing-settings`,this.modal.setAttribute(`role`,`dialog`),this.modal.setAttribute(`aria-modal`,`true`),this.modal.setAttribute(`aria-labelledby`,`tcw-draw-title-${this.uid}`),this.modal.tabIndex=-1,this.modal.addEventListener(`keydown`,e=>this.onKeyDown(e));let o=document.createElement(`div`);o.className=`tcw-modal-header`,this.titleEl=document.createElement(`h3`),this.titleEl.id=`tcw-draw-title-${this.uid}`;let s=document.createElement(`button`);s.type=`button`,s.className=`tcw-modal-close`,s.setAttribute(`aria-label`,this.t(`common.close`)),s.innerHTML=e.i(`x`,16),s.addEventListener(`click`,()=>this.close(!0)),o.append(this.titleEl,s),this.tabsEl=document.createElement(`div`),this.tabsEl.className=`tcw-modal-tabs`,this.tabsEl.setAttribute(`role`,`tablist`),this.tabsEl.addEventListener(`keydown`,e=>this.onTabKey(e)),this.bodyEl=document.createElement(`div`),this.bodyEl.className=`tcw-modal-body`,this.bodyEl.id=`tcw-draw-panel-${this.uid}`,this.bodyEl.setAttribute(`role`,`tabpanel`),this.templateBtn=this.footerButton(`template`,`tcw-footer-menu`,()=>this.openTemplates()),this.modal.append(o,this.tabsEl,this.bodyEl,this.buildFooter()),this.backdrop.appendChild(this.modal),t.appendChild(this.backdrop)}buildFooter(){this.templateBtn.setAttribute(`aria-haspopup`,`menu`),this.templateBtn.setAttribute(`aria-expanded`,`false`),this.templateBtn.innerHTML=`<span></span>${e.i(`chevronDown`,12)}`,this.templateBtn.querySelector(`span`).textContent=this.t(`settings.template`);let t=document.createElement(`div`);t.className=`tcw-footer-end`,t.append(this.footerButton(`cancel`,`tcw-footer-cancel`,()=>this.close(!0),this.t(`common.cancel`)),this.footerButton(`ok`,`tcw-done-btn`,()=>this.close(!1),this.t(`drawingSettings.ok`)));let n=document.createElement(`div`);return n.className=`tcw-modal-footer`,n.append(this.templateBtn,t),n}open(e,t={}){this.target&&this.close(!1),this.returnFocus=document.activeElement instanceof HTMLElement?document.activeElement:null,this.target=e,this.style={...e.style},this.options=structuredClone(e.options),this.anchors=e.anchors.map(e=>({...e})),this.intervals=e.intervals??null,this.titleEl.textContent=e.name,this.tab=t.tab===`text`&&e.text?`text`:`style`,this.callbacks.onBegin(e.id);try{this.renderTabs(),this.renderBody()}catch(t){throw this.target=null,this.callbacks.onEnd(e.id,!0),t}this.backdrop.hidden=!1;let n=this.tab===`text`?this.bodyEl.querySelector(`textarea`):null;n?(n.focus(),n.select()):(this.tabButtons[0]??this.modal).focus()}close(e){let t=this.target;if(!t)return;let n=document.activeElement;!e&&(n instanceof HTMLInputElement||n instanceof HTMLTextAreaElement)&&this.modal.contains(n)&&n.dispatchEvent(new Event(`change`)),this.target=null,this.menu?.close(),this.backdrop.hidden=!0,this.callbacks.onEnd(t.id,e),this.returnFocus?.isConnected&&this.returnFocus.focus(),this.returnFocus=null}isOpen(){return this.target!==null}editing(){return this.target?.id??null}destroy(){this.close(!0),this.menu?.destroy(),this.backdrop.remove()}tabs(){let e=this.target;return e?[`style`,...e.text?[`text`]:[],...e.coordinates!==!1&&e.anchors.length<=F?[`coordinates`]:[],`visibility`]:[]}renderTabs(){this.tabButtons=this.tabs().map(e=>{let t=document.createElement(`button`);return t.type=`button`,t.className=`tcw-modal-tab`,t.id=`tcw-draw-tab-${this.uid}-${e}`,t.setAttribute(`role`,`tab`),t.setAttribute(`aria-controls`,this.bodyEl.id),t.dataset.tab=e,t.textContent=this.t(`drawingSettings.tab.${e}`),t.addEventListener(`click`,()=>this.selectTab(e)),t}),this.tabsEl.replaceChildren(...this.tabButtons),this.markTabs()}markTabs(){for(let e of this.tabButtons){let t=e.dataset.tab===this.tab;e.classList.toggle(`tcw-active`,t),e.setAttribute(`aria-selected`,String(t)),e.tabIndex=t?0:-1,t&&this.bodyEl.setAttribute(`aria-labelledby`,e.id)}}selectTab(e,t=!1){this.tab=e,this.markTabs(),this.renderBody(),t&&this.tabButtons.find(t=>t.dataset.tab===e)?.focus()}onTabKey(e){let t=this.tabButtons.map(e=>e.dataset.tab),n=t.indexOf(this.tab),[r,i]=this.modal.closest(`[dir]`)?.getAttribute(`dir`)===`rtl`?[`ArrowLeft`,`ArrowRight`]:[`ArrowRight`,`ArrowLeft`],a=e.key===r?(n+1)%t.length:e.key===i?(n-1+t.length)%t.length:e.key===`Home`?0:e.key===`End`?t.length-1:-1;a<0||(e.preventDefault(),this.selectTab(t[a],!0))}onKeyDown(t){if(t.key===`Escape`){t.preventDefault(),t.stopPropagation(),this.close(!0);return}e.n(t,this.modal)}renderBody(){this.bodyEl.replaceChildren();let e=this.target;if(e)switch(this.tab){case`text`:A(this.bodyEl,this.style,e=>this.setStyle(e),this.t,e.textLayout,e.textColor,e.textPlace);break;case`coordinates`:N(this.bodyEl,this.anchors,{toWallTime:this.callbacks.toWallTime,fromWallTime:this.callbacks.fromWallTime,roundPrice:this.callbacks.roundPrice,priceStep:this.callbacks.priceStep,move:(e,t)=>this.setAnchor(e,t)},this.t);break;case`visibility`:r.n(this.bodyEl,this.intervals,e=>this.setIntervals(e),this.t);break;default:v(this.bodyEl,{style:()=>this.style,options:()=>this.options,defs:e.defs,fill:e.fill},{style:e=>this.setStyle(e),options:e=>this.setOptions(e),redraw:(e=[])=>{this.renderBody();for(let t of e){let e=this.bodyEl.querySelector(t);if(e){e.focus();break}}}},this.t)}}change(e){this.target&&this.callbacks.onChange(this.target.id,e)}setStyle(e){this.target&&(this.style={...this.style,...e},this.change({style:e}))}setOptions(e){this.target&&(this.options={...this.options,...structuredClone(e)},this.change({options:e}))}setAnchor(e,t){this.target&&(this.anchors=this.anchors.map((n,r)=>r===e?{...n,...t}:n),this.change({anchors:this.anchors.map(e=>({...e}))}))}setIntervals(e){this.target&&(this.intervals=e,this.change({intervals:e}))}openTemplates(){let e=this.target;if(!e)return;if(this.menu?.isOpen()){this.menu.close();return}let r=this.callbacks.templates,i=r?.list(e.type)??[],a=[...i.map((e,t)=>({id:`${I}${t}`,label:e.name,icon:`layers`,remove:n.r(this.t(`templates.delete`),{name:e.name})})),...i.length>0?[`separator`]:[],...r?[{id:`save`,label:this.t(`settings.saveTemplate`),icon:`save`}]:[],...this.callbacks.onSaveDefault?[{id:`default`,label:this.t(`drawingSettings.saveDefault`),icon:`pin`}]:[],{id:`reset`,label:this.t(`settings.resetToDefaults`),icon:`reset`}],o=e=>i[Number(e.slice(2))];this.menu??=new t.f(this.modal,this.t(`settings.template`));let s=this.templateBtn.getBoundingClientRect(),c=this.modal.getBoundingClientRect();this.menu.open(a,s.left-c.left,s.top-c.top,t=>{t===`save`?r?.save({type:e.type,style:{...this.style},options:structuredClone(this.options)}):t===`default`?this.callbacks.onSaveDefault?.(e.type,structuredClone(this.options)):t===`reset`?this.resetOptions():t.startsWith(I)&&this.applyTemplate(o(t))},this.templateBtn,e=>{let t=o(e);t&&r?.remove(t.name,t.type)})}applyTemplate(e){let t=this.target;!e||!t||(Object.keys(e.style).length>0&&this.setStyle(e.style),e.options&&this.setOptions((0,i.sanitizeDrawingOptions)(t.defs,e.options)),this.renderBody())}resetOptions(){let e=this.target;if(!e)return;let t={};for(let[n,r]of Object.entries(e.defs))t[n]=structuredClone(r.default);this.setOptions(t),this.renderBody()}footerButton(e,t,n,r){let i=document.createElement(`button`);return i.type=`button`,i.className=t,i.dataset.act=e,r&&(i.textContent=r),i.addEventListener(`click`,n),i}};exports.WidgetDrawingSettings=R;
2
- //# sourceMappingURL=WidgetDrawingSettings-BpX4Cdys.cjs.map
1
+ const e=require(`./focusTrap-DrhhmG0V.cjs`),t=require(`./settingsControls-Tn8_vJJv.cjs`),n=require(`./i18n-CMgnJ3BI.cjs`),r=require(`./indicatorSettingsTabs-B0liE3ST.cjs`);let i=require(`@tradecanvas/commons`);var a=[1,2,3,4],o=[`solid`,`dashed`,`dotted`],s=[10,11,13,14,16,18,20,24,28,32],c=14,l=12,u=48,d=.5,f=.12,p=[`leftEnd`,`rightEnd`];function m(e,t,n){let r=`drawingOption.${t}`,i=e(r);return i===r?n:i}function h(){let e=document.createElement(`div`);return e.className=`tcw-settings-section`,e}function g(e,...t){let n=document.createElement(`div`);n.className=`tcw-settings-row`;let r=document.createElement(`span`);r.className=`tcw-settings-label`,r.textContent=e;let i=document.createElement(`span`);return i.className=`tcw-indi-plot-controls`,i.append(...t),n.append(r,i),n}function _(e,t){return e.setAttribute(`aria-label`,t),e}function v(e,n,r,i){let a=[],o=h();o.appendChild(y(n.style(),r,a,i));let s=p.filter(e=>n.defs[e]?.kind===`choice`);s.length>0&&o.appendChild(g(i(`drawingSettings.lineEnds`),...s.map(e=>_(t.o([{value:`normal`,label:i(`drawingSettings.lineEnd.normal`)},{value:`arrow`,label:i(`drawingSettings.lineEnd.arrow`)}],String(n.options()[e]??`normal`),t=>r.options({[e]:t})),m(i,e,n.defs[e].label))))),n.fill&&o.appendChild(b(n.style(),r,a,i)),e.appendChild(o);let c=Object.entries(n.defs).filter(([e,t])=>t.kind!==`levels`&&!s.includes(e));if(c.length>0){let t=h();for(let[e,a]of c)t.appendChild(x(e,a,n.options(),r,i));e.appendChild(t)}for(let[t,o]of Object.entries(n.defs))o.kind===`levels`&&e.appendChild(S(t,o,n,r,a,i))}function y(e,n,r,i){let s=_(t.r(e.color,e=>{n.style({color:e});for(let t of r)t(e)}),i(`drawingSettings.color`)),c=_(t.o(a.map(e=>({value:String(e),label:`${e} px`})),String(e.lineWidth),e=>n.style({lineWidth:Number(e)})),i(`drawingSettings.lineWidth`)),l=_(t.o(o.map(e=>({value:e,label:i(`drawingSettings.lineStyle.${e}`)})),e.lineStyle,e=>n.style({lineStyle:e})),i(`drawingSettings.lineStyle`));return g(i(`drawingSettings.line`),s,c,l)}function b(e,n,r,a){let o=(0,i.ownFillColor)(e)??t.d(e.color,f),s=t.l(o),c=t.n(o),l=(0,i.ownFillColor)(e)!==void 0,u=()=>{l=!0,n.style({fillColor:t.d(s,c),fillOpacity:c})},d=_(t.r(s,e=>{s=e,u()}),a(`drawingSettings.fill`));r.push(e=>{l||(s=t.l(e),d.value=s)});let p=_(t.i(Math.round(c*100),{min:0,max:100,step:5},e=>{c=e/100,u()}),a(`drawingSettings.opacity`)),m=document.createElement(`span`);return m.className=`tcw-unit`,m.setAttribute(`aria-hidden`,`true`),m.textContent=`%`,g(a(`drawingSettings.fill`),d,p,m)}function x(e,n,r,i,a){let o=m(a,e,n.label),s=r[e];switch(n.kind){case`boolean`:return t.t(o,!!s,t=>i.options({[e]:t}));case`number`:return t.s(o,t.i(Number(s),{min:n.min,max:n.max,step:n.step},t=>i.options({[e]:t})));case`choice`:return t.s(o,t.o(n.choices.map(t=>({value:t.value,label:m(a,`${e}.${t.value}`,t.label)})),String(s),t=>i.options({[e]:t})));case`text`:{let n=document.createElement(`input`);return n.type=`text`,n.className=`tcw-indi-input`,n.value=String(s??``),n.addEventListener(`change`,()=>i.options({[e]:n.value})),t.s(o,n)}}}function S(n,r,i,a,o,s){let c=document.createElement(`div`);c.className=`tcw-settings-section tcw-levels-editor`;let l=document.createElement(`div`);l.className=`tcw-settings-section-title`,l.textContent=m(s,n,r.label),c.appendChild(l);let f=()=>{let e=i.options()[n];return Array.isArray(e)?e:[]},p=e=>a.options({[n]:e}),h=document.createElement(`div`);h.className=`tcw-levels-grid`,f().forEach((n,r)=>{let c=document.createElement(`div`);c.className=`tcw-level-row`;let l=` ${r+1}`,u=document.createElement(`input`);u.type=`checkbox`,u.checked=n.visible,u.setAttribute(`aria-label`,s(`drawingSettings.levelVisible`)+l),u.addEventListener(`change`,()=>p(f().map((e,t)=>t===r?{...e,visible:u.checked}:e)));let d=_(t.i(n.value,{step:.001},e=>p(f().map((t,n)=>n===r?{...t,value:e}:t))),s(`drawingSettings.levelValue`)+l),m=_(t.r(n.color??i.style().color,e=>p(f().map((t,n)=>n===r?{...t,color:e}:t))),s(`drawingSettings.levelColor`)+l);o.push(e=>{f()[r]?.color===void 0&&(m.value=t.l(e))});let g=document.createElement(`button`);g.type=`button`,g.className=`tcw-level-remove`,g.setAttribute(`aria-label`,s(`drawingSettings.removeLevel`)+l),g.innerHTML=e.i(`x`,12),g.addEventListener(`click`,()=>{p(f().filter((e,t)=>t!==r)),a.redraw([`.tcw-level-row:nth-child(${r+1}) .tcw-level-remove`,`.tcw-level-row:last-child .tcw-level-remove`,`.tcw-level-add`])}),c.append(u,d,m,g),h.appendChild(c)}),c.appendChild(h);let g=document.createElement(`button`);return g.type=`button`,g.className=`tcw-reset-link tcw-level-add`,g.textContent=s(`drawingSettings.addLevel`),g.disabled=f().length>=u,g.addEventListener(`click`,()=>{let e=f().at(-1)?.value??0;p([...f(),{value:Math.round((e+d)*1e3)/1e3,visible:!0}]),a.redraw([`.tcw-level-row:last-child input[type="number"]`])}),c.appendChild(g),c}var C=240,w=40,T=4e3,E=10,D=[`left`,`center`,`right`],O=[`top`,`middle`,`bottom`];function k(e,t,n,r=!1){let i=document.createElement(`label`);i.className=`tcw-inline-check`;let a=document.createElement(`input`);if(a.type=`checkbox`,a.checked=t,a.setAttribute(`aria-label`,e),a.addEventListener(`change`,()=>n(a.checked)),i.append(a),!r){let t=document.createElement(`span`);t.textContent=e,i.append(t)}return i}function A(e,n,r,i,a,o,u=!1){let d=h(),f=document.createElement(`textarea`);f.className=`tcw-indi-input tcw-drawing-text`,f.rows=3,f.value=n.text??``,f.addEventListener(`input`,()=>r({text:f.value}));let p=t.s(i(`drawingSettings.text`),f);p.classList.add(`tcw-text-row`),d.appendChild(p);let m=_(t.o(s.map(e=>({value:String(e),label:`${e} px`})),String((n.fontSize===l?void 0:n.fontSize)??a?.fontSize??c),e=>r({fontSize:Number(e)})),i(`drawingSettings.fontSize`));d.appendChild(g(i(`drawingSettings.fontSize`),m,k(i(`drawingSettings.bold`),n.bold===!0,e=>r({bold:e})),k(i(`drawingSettings.italic`),n.italic===!0,e=>r({italic:e})))),d.appendChild(g(i(`drawingSettings.textColor`),_(t.r(n.textColor??o??n.color,e=>r({textColor:e})),i(`drawingSettings.textColor`)))),e.appendChild(d),a&&e.appendChild(M(n,r,i,a)),u&&e.appendChild(j(n,r,i))}function j(e,n,r){let i=h();return i.appendChild(g(r(`drawingSettings.align`),_(t.o(D.map(e=>({value:e,label:r(`drawingSettings.align.${e}`)})),e.textAlign??`center`,e=>n({textAlign:e})),r(`drawingSettings.align`)))),i.appendChild(g(r(`drawingSettings.vAlign`),_(t.o(O.map(e=>({value:e,label:r(`drawingSettings.vAlign.${e}`)})),e.textVAlign??`top`,e=>n({textVAlign:e})),r(`drawingSettings.vAlign`)))),i}function M(e,n,r,a){let o=h();o.appendChild(g(r(`drawingSettings.align`),_(t.o(D.map(e=>({value:e,label:r(`drawingSettings.align.${e}`)})),e.textAlign??`left`,e=>n({textAlign:e})),r(`drawingSettings.align`))));let s=(0,i.ownFillColor)(e)??t.d(e.color,f);o.appendChild(g(r(`drawingSettings.background`),k(r(`drawingSettings.background`),e.textBackground??a.box,e=>n({textBackground:e}),!0),_(t.r(s,e=>n({fillColor:t.d(e,t.n(s))})),r(`drawingSettings.backgroundColor`)))),o.appendChild(g(r(`drawingSettings.border`),k(r(`drawingSettings.border`),e.textBorder??a.border,e=>n({textBorder:e}),!0),_(t.r(e.borderColor??e.color,e=>n({borderColor:e})),r(`drawingSettings.borderColor`))));let c=e.textWrap??a.wrap,l=c>0?c:a.wrap>0?a.wrap:C,u=c>0,d=_(t.i(l,{min:w,max:T,step:E},e=>{l=e,u&&n({textWrap:e})}),r(`drawingSettings.wrapWidth`));return d.disabled=!u,o.appendChild(g(r(`drawingSettings.wrap`),k(r(`drawingSettings.wrap`),u,e=>{u=e,d.disabled=!e,n({textWrap:e?l:0})},!0),d)),o}function N(e,t,r,i){let a=h();t.forEach((e,t)=>{let o=n.r(i(`drawingSettings.point`),{n:t+1}),s=r.toWallTime(e.time),c=document.createElement(`input`);c.type=`date`,c.className=`tcw-indi-input`,c.value=s.date;let l=document.createElement(`input`);l.type=`time`,l.className=`tcw-indi-input`,l.value=s.time;let u=()=>{let e=r.fromWallTime(c.value,l.value);e!==null&&r.move(t,{time:e})};c.addEventListener(`change`,u),l.addEventListener(`change`,u);let d=g(o,_(P(e.price,r,e=>r.move(t,{price:e})),`${o}: ${i(`drawingSettings.price`)}`),_(c,`${o}: ${i(`drawingSettings.date`)}`),_(l,`${o}: ${i(`drawingSettings.time`)}`));d.classList.add(`tcw-draw-point`),a.appendChild(d)}),e.appendChild(a)}function P(e,n,r){let i=n.roundPrice??(e=>e),a=n.priceStep?.(),o=t.i(i(e),{step:a!==void 0&&a>0?a:`any`},e=>{let t=i(e);o.value=String(t),r(t)});return o}var F=12,I=`t:`,L=1,R=class{backdrop;modal;titleEl;tabsEl;bodyEl;templateBtn;menu=null;tabButtons=[];target=null;style;options={};anchors=[];intervals=null;tab=`style`;returnFocus=null;uid=L++;constructor(t,r,i=n.t){this.callbacks=r,this.t=i,this.backdrop=document.createElement(`div`),this.backdrop.className=`tcw-modal-backdrop`,this.backdrop.hidden=!0;let a=!1;this.backdrop.addEventListener(`pointerdown`,e=>{a=e.target===this.backdrop}),this.backdrop.addEventListener(`click`,e=>{e.target===this.backdrop&&a&&this.close(!0),a=!1}),this.modal=document.createElement(`div`),this.modal.className=`tcw-modal tcw-modal-narrow tcw-drawing-settings`,this.modal.setAttribute(`role`,`dialog`),this.modal.setAttribute(`aria-modal`,`true`),this.modal.setAttribute(`aria-labelledby`,`tcw-draw-title-${this.uid}`),this.modal.tabIndex=-1,this.modal.addEventListener(`keydown`,e=>this.onKeyDown(e));let o=document.createElement(`div`);o.className=`tcw-modal-header`,this.titleEl=document.createElement(`h3`),this.titleEl.id=`tcw-draw-title-${this.uid}`;let s=document.createElement(`button`);s.type=`button`,s.className=`tcw-modal-close`,s.setAttribute(`aria-label`,this.t(`common.close`)),s.innerHTML=e.i(`x`,16),s.addEventListener(`click`,()=>this.close(!0)),o.append(this.titleEl,s),this.tabsEl=document.createElement(`div`),this.tabsEl.className=`tcw-modal-tabs`,this.tabsEl.setAttribute(`role`,`tablist`),this.tabsEl.addEventListener(`keydown`,e=>this.onTabKey(e)),this.bodyEl=document.createElement(`div`),this.bodyEl.className=`tcw-modal-body`,this.bodyEl.id=`tcw-draw-panel-${this.uid}`,this.bodyEl.setAttribute(`role`,`tabpanel`),this.templateBtn=this.footerButton(`template`,`tcw-footer-menu`,()=>this.openTemplates()),this.modal.append(o,this.tabsEl,this.bodyEl,this.buildFooter()),this.backdrop.appendChild(this.modal),t.appendChild(this.backdrop)}buildFooter(){this.templateBtn.setAttribute(`aria-haspopup`,`menu`),this.templateBtn.setAttribute(`aria-expanded`,`false`),this.templateBtn.innerHTML=`<span></span>${e.i(`chevronDown`,12)}`,this.templateBtn.querySelector(`span`).textContent=this.t(`settings.template`);let t=document.createElement(`div`);t.className=`tcw-footer-end`,t.append(this.footerButton(`cancel`,`tcw-footer-cancel`,()=>this.close(!0),this.t(`common.cancel`)),this.footerButton(`ok`,`tcw-done-btn`,()=>this.close(!1),this.t(`drawingSettings.ok`)));let n=document.createElement(`div`);return n.className=`tcw-modal-footer`,n.append(this.templateBtn,t),n}open(e,t={}){this.target&&this.close(!1),this.returnFocus=document.activeElement instanceof HTMLElement?document.activeElement:null,this.target=e,this.style={...e.style},this.options=structuredClone(e.options),this.anchors=e.anchors.map(e=>({...e})),this.intervals=e.intervals??null,this.titleEl.textContent=e.name,this.tab=t.tab===`text`&&e.text?`text`:`style`,this.callbacks.onBegin(e.id);try{this.renderTabs(),this.renderBody()}catch(t){throw this.target=null,this.callbacks.onEnd(e.id,!0),t}this.backdrop.hidden=!1;let n=this.tab===`text`?this.bodyEl.querySelector(`textarea`):null;n?(n.focus(),n.select()):(this.tabButtons[0]??this.modal).focus()}close(e){let t=this.target;if(!t)return;let n=document.activeElement;!e&&(n instanceof HTMLInputElement||n instanceof HTMLTextAreaElement)&&this.modal.contains(n)&&n.dispatchEvent(new Event(`change`)),this.target=null,this.menu?.close(),this.backdrop.hidden=!0,this.callbacks.onEnd(t.id,e),this.returnFocus?.isConnected&&this.returnFocus.focus(),this.returnFocus=null}isOpen(){return this.target!==null}editing(){return this.target?.id??null}destroy(){this.close(!0),this.menu?.destroy(),this.backdrop.remove()}tabs(){let e=this.target;return e?[`style`,...e.text?[`text`]:[],...e.coordinates!==!1&&e.anchors.length<=F?[`coordinates`]:[],`visibility`]:[]}renderTabs(){this.tabButtons=this.tabs().map(e=>{let t=document.createElement(`button`);return t.type=`button`,t.className=`tcw-modal-tab`,t.id=`tcw-draw-tab-${this.uid}-${e}`,t.setAttribute(`role`,`tab`),t.setAttribute(`aria-controls`,this.bodyEl.id),t.dataset.tab=e,t.textContent=this.t(`drawingSettings.tab.${e}`),t.addEventListener(`click`,()=>this.selectTab(e)),t}),this.tabsEl.replaceChildren(...this.tabButtons),this.markTabs()}markTabs(){for(let e of this.tabButtons){let t=e.dataset.tab===this.tab;e.classList.toggle(`tcw-active`,t),e.setAttribute(`aria-selected`,String(t)),e.tabIndex=t?0:-1,t&&this.bodyEl.setAttribute(`aria-labelledby`,e.id)}}selectTab(e,t=!1){this.tab=e,this.markTabs(),this.renderBody(),t&&this.tabButtons.find(t=>t.dataset.tab===e)?.focus()}onTabKey(e){let t=this.tabButtons.map(e=>e.dataset.tab),n=t.indexOf(this.tab),[r,i]=this.modal.closest(`[dir]`)?.getAttribute(`dir`)===`rtl`?[`ArrowLeft`,`ArrowRight`]:[`ArrowRight`,`ArrowLeft`],a=e.key===r?(n+1)%t.length:e.key===i?(n-1+t.length)%t.length:e.key===`Home`?0:e.key===`End`?t.length-1:-1;a<0||(e.preventDefault(),this.selectTab(t[a],!0))}onKeyDown(t){if(t.key===`Escape`){t.preventDefault(),t.stopPropagation(),this.close(!0);return}e.n(t,this.modal)}renderBody(){this.bodyEl.replaceChildren();let e=this.target;if(e)switch(this.tab){case`text`:A(this.bodyEl,this.style,e=>this.setStyle(e),this.t,e.textLayout,e.textColor,e.textPlace);break;case`coordinates`:N(this.bodyEl,this.anchors,{toWallTime:this.callbacks.toWallTime,fromWallTime:this.callbacks.fromWallTime,roundPrice:this.callbacks.roundPrice,priceStep:this.callbacks.priceStep,move:(e,t)=>this.setAnchor(e,t)},this.t);break;case`visibility`:r.n(this.bodyEl,this.intervals,e=>this.setIntervals(e),this.t);break;default:v(this.bodyEl,{style:()=>this.style,options:()=>this.options,defs:e.defs,fill:e.fill},{style:e=>this.setStyle(e),options:e=>this.setOptions(e),redraw:(e=[])=>{this.renderBody();for(let t of e){let e=this.bodyEl.querySelector(t);if(e){e.focus();break}}}},this.t)}}change(e){this.target&&this.callbacks.onChange(this.target.id,e)}setStyle(e){this.target&&(this.style={...this.style,...e},this.change({style:e}))}setOptions(e){this.target&&(this.options={...this.options,...structuredClone(e)},this.change({options:e}))}setAnchor(e,t){this.target&&(this.anchors=this.anchors.map((n,r)=>r===e?{...n,...t}:n),this.change({anchors:this.anchors.map(e=>({...e}))}))}setIntervals(e){this.target&&(this.intervals=e,this.change({intervals:e}))}openTemplates(){let e=this.target;if(!e)return;if(this.menu?.isOpen()){this.menu.close();return}let r=this.callbacks.templates,i=r?.list(e.type)??[],a=[...i.map((e,t)=>({id:`${I}${t}`,label:e.name,icon:`layers`,remove:n.r(this.t(`templates.delete`),{name:e.name})})),...i.length>0?[`separator`]:[],...r?[{id:`save`,label:this.t(`settings.saveTemplate`),icon:`save`}]:[],...this.callbacks.onSaveDefault?[{id:`default`,label:this.t(`drawingSettings.saveDefault`),icon:`pin`}]:[],{id:`reset`,label:this.t(`settings.resetToDefaults`),icon:`reset`}],o=e=>i[Number(e.slice(2))];this.menu??=new t.f(this.modal,this.t(`settings.template`));let s=this.templateBtn.getBoundingClientRect(),c=this.modal.getBoundingClientRect();this.menu.open(a,s.left-c.left,s.top-c.top,t=>{t===`save`?r?.save({type:e.type,style:{...this.style},options:structuredClone(this.options)}):t===`default`?this.callbacks.onSaveDefault?.(e.type,structuredClone(this.options)):t===`reset`?this.resetOptions():t.startsWith(I)&&this.applyTemplate(o(t))},this.templateBtn,e=>{let t=o(e);t&&r?.remove(t.name,t.type)})}applyTemplate(e){let t=this.target;!e||!t||(Object.keys(e.style).length>0&&this.setStyle(e.style),e.options&&this.setOptions((0,i.sanitizeDrawingOptions)(t.defs,e.options)),this.renderBody())}resetOptions(){let e=this.target;if(!e)return;let t={};for(let[n,r]of Object.entries(e.defs))t[n]=structuredClone(r.default);this.setOptions(t),this.renderBody()}footerButton(e,t,n,r){let i=document.createElement(`button`);return i.type=`button`,i.className=t,i.dataset.act=e,r&&(i.textContent=r),i.addEventListener(`click`,n),i}};exports.WidgetDrawingSettings=R;
2
+ //# sourceMappingURL=WidgetDrawingSettings-C_xRMbdJ.cjs.map