@tradecanvas/chart 2.5.0 → 2.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (116) hide show
  1. package/README.md +2 -2
  2. package/dist/Chart.d.ts +6 -0
  3. package/dist/Chart.d.ts.map +1 -1
  4. package/dist/{LayoutSession-CE8S2GCG.js → LayoutSession-CO51QKwZ.js} +10 -3
  5. package/dist/LayoutSession-CO51QKwZ.js.map +1 -0
  6. package/dist/LayoutSession-DIPjmNVe.cjs +2 -0
  7. package/dist/LayoutSession-DIPjmNVe.cjs.map +1 -0
  8. package/dist/{WidgetCommandPalette-B1jLC9oE.js → WidgetCommandPalette-CSIKnTca.js} +2 -2
  9. package/dist/{WidgetCommandPalette-B1jLC9oE.js.map → WidgetCommandPalette-CSIKnTca.js.map} +1 -1
  10. package/dist/{WidgetCommandPalette-Cx-UQ9ft.cjs → WidgetCommandPalette-CZ3GhE1O.cjs} +2 -2
  11. package/dist/{WidgetCommandPalette-Cx-UQ9ft.cjs.map → WidgetCommandPalette-CZ3GhE1O.cjs.map} +1 -1
  12. package/dist/{WidgetDrawingSettings-ezbzlGqD.js → WidgetDrawingSettings-Cc8PeqEZ.js} +2 -2
  13. package/dist/{WidgetDrawingSettings-ezbzlGqD.js.map → WidgetDrawingSettings-Cc8PeqEZ.js.map} +1 -1
  14. package/dist/{WidgetDrawingSettings-BjPR5Wyq.cjs → WidgetDrawingSettings-DutEdVyV.cjs} +2 -2
  15. package/dist/{WidgetDrawingSettings-BjPR5Wyq.cjs.map → WidgetDrawingSettings-DutEdVyV.cjs.map} +1 -1
  16. package/dist/{WidgetGoToDate-DJyCaP4H.js → WidgetGoToDate-DnQxxvf1.js} +2 -2
  17. package/dist/{WidgetGoToDate-DJyCaP4H.js.map → WidgetGoToDate-DnQxxvf1.js.map} +1 -1
  18. package/dist/{WidgetGoToDate-Vfaztduf.cjs → WidgetGoToDate-hNVxz-Zb.cjs} +2 -2
  19. package/dist/{WidgetGoToDate-Vfaztduf.cjs.map → WidgetGoToDate-hNVxz-Zb.cjs.map} +1 -1
  20. package/dist/{WidgetIndicatorPicker-Cw7pFl_l.js → WidgetIndicatorPicker-DNjcuBp6.js} +3 -3
  21. package/dist/{WidgetIndicatorPicker-Cw7pFl_l.js.map → WidgetIndicatorPicker-DNjcuBp6.js.map} +1 -1
  22. package/dist/{WidgetIndicatorPicker-Nc-1Rbm_.cjs → WidgetIndicatorPicker-GCesxFMn.cjs} +2 -2
  23. package/dist/{WidgetIndicatorPicker-Nc-1Rbm_.cjs.map → WidgetIndicatorPicker-GCesxFMn.cjs.map} +1 -1
  24. package/dist/{WidgetIndicatorSettings-Da_T6bmX.cjs → WidgetIndicatorSettings-CBHWj5z5.cjs} +2 -2
  25. package/dist/{WidgetIndicatorSettings-Da_T6bmX.cjs.map → WidgetIndicatorSettings-CBHWj5z5.cjs.map} +1 -1
  26. package/dist/{WidgetIndicatorSettings-DR8Z9RfF.js → WidgetIndicatorSettings-XhHlqyvn.js} +3 -3
  27. package/dist/{WidgetIndicatorSettings-DR8Z9RfF.js.map → WidgetIndicatorSettings-XhHlqyvn.js.map} +1 -1
  28. package/dist/{WidgetSettings-DCGCymVY.js → WidgetSettings-B1ay0W6I.js} +3 -3
  29. package/dist/{WidgetSettings-DCGCymVY.js.map → WidgetSettings-B1ay0W6I.js.map} +1 -1
  30. package/dist/{WidgetSettings-COljE3G_.cjs → WidgetSettings-CBf6hUSV.cjs} +2 -2
  31. package/dist/{WidgetSettings-COljE3G_.cjs.map → WidgetSettings-CBf6hUSV.cjs.map} +1 -1
  32. package/dist/{WidgetSymbolSearch-B8iDwVy8.js → WidgetSymbolSearch-BlQWH3Md.js} +3 -3
  33. package/dist/{WidgetSymbolSearch-B8iDwVy8.js.map → WidgetSymbolSearch-BlQWH3Md.js.map} +1 -1
  34. package/dist/{WidgetSymbolSearch-DVIRTJuT.cjs → WidgetSymbolSearch-CxeLjy63.cjs} +2 -2
  35. package/dist/{WidgetSymbolSearch-DVIRTJuT.cjs.map → WidgetSymbolSearch-CxeLjy63.cjs.map} +1 -1
  36. package/dist/i18n-BFGknfTa.cjs +2 -0
  37. package/dist/i18n-BFGknfTa.cjs.map +1 -0
  38. package/dist/{i18n-DWLKoOBG.js → i18n-BZdkj80c.js} +7 -1
  39. package/dist/i18n-BZdkj80c.js.map +1 -0
  40. package/dist/index.cjs +1 -1
  41. package/dist/index.js +1 -1
  42. package/dist/{indicatorInputWords-VWMPRfzM.js → indicatorInputWords-B8lf8reQ.js} +2 -2
  43. package/dist/{indicatorInputWords-VWMPRfzM.js.map → indicatorInputWords-B8lf8reQ.js.map} +1 -1
  44. package/dist/{indicatorInputWords-C4Mefhve.cjs → indicatorInputWords-_kxwKob4.cjs} +2 -2
  45. package/dist/{indicatorInputWords-C4Mefhve.cjs.map → indicatorInputWords-_kxwKob4.cjs.map} +1 -1
  46. package/dist/widget/ChartWidget.d.ts.map +1 -1
  47. package/dist/widget/WidgetDrawingEdit.d.ts +13 -0
  48. package/dist/widget/WidgetDrawingEdit.d.ts.map +1 -1
  49. package/dist/widget/WidgetMenus.d.ts +2 -0
  50. package/dist/widget/WidgetMenus.d.ts.map +1 -1
  51. package/dist/widget/WidgetObjectTree.d.ts.map +1 -1
  52. package/dist/widget/WidgetSelectionToolbar.d.ts +4 -0
  53. package/dist/widget/WidgetSelectionToolbar.d.ts.map +1 -1
  54. package/dist/widget/drawingMenu.d.ts +3 -1
  55. package/dist/widget/drawingMenu.d.ts.map +1 -1
  56. package/dist/widget/index.cjs +4 -3
  57. package/dist/widget/index.cjs.map +1 -1
  58. package/dist/widget/index.js +179 -118
  59. package/dist/widget/index.js.map +1 -1
  60. package/dist/widget/locales/ar.d.ts.map +1 -1
  61. package/dist/widget/locales/cs.d.ts.map +1 -1
  62. package/dist/widget/locales/da.d.ts.map +1 -1
  63. package/dist/widget/locales/de.d.ts.map +1 -1
  64. package/dist/widget/locales/el.d.ts.map +1 -1
  65. package/dist/widget/locales/en.d.ts +3 -0
  66. package/dist/widget/locales/en.d.ts.map +1 -1
  67. package/dist/widget/locales/es.d.ts.map +1 -1
  68. package/dist/widget/locales/et.d.ts.map +1 -1
  69. package/dist/widget/locales/fa.d.ts.map +1 -1
  70. package/dist/widget/locales/fr.d.ts.map +1 -1
  71. package/dist/widget/locales/he.d.ts.map +1 -1
  72. package/dist/widget/locales/hu.d.ts.map +1 -1
  73. package/dist/widget/locales/id.d.ts.map +1 -1
  74. package/dist/widget/locales/index.cjs +1 -1
  75. package/dist/widget/locales/index.cjs.map +1 -1
  76. package/dist/widget/locales/index.js +85 -1
  77. package/dist/widget/locales/index.js.map +1 -1
  78. package/dist/widget/locales/it.d.ts.map +1 -1
  79. package/dist/widget/locales/ja.d.ts.map +1 -1
  80. package/dist/widget/locales/ko.d.ts.map +1 -1
  81. package/dist/widget/locales/ms.d.ts.map +1 -1
  82. package/dist/widget/locales/nb.d.ts.map +1 -1
  83. package/dist/widget/locales/nl.d.ts.map +1 -1
  84. package/dist/widget/locales/pl.d.ts.map +1 -1
  85. package/dist/widget/locales/pt.d.ts.map +1 -1
  86. package/dist/widget/locales/ro.d.ts.map +1 -1
  87. package/dist/widget/locales/ru.d.ts.map +1 -1
  88. package/dist/widget/locales/sk.d.ts.map +1 -1
  89. package/dist/widget/locales/sv.d.ts.map +1 -1
  90. package/dist/widget/locales/th.d.ts.map +1 -1
  91. package/dist/widget/locales/tr.d.ts.map +1 -1
  92. package/dist/widget/locales/vi.d.ts.map +1 -1
  93. package/dist/widget/locales/zh.d.ts.map +1 -1
  94. package/dist/widget/locales/zhHant.d.ts.map +1 -1
  95. package/dist/widget/widgetConfig.d.ts.map +1 -1
  96. package/dist/widget/widgetFeatures.d.ts.map +1 -1
  97. package/dist/{widgetFeatures-B-el8UA3.cjs → widgetFeatures-DpBWfQ8D.cjs} +2 -2
  98. package/dist/widgetFeatures-DpBWfQ8D.cjs.map +1 -0
  99. package/dist/{widgetFeatures-DsbSG6Pq.js → widgetFeatures-sU-9JOSB.js} +2 -1
  100. package/dist/widgetFeatures-sU-9JOSB.js.map +1 -0
  101. package/dist/widgetLocales-BdRQu8wS.cjs +2 -0
  102. package/dist/widgetLocales-BdRQu8wS.cjs.map +1 -0
  103. package/dist/{widgetLocales-BX7VRdl5.js → widgetLocales-Bgm5-BB5.js} +13 -1
  104. package/dist/widgetLocales-Bgm5-BB5.js.map +1 -0
  105. package/package.json +3 -3
  106. package/dist/LayoutSession-C9bQsnH2.cjs +0 -2
  107. package/dist/LayoutSession-C9bQsnH2.cjs.map +0 -1
  108. package/dist/LayoutSession-CE8S2GCG.js.map +0 -1
  109. package/dist/i18n-DWLKoOBG.js.map +0 -1
  110. package/dist/i18n-fgAwciRT.cjs +0 -2
  111. package/dist/i18n-fgAwciRT.cjs.map +0 -1
  112. package/dist/widgetFeatures-B-el8UA3.cjs.map +0 -1
  113. package/dist/widgetFeatures-DsbSG6Pq.js.map +0 -1
  114. package/dist/widgetLocales-BX7VRdl5.js.map +0 -1
  115. package/dist/widgetLocales-C_XTkni5.cjs +0 -2
  116. package/dist/widgetLocales-C_XTkni5.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"WidgetSettings-DCGCymVY.js","names":[],"sources":["../src/widget/settingsRows.ts","../src/widget/WidgetSettings.ts"],"sourcesContent":["import { toHex } from './settingsControls.js';\nimport { fill, type Translator } from './i18n.js';\n\n/**\n * The rows of the chart settings: a section, a colour, a switch, a choice,\n * a slider and a number, each with its label and calling back on change.\n */\n\n/** Ids for the colour rows' descriptions. */\nlet colorRowCount = 0;\n/** Ids for the number rows' hints. */\nlet numberRowCount = 0;\n/** The most decimals a number in a hint shows: the smallest size taken, 0.00000001, has 8. */\nconst HINT_MAX_DECIMALS = 20;\n\n/** A group of rows; a title names it to a screen reader too (rows named alike under several titles). */\nexport function settingsSection(title?: string): HTMLDivElement {\n const div = document.createElement('div');\n div.className = 'tcw-settings-section';\n if (title) {\n const heading = document.createElement('div');\n heading.className = 'tcw-settings-section-title';\n heading.textContent = title;\n div.appendChild(heading);\n div.setAttribute('role', 'group');\n div.setAttribute('aria-label', title);\n }\n return div;\n}\n\nfunction labelledRow(label: string): HTMLDivElement {\n const row = document.createElement('div');\n row.className = 'tcw-settings-row';\n const lbl = document.createElement('span');\n lbl.className = 'tcw-settings-label';\n lbl.textContent = label;\n row.appendChild(lbl);\n return row;\n}\n\n/**\n * A colour of the look, shown again from `look.read()`. With `look.start`,\n * null is the part's own colour: shown as Auto, the picker starting from\n * `start()`, and once set a button takes it back.\n */\nexport function colorRow(\n label: string,\n value: string | null,\n onChange: (v: string | null) => void,\n look: { read: () => string | null; start?: () => string | number | boolean | null },\n t: Translator,\n): { row: HTMLDivElement; sync: () => void } {\n const row = labelledRow(label);\n const wrap = document.createElement('div');\n wrap.className = 'tcw-color-picker-wrap';\n const input = document.createElement('input');\n input.type = 'color';\n input.setAttribute('aria-label', label);\n // What the swatch can't say (Auto, a colour with transparency) is read with it.\n const hex = document.createElement('span');\n hex.className = 'tcw-color-hex';\n hex.id = `tcw-color-${++colorRowCount}`;\n input.setAttribute('aria-describedby', hex.id);\n\n let back: HTMLButtonElement | null = null;\n const show = (v: string | null) => {\n input.value = toHex(v ?? look.start?.());\n hex.textContent = v ?? t('settings.auto');\n row.classList.toggle('tcw-color-auto', v === null);\n if (v !== null && look.start && !back) {\n back = document.createElement('button');\n back.type = 'button';\n back.className = 'tcw-color-auto-btn';\n back.textContent = t('settings.auto');\n back.setAttribute('aria-label', `${label}: ${t('settings.auto')}`);\n back.addEventListener('click', () => {\n onChange(null);\n // Focus stays in the row as the button goes; the chart may still draw a colour the host set.\n input.focus();\n show(look.read());\n });\n wrap.appendChild(back);\n } else if (v === null && back) {\n back.remove();\n back = null;\n }\n };\n input.addEventListener('input', () => {\n onChange(input.value);\n show(input.value);\n });\n wrap.append(input, hex);\n row.appendChild(wrap);\n show(value);\n return { row, sync: () => show(look.read()) };\n}\n\nexport function toggleRow(label: string, value: boolean, onChange: (v: boolean) => void): HTMLDivElement {\n const row = labelledRow(label);\n const toggle = document.createElement('button');\n toggle.type = 'button';\n toggle.className = `tcw-toggle${value ? ' tcw-on' : ''}`;\n toggle.setAttribute('role', 'switch');\n toggle.setAttribute('aria-checked', String(value));\n toggle.setAttribute('aria-label', label);\n toggle.addEventListener('click', () => {\n const next = !toggle.classList.contains('tcw-on');\n toggle.classList.toggle('tcw-on', next);\n toggle.setAttribute('aria-checked', String(next));\n onChange(next);\n });\n row.appendChild(toggle);\n return row;\n}\n\nexport function selectRow(\n label: string,\n value: string,\n options: readonly { label: string; value: string }[],\n onChange: (v: string) => void,\n): HTMLDivElement {\n const row = labelledRow(label);\n const select = document.createElement('select');\n select.className = 'tcw-settings-select';\n select.setAttribute('aria-label', label);\n for (const opt of options) {\n const o = document.createElement('option');\n o.value = opt.value;\n o.textContent = opt.label;\n if (opt.value === value) o.selected = true;\n select.appendChild(o);\n }\n // A value none of the options has (two keys that differ): nothing chosen, so any pick is a change.\n if (!options.some((opt) => opt.value === value)) select.selectedIndex = -1;\n select.addEventListener('change', () => onChange(select.value));\n row.appendChild(select);\n return row;\n}\n\nexport function rangeRow(\n label: string,\n value: number,\n range: { min: number; max: number; step: number },\n onChange: (v: number) => void,\n format: (v: number) => string = (v) => String(v),\n): HTMLDivElement {\n const row = labelledRow(label);\n const wrap = document.createElement('div');\n wrap.className = 'tcw-settings-range';\n const input = document.createElement('input');\n input.type = 'range';\n input.min = String(range.min);\n input.max = String(range.max);\n input.step = String(range.step);\n input.value = String(value);\n input.setAttribute('aria-label', label);\n const out = document.createElement('span');\n out.className = 'tcw-settings-range-val';\n out.textContent = format(value);\n input.addEventListener('input', () => {\n const v = Number(input.value);\n out.textContent = format(v);\n onChange(v);\n });\n wrap.append(input, out);\n row.appendChild(wrap);\n return row;\n}\n\n/** What a number field takes. */\nexport interface NumberLimits {\n /** The field's step: '1' takes whole counts only, 'any' any number. */\n step: string;\n /** The largest number taken (Infinity: no limit). */\n max: number;\n /** The smallest number taken; without one, any number above 0. */\n min?: number;\n}\n\n/** What a number field takes, in words: the hint under it once it turned a number away. */\nfunction limitsText(limits: NumberLimits, t: Translator, locale: string): string {\n const format = new Intl.NumberFormat(locale, { maximumFractionDigits: HINT_MAX_DECIMALS }).format;\n if (limits.step === '1' && Number.isFinite(limits.max)) {\n return fill(t('settings.numberWhole'), { min: format(Math.max(1, limits.min ?? 1)), max: format(limits.max) });\n }\n return fill(t('settings.numberAtLeast'), { min: format(limits.min ?? 0) });\n}\n\n/**\n * A number field; empty means \"worked out from the data\" (shown as Auto). Only numbers above 0, and from\n * `limits.min` on, are taken; one turned away is marked invalid, and a hint under it, in `locale`, says what is.\n */\nexport function numberRow(\n label: string,\n value: number | null,\n limits: NumberLimits,\n onChange: (v: number | null) => void,\n t: Translator,\n locale = 'en-US',\n): HTMLDivElement {\n const row = document.createElement('div');\n row.className = 'tcw-settings-row tcw-settings-row--number';\n const lbl = document.createElement('label');\n lbl.className = 'tcw-settings-label';\n lbl.textContent = label;\n row.appendChild(lbl);\n const input = document.createElement('input');\n input.type = 'number';\n input.className = 'tcw-settings-number';\n // The min attribute is also where the arrows step from: at 1e-8, the up arrow turns 5 into 5.00000001 and an\n // empty field into 1e-8. It stays 0, and the smallest number taken is checked on change.\n input.min = '0';\n input.step = limits.step;\n if (Number.isFinite(limits.max)) input.max = String(limits.max);\n input.placeholder = t('settings.auto');\n input.value = value === null ? '' : String(value);\n input.setAttribute('aria-label', label);\n // Written when a number is turned away, and heard with the field: red alone says nothing to a screen reader.\n const hint = document.createElement('div');\n hint.className = 'tcw-settings-hint';\n hint.id = `tcw-number-hint-${++numberRowCount}`;\n hint.setAttribute('role', 'status');\n input.setAttribute('aria-describedby', hint.id);\n const mark = (ok: boolean) => {\n if (ok) input.removeAttribute('aria-invalid');\n else input.setAttribute('aria-invalid', 'true');\n hint.textContent = ok ? '' : limitsText(limits, t, locale);\n };\n input.addEventListener('change', () => {\n if (input.value.trim() === '') {\n mark(true);\n onChange(null);\n return;\n }\n const v = Number(input.value);\n const ok = Number.isFinite(v) && v > 0 && v >= (limits.min ?? 0) && v <= limits.max && (limits.step !== '1' || Number.isInteger(v));\n mark(ok);\n if (ok) onChange(v);\n });\n row.append(input, hint);\n return row;\n}\n","import { CHART_STYLE_KEYS, type ChartType, type ChartTypeOptions, type LineStyle } from '@tradecanvas/commons';\nimport type { ChartSettingsState, SettingsCallbacks, SettingsStylePatch } from './types.js';\nimport { CHART_TYPES } from './widgetConfig.js';\nimport {\n APPEARANCE_SECTIONS, HIGH_LOW_SECTION, LAST_PRICE_SECTION, LEGEND_ROWS, SCALE_ROWS, STATUS_LINE_ROWS, TRADING_SECTIONS, VOLUME_SECTION,\n seriesRows, type LookRow, type LookSection,\n} from './widgetSettingsLook.js';\nimport { chartTypeLabel, numberLocaleOptions } from './widgetLocales.js';\nimport { createChartTypeIcon, createIcon } from './icons.js';\nimport { timezoneOptions } from './widgetTimezones.js';\nimport { FOCUSABLE, keepTabInside } from './focusTrap.js';\nimport { WidgetContextMenu, type ContextMenuEntry } from './WidgetContextMenu.js';\nimport { colorRow, numberRow, rangeRow, selectRow, settingsSection, toggleRow, type NumberLimits } from './settingsRows.js';\nimport { fill, type MessageKey, type Translator } from './i18n.js';\n\nexport type SettingsTab = 'symbol' | 'statusLine' | 'scales' | 'appearance' | 'layers' | 'trading';\ntype Tab = SettingsTab;\n\n/** The tabs down the side, in the order a trader looks: the symbol first, the trading colours last. */\nconst TABS: readonly { id: Tab; icon: string }[] = [\n { id: 'symbol', icon: 'chartType:candlestick' },\n { id: 'statusLine', icon: 'type' },\n { id: 'scales', icon: 'ruler' },\n { id: 'appearance', icon: 'palette' },\n { id: 'layers', icon: 'layers' },\n { id: 'trading', icon: 'trendingUp' },\n];\n/** The widths a line takes in the settings, in pixels. */\nconst LINE_WIDTHS = [1, 2, 3, 4];\n/** A template's entry in the Template menu, by its name. */\nconst TEMPLATE_ID = 't:';\n/**\n * The smallest box, reversal or range the chart type's settings take: a\n * hundred-millionth, the finest price step markets commonly quote. A size\n * far under the prices is no use; the chart raises one that would make too\n * many bars anyway, but a slip like 1e-9 is turned away here.\n */\nconst MIN_TYPE_SIZE = 1e-8;\n/** A box, reversal or range: any number from MIN_TYPE_SIZE up. */\nconst SIZE_LIMITS: NumberLimits = { step: 'any', max: Infinity, min: MIN_TYPE_SIZE };\n\nlet nextSettingsId = 1;\n\n/**\n * The chart's settings: tabs down the side (Symbol, Status line, Scales,\n * Appearance, Layers, Trading), each change shown at once. Cancel (Escape,\n * the close button, a click outside) puts it all back, OK keeps it; the\n * Template menu applies, saves and deletes templates, and resets.\n */\nexport class WidgetSettings {\n private callbacks: SettingsCallbacks;\n private t: Translator;\n private backdrop: HTMLDivElement | null = null;\n private modal: HTMLDivElement | null = null;\n private bodyEl: HTMLDivElement | null = null;\n private tabButtons: HTMLButtonElement[] = [];\n private templateBtn: HTMLButtonElement | null = null;\n private menu: WidgetContextMenu | null = null;\n private currentTab: Tab = 'symbol';\n private currentSettings: ChartSettingsState | null = null;\n /** The chart's type, whose settings the Symbol tab offers. */\n private chartType: ChartType | null = null;\n /** The look's rows on view, each showing the chart's value again (a change to one moves others: a wick with its body). */\n private lookRows: { el: HTMLElement; sync: () => void }[] = [];\n private returnFocus: HTMLElement | null = null;\n private readonly uid = nextSettingsId++;\n\n /**\n * `barCountdown` / `logScale` / `legend` / `volume` false leave out the\n * controls for features the chart has switched off: there they would do\n * nothing.\n */\n constructor(\n callbacks: SettingsCallbacks,\n t: Translator,\n private readonly available: {\n barCountdown?: boolean;\n logScale?: boolean;\n legend?: boolean;\n volume?: boolean;\n /** The exchange's time zone to offer (null while unknown), or undefined when there is none to offer. */\n exchangeZone?: () => string | null | undefined;\n /** false: the chart doesn't trade, so the orders' colours aren't offered. */\n trading?: boolean;\n } = {},\n /** Where the panel mounts (the widget's portal: themed, and inside it when fullscreen). */\n private readonly host: () => HTMLElement = () => document.body,\n ) {\n this.callbacks = callbacks;\n this.t = t;\n }\n\n /** Open on `tab` (the Symbol tab unless asked: the price axis's menu asks for Scales). */\n open(currentSettings: ChartSettingsState, chartType: ChartType | null = null, tab: SettingsTab = 'symbol'): void {\n if (this.modal) this.remove();\n this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n this.currentSettings = { ...currentSettings };\n this.chartType = chartType;\n this.currentTab = tab;\n this.buildModal();\n this.tabButtons.find((b) => b.dataset.tab === tab)?.focus();\n }\n\n isOpen(): boolean {\n return this.modal !== null;\n }\n\n /** Show `settings` when they differ from what the dialog shows: a change made outside it while it is open. */\n follow(settings: ChartSettingsState): void {\n if (!this.modal || (this.currentSettings && sameSettings(this.currentSettings, settings))) return;\n this.refresh(settings);\n }\n\n /** The settings as they are now (after an undo, a template), on the tab that's open; `chartType` when it changed. */\n refresh(settings: ChartSettingsState, chartType?: ChartType | null): void {\n if (!this.modal) return;\n this.currentSettings = { ...settings };\n if (chartType !== undefined) this.chartType = chartType;\n // A change from outside (a compare's bars, the host's setSettings) builds the panel again under the\n // control in focus: focus goes to the one in its place, not to the page outside the dialog.\n const focused = this.focusedControl();\n this.renderTabContent();\n if (focused !== null) this.focusControl(focused);\n }\n\n /** The place of the control in focus among the panel's, or null when focus is not in the panel. */\n private focusedControl(): number | null {\n const active = document.activeElement;\n if (!this.bodyEl || !(active instanceof HTMLElement) || !this.bodyEl.contains(active)) return null;\n const at = this.panelControls().indexOf(active);\n return at < 0 ? null : at;\n }\n\n /** Focus the panel's control at `index`, or its last when it has fewer; the tab when it has none. */\n private focusControl(index: number): void {\n const controls = this.panelControls();\n const control = controls[Math.min(index, controls.length - 1)] ?? this.tabButtons.find((b) => b.dataset.tab === this.currentTab);\n control?.focus();\n }\n\n private panelControls(): HTMLElement[] {\n return this.bodyEl ? [...this.bodyEl.querySelectorAll<HTMLElement>(FOCUSABLE)] : [];\n }\n\n /** Close, keeping what was changed (as OK does). */\n close(): void {\n this.finish(true);\n }\n\n destroy(): void {\n this.remove();\n }\n\n /** OK (`keep`) or Cancel, then closed, focus back where the dialog was opened from. */\n private finish(keep: boolean): void {\n if (!this.modal) return;\n if (keep) this.callbacks.onClose();\n else this.callbacks.onCancel?.();\n this.remove();\n if (this.returnFocus?.isConnected) this.returnFocus.focus();\n this.returnFocus = null;\n }\n\n private remove(): void {\n this.menu?.destroy();\n this.menu = null;\n this.backdrop?.remove();\n this.backdrop = this.modal = this.bodyEl = this.templateBtn = null;\n this.tabButtons = [];\n }\n\n private buildModal(): void {\n const backdrop = document.createElement('div');\n backdrop.className = 'tcw-modal-backdrop';\n // A press that starts in the dialog (a slider dragged, text selected) and ends on the backdrop doesn't cancel 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.finish(false);\n pressedBackdrop = false;\n });\n const modal = document.createElement('div');\n modal.className = 'tcw-modal tcw-set';\n modal.setAttribute('role', 'dialog');\n modal.setAttribute('aria-modal', 'true');\n modal.setAttribute('aria-labelledby', `tcw-set-title-${this.uid}`);\n modal.tabIndex = -1;\n modal.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n e.stopPropagation();\n this.finish(false);\n return;\n }\n keepTabInside(e, modal);\n });\n this.backdrop = backdrop;\n this.modal = modal;\n modal.append(this.buildHeader(), this.buildBody(), this.buildFooter());\n backdrop.appendChild(modal);\n this.host().appendChild(backdrop);\n this.markTabs();\n this.renderTabContent();\n }\n\n private buildHeader(): HTMLDivElement {\n const header = document.createElement('div');\n header.className = 'tcw-modal-header';\n const title = document.createElement('h3');\n title.id = `tcw-set-title-${this.uid}`;\n title.textContent = this.t('settings.title');\n const closeBtn = document.createElement('button');\n closeBtn.type = 'button';\n closeBtn.className = 'tcw-modal-close';\n closeBtn.setAttribute('aria-label', this.t('common.close'));\n closeBtn.innerHTML = createIcon('x', 16);\n closeBtn.addEventListener('click', () => this.finish(false));\n header.append(title, closeBtn);\n return header;\n }\n\n /** The tabs down the side, and the open one's settings beside them. */\n private buildBody(): HTMLDivElement {\n const body = document.createElement('div');\n body.className = 'tcw-set-body';\n const nav = document.createElement('div');\n nav.className = 'tcw-set-nav';\n nav.setAttribute('role', 'tablist');\n nav.setAttribute('aria-orientation', 'vertical');\n nav.setAttribute('aria-label', this.t('settings.title'));\n nav.addEventListener('keydown', (e) => this.onTabKey(e));\n this.tabButtons = TABS.map(({ id, icon }) => {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'tcw-set-tab';\n btn.id = `tcw-set-tab-${this.uid}-${id}`;\n btn.dataset.tab = id;\n btn.setAttribute('role', 'tab');\n btn.setAttribute('aria-controls', `tcw-set-panel-${this.uid}`);\n const svg = icon.startsWith('chartType:') ? createChartTypeIcon(icon.slice('chartType:'.length) as ChartType, 16) : createIcon(icon, 16);\n btn.innerHTML = `${svg}<span></span>`;\n btn.querySelector('span')!.textContent = this.t(`settings.tab.${id}` as MessageKey);\n btn.addEventListener('click', () => this.selectTab(id));\n return btn;\n });\n nav.append(...this.tabButtons);\n const panel = document.createElement('div');\n panel.className = 'tcw-modal-body tcw-set-panel';\n panel.id = `tcw-set-panel-${this.uid}`;\n panel.setAttribute('role', 'tabpanel');\n this.bodyEl = panel;\n body.append(nav, panel);\n return body;\n }\n\n /** Template on the left; Cancel and OK on the right. */\n private buildFooter(): HTMLDivElement {\n const footer = document.createElement('div');\n footer.className = 'tcw-modal-footer';\n const template = this.footerButton('template', 'tcw-footer-menu', () => this.openTemplates());\n template.setAttribute('aria-haspopup', 'menu');\n template.setAttribute('aria-expanded', 'false');\n template.innerHTML = `<span></span>${createIcon('chevronDown', 12)}`;\n template.querySelector('span')!.textContent = this.t('settings.template');\n this.templateBtn = template;\n const end = document.createElement('div');\n end.className = 'tcw-footer-end';\n end.append(\n this.footerButton('cancel', 'tcw-footer-cancel', () => this.finish(false), this.t('common.cancel')),\n this.footerButton('ok', 'tcw-done-btn', () => this.finish(true), this.t('drawingSettings.ok')),\n );\n footer.append(template, end);\n return footer;\n }\n\n private footerButton(act: string, className: string, onClick: () => void, text?: string): HTMLButtonElement {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = className;\n btn.dataset.act = act;\n if (text) btn.textContent = text;\n btn.addEventListener('click', onClick);\n return btn;\n }\n\n private markTabs(): void {\n for (const btn of this.tabButtons) {\n const on = btn.dataset.tab === this.currentTab;\n btn.classList.toggle('tcw-active', on);\n btn.setAttribute('aria-selected', String(on));\n btn.tabIndex = on ? 0 : -1;\n if (on) this.bodyEl?.setAttribute('aria-labelledby', btn.id);\n }\n }\n\n private selectTab(tab: Tab, focus = false): void {\n this.currentTab = tab;\n this.markTabs();\n this.renderTabContent();\n if (focus) this.tabButtons.find((b) => b.dataset.tab === tab)?.focus();\n }\n\n /** Through the tabs (Home, End), picking as they go: up and down, or along the row of chips on a phone. */\n private onTabKey(e: KeyboardEvent): void {\n const at = TABS.findIndex((tab) => tab.id === this.currentTab);\n const next = e.key === 'ArrowDown' || e.key === 'ArrowRight' ? (at + 1) % TABS.length\n : e.key === 'ArrowUp' || e.key === 'ArrowLeft' ? (at - 1 + TABS.length) % TABS.length\n : e.key === 'Home' ? 0\n : e.key === 'End' ? TABS.length - 1\n : -1;\n if (next < 0) return;\n e.preventDefault();\n this.selectTab(TABS[next].id, true);\n }\n\n /** The Template menu: the saved templates (each removable), Save as template, Reset to defaults. */\n private openTemplates(): void {\n const btn = this.templateBtn;\n if (!this.modal || !btn) return;\n if (this.menu?.isOpen()) {\n this.menu.close();\n return;\n }\n const templates = this.callbacks.templates;\n const saved: ContextMenuEntry[] = (templates?.list() ?? []).map((name) => ({\n id: `${TEMPLATE_ID}${name}`, label: name, icon: 'layers', remove: fill(this.t('templates.delete'), { name }),\n }));\n const entries: ContextMenuEntry[] = [\n ...saved,\n ...(saved.length > 0 ? ['separator' as const] : []),\n ...(templates ? [{ id: 'save', label: this.t('settings.saveTemplate'), icon: 'save' }] : []),\n { id: 'reset', label: this.t('settings.resetToDefaults'), icon: 'reset' },\n ];\n this.menu ??= new WidgetContextMenu(this.modal, this.t('settings.template'));\n const at = btn.getBoundingClientRect();\n const box = this.modal.getBoundingClientRect();\n // From the button's top: in the footer there is no room below, so it opens above the button.\n this.menu.open(entries, at.left - box.left, at.top - box.top, (id) => {\n if (id === 'reset') this.callbacks.onReset();\n else if (id === 'save') templates?.save();\n else if (id.startsWith(TEMPLATE_ID)) templates?.apply(id.slice(TEMPLATE_ID.length));\n }, btn, (id) => templates?.remove(id.slice(TEMPLATE_ID.length)));\n }\n\n private renderTabContent(): void {\n if (!this.bodyEl || !this.currentSettings) return;\n this.bodyEl.replaceChildren();\n this.lookRows = [];\n switch (this.currentTab) {\n case 'symbol': this.renderSymbolTab(this.currentSettings); break;\n case 'statusLine': this.renderStatusLineTab(this.currentSettings); break;\n case 'scales': this.renderScalesTab(this.currentSettings); break;\n case 'appearance': this.renderAppearanceTab(this.currentSettings); break;\n case 'layers': this.renderLayersTab(this.currentSettings); break;\n case 'trading':\n for (const section of TRADING_SECTIONS) {\n if (!section.trading || this.available.trading !== false) this.renderLookSection(section);\n }\n break;\n }\n }\n\n /** The chart type's own settings and colours, the main series, the last price, the volume, the high and low. */\n private renderSymbolTab(s: ChartSettingsState): void {\n this.renderChartTypeSection();\n this.addSection(undefined, [\n toggleRow(this.t('settings.mainSeries'), s.mainSeriesVisible, (v) => this.patch({ mainSeriesVisible: v })),\n toggleRow(this.t('settings.extendedHours'), s.extendedHours, (v) => this.patch({ extendedHours: v })),\n ]);\n // A section's own switch says \"Show\": its title names what it shows.\n const show = this.t('common.show');\n this.renderLookSection(LAST_PRICE_SECTION);\n if (this.available.volume !== false) {\n this.renderLookSection(VOLUME_SECTION, [toggleRow(show, s.volumeVisible, (v) => this.patch({ volumeVisible: v }))]);\n }\n this.renderLookSection(HIGH_LOW_SECTION, [toggleRow(show, s.highLowLines, (v) => this.patch({ highLowLines: v }))]);\n }\n\n /** The legend over the chart: shown or not, its colours; the panes' titles. */\n private renderStatusLineTab(s: ChartSettingsState): void {\n const legend = this.available.legend !== false;\n const rows = legend ? STATUS_LINE_ROWS : STATUS_LINE_ROWS.filter((row) => !LEGEND_ROWS.includes(row));\n this.addSection(undefined, [\n ...(legend ? [toggleRow(this.t('settings.ohlcLegend'), s.legendVisible, (v) => this.patch({ legendVisible: v }))] : []),\n ...rows.map((row) => this.lookRow(row)),\n ]);\n }\n\n /** The price scale's mode and behaviour, its labels, the time zone, how numbers are written, the axes' colours. */\n private renderScalesTab(s: ChartSettingsState): void {\n const scales = [\n { value: 'regular', label: this.t('settings.scale.regular') },\n { value: 'logarithmic', label: this.t('settings.scale.logarithmic') },\n { value: 'percentage', label: this.t('settings.scale.percentage') },\n { value: 'indexedTo100', label: this.t('settings.scale.indexedTo100') },\n ].filter((o) => o.value !== 'logarithmic' || this.available.logScale !== false);\n const exchangeZone = this.available.exchangeZone?.();\n const zones = timezoneOptions(s.timezone, Date.now(), this.t('settings.timezone.local'),\n exchangeZone !== undefined ? { label: this.t('settings.timezone.exchange'), zone: exchangeZone } : undefined);\n this.addSection(undefined, [\n selectRow(this.t('settings.priceScale'), s.scaleMode, scales, (v) => this.patch({ scaleMode: v as ChartSettingsState['scaleMode'] })),\n toggleRow(this.t('settings.autoScale'), s.autoScale, (v) => this.patch({ autoScale: v })),\n toggleRow(this.t('settings.invertScale'), s.invertScale, (v) => this.patch({ invertScale: v })),\n toggleRow(this.t('settings.leftScale'), s.leftPriceScale, (v) => this.patch({ leftPriceScale: v })),\n toggleRow(this.t('settings.indicatorValues'), s.indicatorValueLabels, (v) => this.patch({ indicatorValueLabels: v })),\n toggleRow(this.t('settings.alignAxisLabels'), s.alignAxisLabels, (v) => this.patch({ alignAxisLabels: v })),\n ...(this.available.barCountdown !== false\n ? [toggleRow(this.t('settings.barCountdown'), s.barCountdown, (v) => this.patch({ barCountdown: v }))]\n : []),\n selectRow(this.t('settings.timezone'), s.timezone, zones, (v) => this.patch({ timezone: v })),\n selectRow(this.t('settings.numberLocale'), s.numberLocale, numberLocaleOptions(s.numberLocale), (v) => this.patch({ numberLocale: v })),\n ]);\n this.addSection(this.t('settings.section.axes'), SCALE_ROWS.map((row) => this.lookRow(row)));\n }\n\n /** The background, the grid, the crosshair, the session breaks, the drawings' handles. */\n private renderAppearanceTab(s: ChartSettingsState): void {\n const [background, grid, crosshair, ...rest] = APPEARANCE_SECTIONS;\n this.renderLookSection(background);\n this.renderLookSection(grid, [toggleRow(this.t('common.show'), s.gridVisible, (v) => this.patch({ gridVisible: v }))]);\n this.renderLookSection(crosshair, [selectRow(this.t('settings.crosshairMode'), s.crosshairMode, [\n { label: this.t('settings.crosshair.magnet'), value: 'magnet' },\n { label: this.t('settings.crosshair.normal'), value: 'normal' },\n { label: this.t('settings.crosshair.hidden'), value: 'hidden' },\n ], (v) => this.patch({ crosshairMode: v as ChartSettingsState['crosshairMode'] })),\n selectRow(this.t('settings.crosshairCursor'), s.crosshairCursor, [\n { label: this.t('drawing.cursorCross'), value: 'cross' },\n { label: this.t('drawing.cursorDot'), value: 'dot' },\n { label: this.t('drawing.cursorArrow'), value: 'arrow' },\n ], (v) => this.patch({ crosshairCursor: v as ChartSettingsState['crosshairCursor'] }))]);\n for (const section of rest) this.renderLookSection(section);\n }\n\n /** What the chart can draw over the bars: the profiles, the depth, the swings, the sessions, the prior levels. */\n private renderLayersTab(s: ChartSettingsState): void {\n const percent = (v: number) => `${Math.round(v * 100)}%`;\n const t = (key: MessageKey) => this.t(key);\n this.addSection(undefined, [toggleRow(t('settings.volumeProfile'), s.volumeProfileVisible, (v) => this.patch({ volumeProfileVisible: v }))]);\n this.addSection(undefined, [\n toggleRow(t('settings.marketProfile'), s.marketProfileVisible, (v) => this.patch({ marketProfileVisible: v })),\n toggleRow(t('settings.marketProfileSplit'), s.marketProfileSplit, (v) => this.patch({ marketProfileSplit: v })),\n toggleRow(t('settings.marketProfileLetters'), s.marketProfileLetters, (v) => this.patch({ marketProfileLetters: v })),\n rangeRow(t('settings.marketProfileBuckets'), s.marketProfileBuckets, { min: 8, max: 200, step: 1 }, (v) => this.patch({ marketProfileBuckets: v })),\n rangeRow(t('settings.marketProfileOpacity'), s.marketProfileOpacity, { min: 0.05, max: 1, step: 0.05 }, (v) => this.patch({ marketProfileOpacity: v }), percent),\n ]);\n this.addSection(undefined, [\n toggleRow(t('settings.depthHeatmap'), s.depthHeatmapVisible, (v) => this.patch({ depthHeatmapVisible: v })),\n rangeRow(t('settings.depthHeatmapOpacity'), s.depthHeatmapOpacity, { min: 0.1, max: 1, step: 0.05 }, (v) => this.patch({ depthHeatmapOpacity: v }), percent),\n ]);\n this.addSection(undefined, [\n toggleRow(t('settings.swingMarkers'), s.pivotMarkersVisible, (v) => this.patch({ pivotMarkersVisible: v })),\n rangeRow(t('settings.swingStrength'), s.pivotStrength, { min: 2, max: 20, step: 1 }, (v) => this.patch({ pivotStrength: v })),\n toggleRow(t('settings.swingStructure'), s.pivotStructureLabels, (v) => this.patch({ pivotStructureLabels: v })),\n ]);\n this.addSection(undefined, [\n toggleRow(t('settings.sessionShading'), s.sessionShadingVisible, (v) => this.patch({ sessionShadingVisible: v })),\n toggleRow(t('settings.periodLevels'), s.periodLevelsVisible, (v) => this.patch({ periodLevelsVisible: v })),\n selectRow(t('settings.periodLevelsBasis'), s.periodLevelsPeriod, [\n { value: 'day', label: t('settings.priorDay') },\n { value: 'week', label: t('settings.priorWeek') },\n ], (v) => this.patch({ periodLevelsPeriod: v as ChartSettingsState['periodLevelsPeriod'] })),\n ]);\n }\n\n private addSection(title: string | undefined, rows: readonly HTMLElement[]): HTMLDivElement {\n const section = settingsSection(title);\n section.append(...rows);\n this.bodyEl?.appendChild(section);\n return section;\n }\n\n /** A section of the look, after `lead` (the switch it goes with, say). */\n private renderLookSection(section: LookSection, lead: readonly HTMLElement[] = []): void {\n this.addSection(this.t(section.title), [...lead, ...section.rows.map((row) => this.lookRow(row))]);\n }\n\n /** A row of the look: a colour, a switch, a dash or a width, as its key takes it, on the user's layer. */\n private lookRow(row: LookRow): HTMLDivElement {\n const label = this.t(row.label);\n const read = () => this.callbacks.styleValue(row.keys[0]);\n /** The keys' value, or '' when they differ (the host set each way apart): any pick then sets them all. */\n const shared = (): string => {\n const values = row.keys.map((key) => this.callbacks.styleValue(key));\n return values.every((v) => v === values[0]) && values[0] !== null ? String(values[0]) : '';\n };\n let el: HTMLDivElement;\n const set = (v: string | number | boolean | null) => {\n this.callbacks.onStyleChange(Object.fromEntries(row.keys.map((key) => [key, v])) as SettingsStylePatch);\n for (const other of this.lookRows) if (other.el !== el) other.sync();\n };\n const auto = row.auto ? [{ value: '', label: this.t('settings.auto') }] : [];\n let sync: () => void;\n switch (CHART_STYLE_KEYS[row.keys[0]]) {\n case 'boolean': {\n el = toggleRow(label, read() === true, set);\n const toggle = el.querySelector('button')!;\n sync = () => {\n const on = read() === true;\n toggle.classList.toggle('tcw-on', on);\n toggle.setAttribute('aria-checked', String(on));\n };\n break;\n }\n case 'lineStyle':\n el = selectRow(label, shared(), [...auto, ...this.lineStyles()], (v) => set(v === '' ? null : asLineStyle(v)));\n sync = () => { el.querySelector('select')!.value = shared(); };\n break;\n case 'width': {\n const value = read();\n const widths = typeof value === 'number' && !LINE_WIDTHS.includes(value) ? [...LINE_WIDTHS, value].sort((a, b) => a - b) : LINE_WIDTHS;\n el = selectRow(label, shared(), [...auto, ...widths.map((w) => ({ value: String(w), label: `${w}px` }))],\n (v) => set(v === '' ? null : Number(v)));\n sync = () => { el.querySelector('select')!.value = shared(); };\n break;\n }\n default: {\n const value = read();\n const colour = colorRow(label, typeof value === 'string' ? value : null, set, {\n read: () => { const v = read(); return typeof v === 'string' ? v : null; },\n start: row.auto ? () => (row.auto?.from ? this.callbacks.styleValue(row.auto.from) : row.auto?.hint) ?? null : undefined,\n }, this.t);\n el = colour.row;\n sync = colour.sync;\n }\n }\n this.lookRows.push({ el, sync });\n return el;\n }\n\n private lineStyles(): { value: string; label: string }[] {\n return [\n { value: 'solid', label: this.t('drawingSettings.lineStyle.solid') },\n { value: 'dashed', label: this.t('drawingSettings.lineStyle.dashed') },\n { value: 'dotted', label: this.t('drawingSettings.lineStyle.dotted') },\n ];\n }\n\n /** The chart's type: its settings (Renko's box, Kagi's reversal…) and its colours and widths. */\n private renderChartTypeSection(): void {\n if (!this.bodyEl || !this.currentSettings || !this.chartType) return;\n const type = this.chartType;\n const all = this.currentSettings.chartTypeOptions ?? {};\n const def = CHART_TYPES.find((c) => c.value === type);\n const section = settingsSection(def ? chartTypeLabel(def, this.t) : type);\n const own = () => this.currentSettings?.chartTypeOptions ?? {};\n /** Change one type's settings: the rest of its own stay. */\n const set = <K extends keyof ChartTypeOptions>(key: K, value: NonNullable<ChartTypeOptions[K]>) =>\n this.patch({ chartTypeOptions: { ...own(), [key]: value } });\n const number = (label: MessageKey, value: number | null, limits: NumberLimits, onChange: (v: number | null) => void) =>\n section.appendChild(numberRow(this.t(label), value, limits, onChange, this.t, this.currentSettings?.numberLocale || undefined));\n switch (type) {\n case 'renko': {\n const o = all.renko ?? {};\n number('settings.boxSize', typeof o.boxSize === 'number' ? o.boxSize : null, SIZE_LIMITS,\n (v) => set('renko', { ...(own().renko ?? {}), boxSize: v ?? 'atr' }));\n number('settings.atrPeriod', o.atrPeriod ?? null, { step: '1', max: 500 }, (v) => set('renko', withValue(own().renko, 'atrPeriod', v)));\n break;\n }\n case 'lineBreak':\n number('settings.lineBreakLines', all.lineBreak?.lines ?? null, { step: '1', max: 10 }, (v) => set('lineBreak', withValue(own().lineBreak, 'lines', v)));\n break;\n case 'kagi':\n number('settings.reversal', all.kagi?.reversal ?? null, SIZE_LIMITS, (v) => set('kagi', withValue(own().kagi, 'reversal', v)));\n section.appendChild(selectRow(this.t('settings.reversalType'), all.kagi?.reversalType ?? 'percent', [\n { value: 'percent', label: this.t('settings.reversalType.percent') },\n { value: 'price', label: this.t('settings.reversalType.price') },\n ], (v) => set('kagi', { ...(own().kagi ?? {}), reversalType: v === 'price' ? 'price' : 'percent' })));\n break;\n case 'pointAndFigure':\n number('settings.boxSize', typeof all.pointAndFigure?.boxSize === 'number' ? all.pointAndFigure.boxSize : null, SIZE_LIMITS,\n (v) => set('pointAndFigure', { ...(own().pointAndFigure ?? {}), boxSize: v ?? 'auto' }));\n number('settings.reversalBoxes', all.pointAndFigure?.reversal ?? null, { step: '1', max: 10 },\n (v) => set('pointAndFigure', withValue(own().pointAndFigure, 'reversal', v)));\n break;\n case 'rangeBars':\n number('settings.barRange', typeof all.rangeBars?.range === 'number' ? all.rangeBars.range : null, SIZE_LIMITS,\n (v) => set('rangeBars', { range: v ?? 'auto' }));\n break;\n default:\n break;\n }\n for (const row of seriesRows(type)) section.appendChild(this.lookRow(row));\n this.bodyEl.appendChild(section);\n }\n\n private patch(partial: Partial<ChartSettingsState>): void {\n if (this.currentSettings) Object.assign(this.currentSettings, partial);\n this.callbacks.onChange(partial);\n }\n}\n\n/** Whether two settings say the same, whatever order their keys were set in, at any depth. */\nfunction sameSettings(a: ChartSettingsState, b: ChartSettingsState): boolean {\n return sameValue(a, b);\n}\n\nfunction sameValue(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) return false;\n if (Array.isArray(a) !== Array.isArray(b)) return false;\n const x = a as Record<string, unknown>;\n const y = b as Record<string, unknown>;\n // A key set to undefined is as one not there, as JSON has it.\n const keys = new Set([...Object.keys(x), ...Object.keys(y)].filter((k) => x[k] !== undefined || y[k] !== undefined));\n for (const key of keys) if (!sameValue(x[key], y[key])) return false;\n return true;\n}\n\n/** `settings` with `key` set to `value`, or without it (back to its default) for null. */\nfunction withValue<T extends object, K extends string>(settings: T | undefined, key: K, value: number | null): T {\n const next = { ...(settings ?? {}) } as Record<string, unknown>;\n if (value === null) delete next[key];\n else next[key] = value;\n return next as T;\n}\n\nfunction asLineStyle(v: string): LineStyle {\n return v === 'dashed' || v === 'dotted' ? v : 'solid';\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"WidgetSettings-B1ay0W6I.js","names":[],"sources":["../src/widget/settingsRows.ts","../src/widget/WidgetSettings.ts"],"sourcesContent":["import { toHex } from './settingsControls.js';\nimport { fill, type Translator } from './i18n.js';\n\n/**\n * The rows of the chart settings: a section, a colour, a switch, a choice,\n * a slider and a number, each with its label and calling back on change.\n */\n\n/** Ids for the colour rows' descriptions. */\nlet colorRowCount = 0;\n/** Ids for the number rows' hints. */\nlet numberRowCount = 0;\n/** The most decimals a number in a hint shows: the smallest size taken, 0.00000001, has 8. */\nconst HINT_MAX_DECIMALS = 20;\n\n/** A group of rows; a title names it to a screen reader too (rows named alike under several titles). */\nexport function settingsSection(title?: string): HTMLDivElement {\n const div = document.createElement('div');\n div.className = 'tcw-settings-section';\n if (title) {\n const heading = document.createElement('div');\n heading.className = 'tcw-settings-section-title';\n heading.textContent = title;\n div.appendChild(heading);\n div.setAttribute('role', 'group');\n div.setAttribute('aria-label', title);\n }\n return div;\n}\n\nfunction labelledRow(label: string): HTMLDivElement {\n const row = document.createElement('div');\n row.className = 'tcw-settings-row';\n const lbl = document.createElement('span');\n lbl.className = 'tcw-settings-label';\n lbl.textContent = label;\n row.appendChild(lbl);\n return row;\n}\n\n/**\n * A colour of the look, shown again from `look.read()`. With `look.start`,\n * null is the part's own colour: shown as Auto, the picker starting from\n * `start()`, and once set a button takes it back.\n */\nexport function colorRow(\n label: string,\n value: string | null,\n onChange: (v: string | null) => void,\n look: { read: () => string | null; start?: () => string | number | boolean | null },\n t: Translator,\n): { row: HTMLDivElement; sync: () => void } {\n const row = labelledRow(label);\n const wrap = document.createElement('div');\n wrap.className = 'tcw-color-picker-wrap';\n const input = document.createElement('input');\n input.type = 'color';\n input.setAttribute('aria-label', label);\n // What the swatch can't say (Auto, a colour with transparency) is read with it.\n const hex = document.createElement('span');\n hex.className = 'tcw-color-hex';\n hex.id = `tcw-color-${++colorRowCount}`;\n input.setAttribute('aria-describedby', hex.id);\n\n let back: HTMLButtonElement | null = null;\n const show = (v: string | null) => {\n input.value = toHex(v ?? look.start?.());\n hex.textContent = v ?? t('settings.auto');\n row.classList.toggle('tcw-color-auto', v === null);\n if (v !== null && look.start && !back) {\n back = document.createElement('button');\n back.type = 'button';\n back.className = 'tcw-color-auto-btn';\n back.textContent = t('settings.auto');\n back.setAttribute('aria-label', `${label}: ${t('settings.auto')}`);\n back.addEventListener('click', () => {\n onChange(null);\n // Focus stays in the row as the button goes; the chart may still draw a colour the host set.\n input.focus();\n show(look.read());\n });\n wrap.appendChild(back);\n } else if (v === null && back) {\n back.remove();\n back = null;\n }\n };\n input.addEventListener('input', () => {\n onChange(input.value);\n show(input.value);\n });\n wrap.append(input, hex);\n row.appendChild(wrap);\n show(value);\n return { row, sync: () => show(look.read()) };\n}\n\nexport function toggleRow(label: string, value: boolean, onChange: (v: boolean) => void): HTMLDivElement {\n const row = labelledRow(label);\n const toggle = document.createElement('button');\n toggle.type = 'button';\n toggle.className = `tcw-toggle${value ? ' tcw-on' : ''}`;\n toggle.setAttribute('role', 'switch');\n toggle.setAttribute('aria-checked', String(value));\n toggle.setAttribute('aria-label', label);\n toggle.addEventListener('click', () => {\n const next = !toggle.classList.contains('tcw-on');\n toggle.classList.toggle('tcw-on', next);\n toggle.setAttribute('aria-checked', String(next));\n onChange(next);\n });\n row.appendChild(toggle);\n return row;\n}\n\nexport function selectRow(\n label: string,\n value: string,\n options: readonly { label: string; value: string }[],\n onChange: (v: string) => void,\n): HTMLDivElement {\n const row = labelledRow(label);\n const select = document.createElement('select');\n select.className = 'tcw-settings-select';\n select.setAttribute('aria-label', label);\n for (const opt of options) {\n const o = document.createElement('option');\n o.value = opt.value;\n o.textContent = opt.label;\n if (opt.value === value) o.selected = true;\n select.appendChild(o);\n }\n // A value none of the options has (two keys that differ): nothing chosen, so any pick is a change.\n if (!options.some((opt) => opt.value === value)) select.selectedIndex = -1;\n select.addEventListener('change', () => onChange(select.value));\n row.appendChild(select);\n return row;\n}\n\nexport function rangeRow(\n label: string,\n value: number,\n range: { min: number; max: number; step: number },\n onChange: (v: number) => void,\n format: (v: number) => string = (v) => String(v),\n): HTMLDivElement {\n const row = labelledRow(label);\n const wrap = document.createElement('div');\n wrap.className = 'tcw-settings-range';\n const input = document.createElement('input');\n input.type = 'range';\n input.min = String(range.min);\n input.max = String(range.max);\n input.step = String(range.step);\n input.value = String(value);\n input.setAttribute('aria-label', label);\n const out = document.createElement('span');\n out.className = 'tcw-settings-range-val';\n out.textContent = format(value);\n input.addEventListener('input', () => {\n const v = Number(input.value);\n out.textContent = format(v);\n onChange(v);\n });\n wrap.append(input, out);\n row.appendChild(wrap);\n return row;\n}\n\n/** What a number field takes. */\nexport interface NumberLimits {\n /** The field's step: '1' takes whole counts only, 'any' any number. */\n step: string;\n /** The largest number taken (Infinity: no limit). */\n max: number;\n /** The smallest number taken; without one, any number above 0. */\n min?: number;\n}\n\n/** What a number field takes, in words: the hint under it once it turned a number away. */\nfunction limitsText(limits: NumberLimits, t: Translator, locale: string): string {\n const format = new Intl.NumberFormat(locale, { maximumFractionDigits: HINT_MAX_DECIMALS }).format;\n if (limits.step === '1' && Number.isFinite(limits.max)) {\n return fill(t('settings.numberWhole'), { min: format(Math.max(1, limits.min ?? 1)), max: format(limits.max) });\n }\n return fill(t('settings.numberAtLeast'), { min: format(limits.min ?? 0) });\n}\n\n/**\n * A number field; empty means \"worked out from the data\" (shown as Auto). Only numbers above 0, and from\n * `limits.min` on, are taken; one turned away is marked invalid, and a hint under it, in `locale`, says what is.\n */\nexport function numberRow(\n label: string,\n value: number | null,\n limits: NumberLimits,\n onChange: (v: number | null) => void,\n t: Translator,\n locale = 'en-US',\n): HTMLDivElement {\n const row = document.createElement('div');\n row.className = 'tcw-settings-row tcw-settings-row--number';\n const lbl = document.createElement('label');\n lbl.className = 'tcw-settings-label';\n lbl.textContent = label;\n row.appendChild(lbl);\n const input = document.createElement('input');\n input.type = 'number';\n input.className = 'tcw-settings-number';\n // The min attribute is also where the arrows step from: at 1e-8, the up arrow turns 5 into 5.00000001 and an\n // empty field into 1e-8. It stays 0, and the smallest number taken is checked on change.\n input.min = '0';\n input.step = limits.step;\n if (Number.isFinite(limits.max)) input.max = String(limits.max);\n input.placeholder = t('settings.auto');\n input.value = value === null ? '' : String(value);\n input.setAttribute('aria-label', label);\n // Written when a number is turned away, and heard with the field: red alone says nothing to a screen reader.\n const hint = document.createElement('div');\n hint.className = 'tcw-settings-hint';\n hint.id = `tcw-number-hint-${++numberRowCount}`;\n hint.setAttribute('role', 'status');\n input.setAttribute('aria-describedby', hint.id);\n const mark = (ok: boolean) => {\n if (ok) input.removeAttribute('aria-invalid');\n else input.setAttribute('aria-invalid', 'true');\n hint.textContent = ok ? '' : limitsText(limits, t, locale);\n };\n input.addEventListener('change', () => {\n if (input.value.trim() === '') {\n mark(true);\n onChange(null);\n return;\n }\n const v = Number(input.value);\n const ok = Number.isFinite(v) && v > 0 && v >= (limits.min ?? 0) && v <= limits.max && (limits.step !== '1' || Number.isInteger(v));\n mark(ok);\n if (ok) onChange(v);\n });\n row.append(input, hint);\n return row;\n}\n","import { CHART_STYLE_KEYS, type ChartType, type ChartTypeOptions, type LineStyle } from '@tradecanvas/commons';\nimport type { ChartSettingsState, SettingsCallbacks, SettingsStylePatch } from './types.js';\nimport { CHART_TYPES } from './widgetConfig.js';\nimport {\n APPEARANCE_SECTIONS, HIGH_LOW_SECTION, LAST_PRICE_SECTION, LEGEND_ROWS, SCALE_ROWS, STATUS_LINE_ROWS, TRADING_SECTIONS, VOLUME_SECTION,\n seriesRows, type LookRow, type LookSection,\n} from './widgetSettingsLook.js';\nimport { chartTypeLabel, numberLocaleOptions } from './widgetLocales.js';\nimport { createChartTypeIcon, createIcon } from './icons.js';\nimport { timezoneOptions } from './widgetTimezones.js';\nimport { FOCUSABLE, keepTabInside } from './focusTrap.js';\nimport { WidgetContextMenu, type ContextMenuEntry } from './WidgetContextMenu.js';\nimport { colorRow, numberRow, rangeRow, selectRow, settingsSection, toggleRow, type NumberLimits } from './settingsRows.js';\nimport { fill, type MessageKey, type Translator } from './i18n.js';\n\nexport type SettingsTab = 'symbol' | 'statusLine' | 'scales' | 'appearance' | 'layers' | 'trading';\ntype Tab = SettingsTab;\n\n/** The tabs down the side, in the order a trader looks: the symbol first, the trading colours last. */\nconst TABS: readonly { id: Tab; icon: string }[] = [\n { id: 'symbol', icon: 'chartType:candlestick' },\n { id: 'statusLine', icon: 'type' },\n { id: 'scales', icon: 'ruler' },\n { id: 'appearance', icon: 'palette' },\n { id: 'layers', icon: 'layers' },\n { id: 'trading', icon: 'trendingUp' },\n];\n/** The widths a line takes in the settings, in pixels. */\nconst LINE_WIDTHS = [1, 2, 3, 4];\n/** A template's entry in the Template menu, by its name. */\nconst TEMPLATE_ID = 't:';\n/**\n * The smallest box, reversal or range the chart type's settings take: a\n * hundred-millionth, the finest price step markets commonly quote. A size\n * far under the prices is no use; the chart raises one that would make too\n * many bars anyway, but a slip like 1e-9 is turned away here.\n */\nconst MIN_TYPE_SIZE = 1e-8;\n/** A box, reversal or range: any number from MIN_TYPE_SIZE up. */\nconst SIZE_LIMITS: NumberLimits = { step: 'any', max: Infinity, min: MIN_TYPE_SIZE };\n\nlet nextSettingsId = 1;\n\n/**\n * The chart's settings: tabs down the side (Symbol, Status line, Scales,\n * Appearance, Layers, Trading), each change shown at once. Cancel (Escape,\n * the close button, a click outside) puts it all back, OK keeps it; the\n * Template menu applies, saves and deletes templates, and resets.\n */\nexport class WidgetSettings {\n private callbacks: SettingsCallbacks;\n private t: Translator;\n private backdrop: HTMLDivElement | null = null;\n private modal: HTMLDivElement | null = null;\n private bodyEl: HTMLDivElement | null = null;\n private tabButtons: HTMLButtonElement[] = [];\n private templateBtn: HTMLButtonElement | null = null;\n private menu: WidgetContextMenu | null = null;\n private currentTab: Tab = 'symbol';\n private currentSettings: ChartSettingsState | null = null;\n /** The chart's type, whose settings the Symbol tab offers. */\n private chartType: ChartType | null = null;\n /** The look's rows on view, each showing the chart's value again (a change to one moves others: a wick with its body). */\n private lookRows: { el: HTMLElement; sync: () => void }[] = [];\n private returnFocus: HTMLElement | null = null;\n private readonly uid = nextSettingsId++;\n\n /**\n * `barCountdown` / `logScale` / `legend` / `volume` false leave out the\n * controls for features the chart has switched off: there they would do\n * nothing.\n */\n constructor(\n callbacks: SettingsCallbacks,\n t: Translator,\n private readonly available: {\n barCountdown?: boolean;\n logScale?: boolean;\n legend?: boolean;\n volume?: boolean;\n /** The exchange's time zone to offer (null while unknown), or undefined when there is none to offer. */\n exchangeZone?: () => string | null | undefined;\n /** false: the chart doesn't trade, so the orders' colours aren't offered. */\n trading?: boolean;\n } = {},\n /** Where the panel mounts (the widget's portal: themed, and inside it when fullscreen). */\n private readonly host: () => HTMLElement = () => document.body,\n ) {\n this.callbacks = callbacks;\n this.t = t;\n }\n\n /** Open on `tab` (the Symbol tab unless asked: the price axis's menu asks for Scales). */\n open(currentSettings: ChartSettingsState, chartType: ChartType | null = null, tab: SettingsTab = 'symbol'): void {\n if (this.modal) this.remove();\n this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n this.currentSettings = { ...currentSettings };\n this.chartType = chartType;\n this.currentTab = tab;\n this.buildModal();\n this.tabButtons.find((b) => b.dataset.tab === tab)?.focus();\n }\n\n isOpen(): boolean {\n return this.modal !== null;\n }\n\n /** Show `settings` when they differ from what the dialog shows: a change made outside it while it is open. */\n follow(settings: ChartSettingsState): void {\n if (!this.modal || (this.currentSettings && sameSettings(this.currentSettings, settings))) return;\n this.refresh(settings);\n }\n\n /** The settings as they are now (after an undo, a template), on the tab that's open; `chartType` when it changed. */\n refresh(settings: ChartSettingsState, chartType?: ChartType | null): void {\n if (!this.modal) return;\n this.currentSettings = { ...settings };\n if (chartType !== undefined) this.chartType = chartType;\n // A change from outside (a compare's bars, the host's setSettings) builds the panel again under the\n // control in focus: focus goes to the one in its place, not to the page outside the dialog.\n const focused = this.focusedControl();\n this.renderTabContent();\n if (focused !== null) this.focusControl(focused);\n }\n\n /** The place of the control in focus among the panel's, or null when focus is not in the panel. */\n private focusedControl(): number | null {\n const active = document.activeElement;\n if (!this.bodyEl || !(active instanceof HTMLElement) || !this.bodyEl.contains(active)) return null;\n const at = this.panelControls().indexOf(active);\n return at < 0 ? null : at;\n }\n\n /** Focus the panel's control at `index`, or its last when it has fewer; the tab when it has none. */\n private focusControl(index: number): void {\n const controls = this.panelControls();\n const control = controls[Math.min(index, controls.length - 1)] ?? this.tabButtons.find((b) => b.dataset.tab === this.currentTab);\n control?.focus();\n }\n\n private panelControls(): HTMLElement[] {\n return this.bodyEl ? [...this.bodyEl.querySelectorAll<HTMLElement>(FOCUSABLE)] : [];\n }\n\n /** Close, keeping what was changed (as OK does). */\n close(): void {\n this.finish(true);\n }\n\n destroy(): void {\n this.remove();\n }\n\n /** OK (`keep`) or Cancel, then closed, focus back where the dialog was opened from. */\n private finish(keep: boolean): void {\n if (!this.modal) return;\n if (keep) this.callbacks.onClose();\n else this.callbacks.onCancel?.();\n this.remove();\n if (this.returnFocus?.isConnected) this.returnFocus.focus();\n this.returnFocus = null;\n }\n\n private remove(): void {\n this.menu?.destroy();\n this.menu = null;\n this.backdrop?.remove();\n this.backdrop = this.modal = this.bodyEl = this.templateBtn = null;\n this.tabButtons = [];\n }\n\n private buildModal(): void {\n const backdrop = document.createElement('div');\n backdrop.className = 'tcw-modal-backdrop';\n // A press that starts in the dialog (a slider dragged, text selected) and ends on the backdrop doesn't cancel 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.finish(false);\n pressedBackdrop = false;\n });\n const modal = document.createElement('div');\n modal.className = 'tcw-modal tcw-set';\n modal.setAttribute('role', 'dialog');\n modal.setAttribute('aria-modal', 'true');\n modal.setAttribute('aria-labelledby', `tcw-set-title-${this.uid}`);\n modal.tabIndex = -1;\n modal.addEventListener('keydown', (e) => {\n if (e.key === 'Escape') {\n e.preventDefault();\n e.stopPropagation();\n this.finish(false);\n return;\n }\n keepTabInside(e, modal);\n });\n this.backdrop = backdrop;\n this.modal = modal;\n modal.append(this.buildHeader(), this.buildBody(), this.buildFooter());\n backdrop.appendChild(modal);\n this.host().appendChild(backdrop);\n this.markTabs();\n this.renderTabContent();\n }\n\n private buildHeader(): HTMLDivElement {\n const header = document.createElement('div');\n header.className = 'tcw-modal-header';\n const title = document.createElement('h3');\n title.id = `tcw-set-title-${this.uid}`;\n title.textContent = this.t('settings.title');\n const closeBtn = document.createElement('button');\n closeBtn.type = 'button';\n closeBtn.className = 'tcw-modal-close';\n closeBtn.setAttribute('aria-label', this.t('common.close'));\n closeBtn.innerHTML = createIcon('x', 16);\n closeBtn.addEventListener('click', () => this.finish(false));\n header.append(title, closeBtn);\n return header;\n }\n\n /** The tabs down the side, and the open one's settings beside them. */\n private buildBody(): HTMLDivElement {\n const body = document.createElement('div');\n body.className = 'tcw-set-body';\n const nav = document.createElement('div');\n nav.className = 'tcw-set-nav';\n nav.setAttribute('role', 'tablist');\n nav.setAttribute('aria-orientation', 'vertical');\n nav.setAttribute('aria-label', this.t('settings.title'));\n nav.addEventListener('keydown', (e) => this.onTabKey(e));\n this.tabButtons = TABS.map(({ id, icon }) => {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'tcw-set-tab';\n btn.id = `tcw-set-tab-${this.uid}-${id}`;\n btn.dataset.tab = id;\n btn.setAttribute('role', 'tab');\n btn.setAttribute('aria-controls', `tcw-set-panel-${this.uid}`);\n const svg = icon.startsWith('chartType:') ? createChartTypeIcon(icon.slice('chartType:'.length) as ChartType, 16) : createIcon(icon, 16);\n btn.innerHTML = `${svg}<span></span>`;\n btn.querySelector('span')!.textContent = this.t(`settings.tab.${id}` as MessageKey);\n btn.addEventListener('click', () => this.selectTab(id));\n return btn;\n });\n nav.append(...this.tabButtons);\n const panel = document.createElement('div');\n panel.className = 'tcw-modal-body tcw-set-panel';\n panel.id = `tcw-set-panel-${this.uid}`;\n panel.setAttribute('role', 'tabpanel');\n this.bodyEl = panel;\n body.append(nav, panel);\n return body;\n }\n\n /** Template on the left; Cancel and OK on the right. */\n private buildFooter(): HTMLDivElement {\n const footer = document.createElement('div');\n footer.className = 'tcw-modal-footer';\n const template = this.footerButton('template', 'tcw-footer-menu', () => this.openTemplates());\n template.setAttribute('aria-haspopup', 'menu');\n template.setAttribute('aria-expanded', 'false');\n template.innerHTML = `<span></span>${createIcon('chevronDown', 12)}`;\n template.querySelector('span')!.textContent = this.t('settings.template');\n this.templateBtn = template;\n const end = document.createElement('div');\n end.className = 'tcw-footer-end';\n end.append(\n this.footerButton('cancel', 'tcw-footer-cancel', () => this.finish(false), this.t('common.cancel')),\n this.footerButton('ok', 'tcw-done-btn', () => this.finish(true), this.t('drawingSettings.ok')),\n );\n footer.append(template, end);\n return footer;\n }\n\n private footerButton(act: string, className: string, onClick: () => void, text?: string): HTMLButtonElement {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = className;\n btn.dataset.act = act;\n if (text) btn.textContent = text;\n btn.addEventListener('click', onClick);\n return btn;\n }\n\n private markTabs(): void {\n for (const btn of this.tabButtons) {\n const on = btn.dataset.tab === this.currentTab;\n btn.classList.toggle('tcw-active', on);\n btn.setAttribute('aria-selected', String(on));\n btn.tabIndex = on ? 0 : -1;\n if (on) this.bodyEl?.setAttribute('aria-labelledby', btn.id);\n }\n }\n\n private selectTab(tab: Tab, focus = false): void {\n this.currentTab = tab;\n this.markTabs();\n this.renderTabContent();\n if (focus) this.tabButtons.find((b) => b.dataset.tab === tab)?.focus();\n }\n\n /** Through the tabs (Home, End), picking as they go: up and down, or along the row of chips on a phone. */\n private onTabKey(e: KeyboardEvent): void {\n const at = TABS.findIndex((tab) => tab.id === this.currentTab);\n const next = e.key === 'ArrowDown' || e.key === 'ArrowRight' ? (at + 1) % TABS.length\n : e.key === 'ArrowUp' || e.key === 'ArrowLeft' ? (at - 1 + TABS.length) % TABS.length\n : e.key === 'Home' ? 0\n : e.key === 'End' ? TABS.length - 1\n : -1;\n if (next < 0) return;\n e.preventDefault();\n this.selectTab(TABS[next].id, true);\n }\n\n /** The Template menu: the saved templates (each removable), Save as template, Reset to defaults. */\n private openTemplates(): void {\n const btn = this.templateBtn;\n if (!this.modal || !btn) return;\n if (this.menu?.isOpen()) {\n this.menu.close();\n return;\n }\n const templates = this.callbacks.templates;\n const saved: ContextMenuEntry[] = (templates?.list() ?? []).map((name) => ({\n id: `${TEMPLATE_ID}${name}`, label: name, icon: 'layers', remove: fill(this.t('templates.delete'), { name }),\n }));\n const entries: ContextMenuEntry[] = [\n ...saved,\n ...(saved.length > 0 ? ['separator' as const] : []),\n ...(templates ? [{ id: 'save', label: this.t('settings.saveTemplate'), icon: 'save' }] : []),\n { id: 'reset', label: this.t('settings.resetToDefaults'), icon: 'reset' },\n ];\n this.menu ??= new WidgetContextMenu(this.modal, this.t('settings.template'));\n const at = btn.getBoundingClientRect();\n const box = this.modal.getBoundingClientRect();\n // From the button's top: in the footer there is no room below, so it opens above the button.\n this.menu.open(entries, at.left - box.left, at.top - box.top, (id) => {\n if (id === 'reset') this.callbacks.onReset();\n else if (id === 'save') templates?.save();\n else if (id.startsWith(TEMPLATE_ID)) templates?.apply(id.slice(TEMPLATE_ID.length));\n }, btn, (id) => templates?.remove(id.slice(TEMPLATE_ID.length)));\n }\n\n private renderTabContent(): void {\n if (!this.bodyEl || !this.currentSettings) return;\n this.bodyEl.replaceChildren();\n this.lookRows = [];\n switch (this.currentTab) {\n case 'symbol': this.renderSymbolTab(this.currentSettings); break;\n case 'statusLine': this.renderStatusLineTab(this.currentSettings); break;\n case 'scales': this.renderScalesTab(this.currentSettings); break;\n case 'appearance': this.renderAppearanceTab(this.currentSettings); break;\n case 'layers': this.renderLayersTab(this.currentSettings); break;\n case 'trading':\n for (const section of TRADING_SECTIONS) {\n if (!section.trading || this.available.trading !== false) this.renderLookSection(section);\n }\n break;\n }\n }\n\n /** The chart type's own settings and colours, the main series, the last price, the volume, the high and low. */\n private renderSymbolTab(s: ChartSettingsState): void {\n this.renderChartTypeSection();\n this.addSection(undefined, [\n toggleRow(this.t('settings.mainSeries'), s.mainSeriesVisible, (v) => this.patch({ mainSeriesVisible: v })),\n toggleRow(this.t('settings.extendedHours'), s.extendedHours, (v) => this.patch({ extendedHours: v })),\n ]);\n // A section's own switch says \"Show\": its title names what it shows.\n const show = this.t('common.show');\n this.renderLookSection(LAST_PRICE_SECTION);\n if (this.available.volume !== false) {\n this.renderLookSection(VOLUME_SECTION, [toggleRow(show, s.volumeVisible, (v) => this.patch({ volumeVisible: v }))]);\n }\n this.renderLookSection(HIGH_LOW_SECTION, [toggleRow(show, s.highLowLines, (v) => this.patch({ highLowLines: v }))]);\n }\n\n /** The legend over the chart: shown or not, its colours; the panes' titles. */\n private renderStatusLineTab(s: ChartSettingsState): void {\n const legend = this.available.legend !== false;\n const rows = legend ? STATUS_LINE_ROWS : STATUS_LINE_ROWS.filter((row) => !LEGEND_ROWS.includes(row));\n this.addSection(undefined, [\n ...(legend ? [toggleRow(this.t('settings.ohlcLegend'), s.legendVisible, (v) => this.patch({ legendVisible: v }))] : []),\n ...rows.map((row) => this.lookRow(row)),\n ]);\n }\n\n /** The price scale's mode and behaviour, its labels, the time zone, how numbers are written, the axes' colours. */\n private renderScalesTab(s: ChartSettingsState): void {\n const scales = [\n { value: 'regular', label: this.t('settings.scale.regular') },\n { value: 'logarithmic', label: this.t('settings.scale.logarithmic') },\n { value: 'percentage', label: this.t('settings.scale.percentage') },\n { value: 'indexedTo100', label: this.t('settings.scale.indexedTo100') },\n ].filter((o) => o.value !== 'logarithmic' || this.available.logScale !== false);\n const exchangeZone = this.available.exchangeZone?.();\n const zones = timezoneOptions(s.timezone, Date.now(), this.t('settings.timezone.local'),\n exchangeZone !== undefined ? { label: this.t('settings.timezone.exchange'), zone: exchangeZone } : undefined);\n this.addSection(undefined, [\n selectRow(this.t('settings.priceScale'), s.scaleMode, scales, (v) => this.patch({ scaleMode: v as ChartSettingsState['scaleMode'] })),\n toggleRow(this.t('settings.autoScale'), s.autoScale, (v) => this.patch({ autoScale: v })),\n toggleRow(this.t('settings.invertScale'), s.invertScale, (v) => this.patch({ invertScale: v })),\n toggleRow(this.t('settings.leftScale'), s.leftPriceScale, (v) => this.patch({ leftPriceScale: v })),\n toggleRow(this.t('settings.indicatorValues'), s.indicatorValueLabels, (v) => this.patch({ indicatorValueLabels: v })),\n toggleRow(this.t('settings.alignAxisLabels'), s.alignAxisLabels, (v) => this.patch({ alignAxisLabels: v })),\n ...(this.available.barCountdown !== false\n ? [toggleRow(this.t('settings.barCountdown'), s.barCountdown, (v) => this.patch({ barCountdown: v }))]\n : []),\n selectRow(this.t('settings.timezone'), s.timezone, zones, (v) => this.patch({ timezone: v })),\n selectRow(this.t('settings.numberLocale'), s.numberLocale, numberLocaleOptions(s.numberLocale), (v) => this.patch({ numberLocale: v })),\n ]);\n this.addSection(this.t('settings.section.axes'), SCALE_ROWS.map((row) => this.lookRow(row)));\n }\n\n /** The background, the grid, the crosshair, the session breaks, the drawings' handles. */\n private renderAppearanceTab(s: ChartSettingsState): void {\n const [background, grid, crosshair, ...rest] = APPEARANCE_SECTIONS;\n this.renderLookSection(background);\n this.renderLookSection(grid, [toggleRow(this.t('common.show'), s.gridVisible, (v) => this.patch({ gridVisible: v }))]);\n this.renderLookSection(crosshair, [selectRow(this.t('settings.crosshairMode'), s.crosshairMode, [\n { label: this.t('settings.crosshair.magnet'), value: 'magnet' },\n { label: this.t('settings.crosshair.normal'), value: 'normal' },\n { label: this.t('settings.crosshair.hidden'), value: 'hidden' },\n ], (v) => this.patch({ crosshairMode: v as ChartSettingsState['crosshairMode'] })),\n selectRow(this.t('settings.crosshairCursor'), s.crosshairCursor, [\n { label: this.t('drawing.cursorCross'), value: 'cross' },\n { label: this.t('drawing.cursorDot'), value: 'dot' },\n { label: this.t('drawing.cursorArrow'), value: 'arrow' },\n ], (v) => this.patch({ crosshairCursor: v as ChartSettingsState['crosshairCursor'] }))]);\n for (const section of rest) this.renderLookSection(section);\n }\n\n /** What the chart can draw over the bars: the profiles, the depth, the swings, the sessions, the prior levels. */\n private renderLayersTab(s: ChartSettingsState): void {\n const percent = (v: number) => `${Math.round(v * 100)}%`;\n const t = (key: MessageKey) => this.t(key);\n this.addSection(undefined, [toggleRow(t('settings.volumeProfile'), s.volumeProfileVisible, (v) => this.patch({ volumeProfileVisible: v }))]);\n this.addSection(undefined, [\n toggleRow(t('settings.marketProfile'), s.marketProfileVisible, (v) => this.patch({ marketProfileVisible: v })),\n toggleRow(t('settings.marketProfileSplit'), s.marketProfileSplit, (v) => this.patch({ marketProfileSplit: v })),\n toggleRow(t('settings.marketProfileLetters'), s.marketProfileLetters, (v) => this.patch({ marketProfileLetters: v })),\n rangeRow(t('settings.marketProfileBuckets'), s.marketProfileBuckets, { min: 8, max: 200, step: 1 }, (v) => this.patch({ marketProfileBuckets: v })),\n rangeRow(t('settings.marketProfileOpacity'), s.marketProfileOpacity, { min: 0.05, max: 1, step: 0.05 }, (v) => this.patch({ marketProfileOpacity: v }), percent),\n ]);\n this.addSection(undefined, [\n toggleRow(t('settings.depthHeatmap'), s.depthHeatmapVisible, (v) => this.patch({ depthHeatmapVisible: v })),\n rangeRow(t('settings.depthHeatmapOpacity'), s.depthHeatmapOpacity, { min: 0.1, max: 1, step: 0.05 }, (v) => this.patch({ depthHeatmapOpacity: v }), percent),\n ]);\n this.addSection(undefined, [\n toggleRow(t('settings.swingMarkers'), s.pivotMarkersVisible, (v) => this.patch({ pivotMarkersVisible: v })),\n rangeRow(t('settings.swingStrength'), s.pivotStrength, { min: 2, max: 20, step: 1 }, (v) => this.patch({ pivotStrength: v })),\n toggleRow(t('settings.swingStructure'), s.pivotStructureLabels, (v) => this.patch({ pivotStructureLabels: v })),\n ]);\n this.addSection(undefined, [\n toggleRow(t('settings.sessionShading'), s.sessionShadingVisible, (v) => this.patch({ sessionShadingVisible: v })),\n toggleRow(t('settings.periodLevels'), s.periodLevelsVisible, (v) => this.patch({ periodLevelsVisible: v })),\n selectRow(t('settings.periodLevelsBasis'), s.periodLevelsPeriod, [\n { value: 'day', label: t('settings.priorDay') },\n { value: 'week', label: t('settings.priorWeek') },\n ], (v) => this.patch({ periodLevelsPeriod: v as ChartSettingsState['periodLevelsPeriod'] })),\n ]);\n }\n\n private addSection(title: string | undefined, rows: readonly HTMLElement[]): HTMLDivElement {\n const section = settingsSection(title);\n section.append(...rows);\n this.bodyEl?.appendChild(section);\n return section;\n }\n\n /** A section of the look, after `lead` (the switch it goes with, say). */\n private renderLookSection(section: LookSection, lead: readonly HTMLElement[] = []): void {\n this.addSection(this.t(section.title), [...lead, ...section.rows.map((row) => this.lookRow(row))]);\n }\n\n /** A row of the look: a colour, a switch, a dash or a width, as its key takes it, on the user's layer. */\n private lookRow(row: LookRow): HTMLDivElement {\n const label = this.t(row.label);\n const read = () => this.callbacks.styleValue(row.keys[0]);\n /** The keys' value, or '' when they differ (the host set each way apart): any pick then sets them all. */\n const shared = (): string => {\n const values = row.keys.map((key) => this.callbacks.styleValue(key));\n return values.every((v) => v === values[0]) && values[0] !== null ? String(values[0]) : '';\n };\n let el: HTMLDivElement;\n const set = (v: string | number | boolean | null) => {\n this.callbacks.onStyleChange(Object.fromEntries(row.keys.map((key) => [key, v])) as SettingsStylePatch);\n for (const other of this.lookRows) if (other.el !== el) other.sync();\n };\n const auto = row.auto ? [{ value: '', label: this.t('settings.auto') }] : [];\n let sync: () => void;\n switch (CHART_STYLE_KEYS[row.keys[0]]) {\n case 'boolean': {\n el = toggleRow(label, read() === true, set);\n const toggle = el.querySelector('button')!;\n sync = () => {\n const on = read() === true;\n toggle.classList.toggle('tcw-on', on);\n toggle.setAttribute('aria-checked', String(on));\n };\n break;\n }\n case 'lineStyle':\n el = selectRow(label, shared(), [...auto, ...this.lineStyles()], (v) => set(v === '' ? null : asLineStyle(v)));\n sync = () => { el.querySelector('select')!.value = shared(); };\n break;\n case 'width': {\n const value = read();\n const widths = typeof value === 'number' && !LINE_WIDTHS.includes(value) ? [...LINE_WIDTHS, value].sort((a, b) => a - b) : LINE_WIDTHS;\n el = selectRow(label, shared(), [...auto, ...widths.map((w) => ({ value: String(w), label: `${w}px` }))],\n (v) => set(v === '' ? null : Number(v)));\n sync = () => { el.querySelector('select')!.value = shared(); };\n break;\n }\n default: {\n const value = read();\n const colour = colorRow(label, typeof value === 'string' ? value : null, set, {\n read: () => { const v = read(); return typeof v === 'string' ? v : null; },\n start: row.auto ? () => (row.auto?.from ? this.callbacks.styleValue(row.auto.from) : row.auto?.hint) ?? null : undefined,\n }, this.t);\n el = colour.row;\n sync = colour.sync;\n }\n }\n this.lookRows.push({ el, sync });\n return el;\n }\n\n private lineStyles(): { value: string; label: string }[] {\n return [\n { value: 'solid', label: this.t('drawingSettings.lineStyle.solid') },\n { value: 'dashed', label: this.t('drawingSettings.lineStyle.dashed') },\n { value: 'dotted', label: this.t('drawingSettings.lineStyle.dotted') },\n ];\n }\n\n /** The chart's type: its settings (Renko's box, Kagi's reversal…) and its colours and widths. */\n private renderChartTypeSection(): void {\n if (!this.bodyEl || !this.currentSettings || !this.chartType) return;\n const type = this.chartType;\n const all = this.currentSettings.chartTypeOptions ?? {};\n const def = CHART_TYPES.find((c) => c.value === type);\n const section = settingsSection(def ? chartTypeLabel(def, this.t) : type);\n const own = () => this.currentSettings?.chartTypeOptions ?? {};\n /** Change one type's settings: the rest of its own stay. */\n const set = <K extends keyof ChartTypeOptions>(key: K, value: NonNullable<ChartTypeOptions[K]>) =>\n this.patch({ chartTypeOptions: { ...own(), [key]: value } });\n const number = (label: MessageKey, value: number | null, limits: NumberLimits, onChange: (v: number | null) => void) =>\n section.appendChild(numberRow(this.t(label), value, limits, onChange, this.t, this.currentSettings?.numberLocale || undefined));\n switch (type) {\n case 'renko': {\n const o = all.renko ?? {};\n number('settings.boxSize', typeof o.boxSize === 'number' ? o.boxSize : null, SIZE_LIMITS,\n (v) => set('renko', { ...(own().renko ?? {}), boxSize: v ?? 'atr' }));\n number('settings.atrPeriod', o.atrPeriod ?? null, { step: '1', max: 500 }, (v) => set('renko', withValue(own().renko, 'atrPeriod', v)));\n break;\n }\n case 'lineBreak':\n number('settings.lineBreakLines', all.lineBreak?.lines ?? null, { step: '1', max: 10 }, (v) => set('lineBreak', withValue(own().lineBreak, 'lines', v)));\n break;\n case 'kagi':\n number('settings.reversal', all.kagi?.reversal ?? null, SIZE_LIMITS, (v) => set('kagi', withValue(own().kagi, 'reversal', v)));\n section.appendChild(selectRow(this.t('settings.reversalType'), all.kagi?.reversalType ?? 'percent', [\n { value: 'percent', label: this.t('settings.reversalType.percent') },\n { value: 'price', label: this.t('settings.reversalType.price') },\n ], (v) => set('kagi', { ...(own().kagi ?? {}), reversalType: v === 'price' ? 'price' : 'percent' })));\n break;\n case 'pointAndFigure':\n number('settings.boxSize', typeof all.pointAndFigure?.boxSize === 'number' ? all.pointAndFigure.boxSize : null, SIZE_LIMITS,\n (v) => set('pointAndFigure', { ...(own().pointAndFigure ?? {}), boxSize: v ?? 'auto' }));\n number('settings.reversalBoxes', all.pointAndFigure?.reversal ?? null, { step: '1', max: 10 },\n (v) => set('pointAndFigure', withValue(own().pointAndFigure, 'reversal', v)));\n break;\n case 'rangeBars':\n number('settings.barRange', typeof all.rangeBars?.range === 'number' ? all.rangeBars.range : null, SIZE_LIMITS,\n (v) => set('rangeBars', { range: v ?? 'auto' }));\n break;\n default:\n break;\n }\n for (const row of seriesRows(type)) section.appendChild(this.lookRow(row));\n this.bodyEl.appendChild(section);\n }\n\n private patch(partial: Partial<ChartSettingsState>): void {\n if (this.currentSettings) Object.assign(this.currentSettings, partial);\n this.callbacks.onChange(partial);\n }\n}\n\n/** Whether two settings say the same, whatever order their keys were set in, at any depth. */\nfunction sameSettings(a: ChartSettingsState, b: ChartSettingsState): boolean {\n return sameValue(a, b);\n}\n\nfunction sameValue(a: unknown, b: unknown): boolean {\n if (a === b) return true;\n if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) return false;\n if (Array.isArray(a) !== Array.isArray(b)) return false;\n const x = a as Record<string, unknown>;\n const y = b as Record<string, unknown>;\n // A key set to undefined is as one not there, as JSON has it.\n const keys = new Set([...Object.keys(x), ...Object.keys(y)].filter((k) => x[k] !== undefined || y[k] !== undefined));\n for (const key of keys) if (!sameValue(x[key], y[key])) return false;\n return true;\n}\n\n/** `settings` with `key` set to `value`, or without it (back to its default) for null. */\nfunction withValue<T extends object, K extends string>(settings: T | undefined, key: K, value: number | null): T {\n const next = { ...(settings ?? {}) } as Record<string, unknown>;\n if (value === null) delete next[key];\n else next[key] = value;\n return next as T;\n}\n\nfunction asLineStyle(v: string): LineStyle {\n return v === 'dashed' || v === 'dotted' ? v : 'solid';\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require(`./widgetLocales-C_XTkni5.cjs`),t=require(`./focusTrap-DrhhmG0V.cjs`),n=require(`./settingsControls-Tn8_vJJv.cjs`),r=require(`./i18n-fgAwciRT.cjs`);let i=require(`@tradecanvas/commons`);var a=0,o=0,s=20;function c(e){let t=document.createElement(`div`);if(t.className=`tcw-settings-section`,e){let n=document.createElement(`div`);n.className=`tcw-settings-section-title`,n.textContent=e,t.appendChild(n),t.setAttribute(`role`,`group`),t.setAttribute(`aria-label`,e)}return t}function l(e){let t=document.createElement(`div`);t.className=`tcw-settings-row`;let n=document.createElement(`span`);return n.className=`tcw-settings-label`,n.textContent=e,t.appendChild(n),t}function u(e,t,r,i,o){let s=l(e),c=document.createElement(`div`);c.className=`tcw-color-picker-wrap`;let u=document.createElement(`input`);u.type=`color`,u.setAttribute(`aria-label`,e);let d=document.createElement(`span`);d.className=`tcw-color-hex`,d.id=`tcw-color-${++a}`,u.setAttribute(`aria-describedby`,d.id);let f=null,p=t=>{u.value=n.l(t??i.start?.()),d.textContent=t??o(`settings.auto`),s.classList.toggle(`tcw-color-auto`,t===null),t!==null&&i.start&&!f?(f=document.createElement(`button`),f.type=`button`,f.className=`tcw-color-auto-btn`,f.textContent=o(`settings.auto`),f.setAttribute(`aria-label`,`${e}: ${o(`settings.auto`)}`),f.addEventListener(`click`,()=>{r(null),u.focus(),p(i.read())}),c.appendChild(f)):t===null&&f&&(f.remove(),f=null)};return u.addEventListener(`input`,()=>{r(u.value),p(u.value)}),c.append(u,d),s.appendChild(c),p(t),{row:s,sync:()=>p(i.read())}}function d(e,t,n){let r=l(e),i=document.createElement(`button`);return i.type=`button`,i.className=`tcw-toggle${t?` tcw-on`:``}`,i.setAttribute(`role`,`switch`),i.setAttribute(`aria-checked`,String(t)),i.setAttribute(`aria-label`,e),i.addEventListener(`click`,()=>{let e=!i.classList.contains(`tcw-on`);i.classList.toggle(`tcw-on`,e),i.setAttribute(`aria-checked`,String(e)),n(e)}),r.appendChild(i),r}function f(e,t,n,r){let i=l(e),a=document.createElement(`select`);a.className=`tcw-settings-select`,a.setAttribute(`aria-label`,e);for(let e of n){let n=document.createElement(`option`);n.value=e.value,n.textContent=e.label,e.value===t&&(n.selected=!0),a.appendChild(n)}return n.some(e=>e.value===t)||(a.selectedIndex=-1),a.addEventListener(`change`,()=>r(a.value)),i.appendChild(a),i}function p(e,t,n,r,i=e=>String(e)){let a=l(e),o=document.createElement(`div`);o.className=`tcw-settings-range`;let s=document.createElement(`input`);s.type=`range`,s.min=String(n.min),s.max=String(n.max),s.step=String(n.step),s.value=String(t),s.setAttribute(`aria-label`,e);let c=document.createElement(`span`);return c.className=`tcw-settings-range-val`,c.textContent=i(t),s.addEventListener(`input`,()=>{let e=Number(s.value);c.textContent=i(e),r(e)}),o.append(s,c),a.appendChild(o),a}function m(e,t,n){let i=new Intl.NumberFormat(n,{maximumFractionDigits:s}).format;return e.step===`1`&&Number.isFinite(e.max)?r.r(t(`settings.numberWhole`),{min:i(Math.max(1,e.min??1)),max:i(e.max)}):r.r(t(`settings.numberAtLeast`),{min:i(e.min??0)})}function h(e,t,n,r,i,a=`en-US`){let s=document.createElement(`div`);s.className=`tcw-settings-row tcw-settings-row--number`;let c=document.createElement(`label`);c.className=`tcw-settings-label`,c.textContent=e,s.appendChild(c);let l=document.createElement(`input`);l.type=`number`,l.className=`tcw-settings-number`,l.min=`0`,l.step=n.step,Number.isFinite(n.max)&&(l.max=String(n.max)),l.placeholder=i(`settings.auto`),l.value=t===null?``:String(t),l.setAttribute(`aria-label`,e);let u=document.createElement(`div`);u.className=`tcw-settings-hint`,u.id=`tcw-number-hint-${++o}`,u.setAttribute(`role`,`status`),l.setAttribute(`aria-describedby`,u.id);let d=e=>{e?l.removeAttribute(`aria-invalid`):l.setAttribute(`aria-invalid`,`true`),u.textContent=e?``:m(n,i,a)};return l.addEventListener(`change`,()=>{if(l.value.trim()===``){d(!0),r(null);return}let e=Number(l.value),t=Number.isFinite(e)&&e>0&&e>=(n.min??0)&&e<=n.max&&(n.step!==`1`||Number.isInteger(e));d(t),t&&r(e)}),s.append(l,u),s}var g=[{id:`symbol`,icon:`chartType:candlestick`},{id:`statusLine`,icon:`type`},{id:`scales`,icon:`ruler`},{id:`appearance`,icon:`palette`},{id:`layers`,icon:`layers`},{id:`trading`,icon:`trendingUp`}],_=[1,2,3,4],v=`t:`,y={step:`any`,max:1/0,min:1e-8},b=1,x=class{callbacks;t;backdrop=null;modal=null;bodyEl=null;tabButtons=[];templateBtn=null;menu=null;currentTab=`symbol`;currentSettings=null;chartType=null;lookRows=[];returnFocus=null;uid=b++;constructor(e,t,n={},r=()=>document.body){this.available=n,this.host=r,this.callbacks=e,this.t=t}open(e,t=null,n=`symbol`){this.modal&&this.remove(),this.returnFocus=document.activeElement instanceof HTMLElement?document.activeElement:null,this.currentSettings={...e},this.chartType=t,this.currentTab=n,this.buildModal(),this.tabButtons.find(e=>e.dataset.tab===n)?.focus()}isOpen(){return this.modal!==null}follow(e){!this.modal||this.currentSettings&&S(this.currentSettings,e)||this.refresh(e)}refresh(e,t){if(!this.modal)return;this.currentSettings={...e},t!==void 0&&(this.chartType=t);let n=this.focusedControl();this.renderTabContent(),n!==null&&this.focusControl(n)}focusedControl(){let e=document.activeElement;if(!this.bodyEl||!(e instanceof HTMLElement)||!this.bodyEl.contains(e))return null;let t=this.panelControls().indexOf(e);return t<0?null:t}focusControl(e){let t=this.panelControls();(t[Math.min(e,t.length-1)]??this.tabButtons.find(e=>e.dataset.tab===this.currentTab))?.focus()}panelControls(){return this.bodyEl?[...this.bodyEl.querySelectorAll(t.t)]:[]}close(){this.finish(!0)}destroy(){this.remove()}finish(e){this.modal&&(e?this.callbacks.onClose():this.callbacks.onCancel?.(),this.remove(),this.returnFocus?.isConnected&&this.returnFocus.focus(),this.returnFocus=null)}remove(){this.menu?.destroy(),this.menu=null,this.backdrop?.remove(),this.backdrop=this.modal=this.bodyEl=this.templateBtn=null,this.tabButtons=[]}buildModal(){let e=document.createElement(`div`);e.className=`tcw-modal-backdrop`;let n=!1;e.addEventListener(`pointerdown`,t=>{n=t.target===e}),e.addEventListener(`click`,t=>{t.target===e&&n&&this.finish(!1),n=!1});let r=document.createElement(`div`);r.className=`tcw-modal tcw-set`,r.setAttribute(`role`,`dialog`),r.setAttribute(`aria-modal`,`true`),r.setAttribute(`aria-labelledby`,`tcw-set-title-${this.uid}`),r.tabIndex=-1,r.addEventListener(`keydown`,e=>{if(e.key===`Escape`){e.preventDefault(),e.stopPropagation(),this.finish(!1);return}t.n(e,r)}),this.backdrop=e,this.modal=r,r.append(this.buildHeader(),this.buildBody(),this.buildFooter()),e.appendChild(r),this.host().appendChild(e),this.markTabs(),this.renderTabContent()}buildHeader(){let e=document.createElement(`div`);e.className=`tcw-modal-header`;let n=document.createElement(`h3`);n.id=`tcw-set-title-${this.uid}`,n.textContent=this.t(`settings.title`);let r=document.createElement(`button`);return r.type=`button`,r.className=`tcw-modal-close`,r.setAttribute(`aria-label`,this.t(`common.close`)),r.innerHTML=t.i(`x`,16),r.addEventListener(`click`,()=>this.finish(!1)),e.append(n,r),e}buildBody(){let e=document.createElement(`div`);e.className=`tcw-set-body`;let n=document.createElement(`div`);n.className=`tcw-set-nav`,n.setAttribute(`role`,`tablist`),n.setAttribute(`aria-orientation`,`vertical`),n.setAttribute(`aria-label`,this.t(`settings.title`)),n.addEventListener(`keydown`,e=>this.onTabKey(e)),this.tabButtons=g.map(({id:e,icon:n})=>{let r=document.createElement(`button`);return r.type=`button`,r.className=`tcw-set-tab`,r.id=`tcw-set-tab-${this.uid}-${e}`,r.dataset.tab=e,r.setAttribute(`role`,`tab`),r.setAttribute(`aria-controls`,`tcw-set-panel-${this.uid}`),r.innerHTML=`${n.startsWith(`chartType:`)?t.r(n.slice(10),16):t.i(n,16)}<span></span>`,r.querySelector(`span`).textContent=this.t(`settings.tab.${e}`),r.addEventListener(`click`,()=>this.selectTab(e)),r}),n.append(...this.tabButtons);let r=document.createElement(`div`);return r.className=`tcw-modal-body tcw-set-panel`,r.id=`tcw-set-panel-${this.uid}`,r.setAttribute(`role`,`tabpanel`),this.bodyEl=r,e.append(n,r),e}buildFooter(){let e=document.createElement(`div`);e.className=`tcw-modal-footer`;let n=this.footerButton(`template`,`tcw-footer-menu`,()=>this.openTemplates());n.setAttribute(`aria-haspopup`,`menu`),n.setAttribute(`aria-expanded`,`false`),n.innerHTML=`<span></span>${t.i(`chevronDown`,12)}`,n.querySelector(`span`).textContent=this.t(`settings.template`),this.templateBtn=n;let r=document.createElement(`div`);return r.className=`tcw-footer-end`,r.append(this.footerButton(`cancel`,`tcw-footer-cancel`,()=>this.finish(!1),this.t(`common.cancel`)),this.footerButton(`ok`,`tcw-done-btn`,()=>this.finish(!0),this.t(`drawingSettings.ok`))),e.append(n,r),e}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}markTabs(){for(let e of this.tabButtons){let t=e.dataset.tab===this.currentTab;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.currentTab=e,this.markTabs(),this.renderTabContent(),t&&this.tabButtons.find(t=>t.dataset.tab===e)?.focus()}onTabKey(e){let t=g.findIndex(e=>e.id===this.currentTab),n=e.key===`ArrowDown`||e.key===`ArrowRight`?(t+1)%g.length:e.key===`ArrowUp`||e.key===`ArrowLeft`?(t-1+g.length)%g.length:e.key===`Home`?0:e.key===`End`?g.length-1:-1;n<0||(e.preventDefault(),this.selectTab(g[n].id,!0))}openTemplates(){let e=this.templateBtn;if(!this.modal||!e)return;if(this.menu?.isOpen()){this.menu.close();return}let t=this.callbacks.templates,i=(t?.list()??[]).map(e=>({id:`${v}${e}`,label:e,icon:`layers`,remove:r.r(this.t(`templates.delete`),{name:e})})),a=[...i,...i.length>0?[`separator`]:[],...t?[{id:`save`,label:this.t(`settings.saveTemplate`),icon:`save`}]:[],{id:`reset`,label:this.t(`settings.resetToDefaults`),icon:`reset`}];this.menu??=new n.f(this.modal,this.t(`settings.template`));let o=e.getBoundingClientRect(),s=this.modal.getBoundingClientRect();this.menu.open(a,o.left-s.left,o.top-s.top,e=>{e===`reset`?this.callbacks.onReset():e===`save`?t?.save():e.startsWith(v)&&t?.apply(e.slice(2))},e,e=>t?.remove(e.slice(2)))}renderTabContent(){if(!(!this.bodyEl||!this.currentSettings))switch(this.bodyEl.replaceChildren(),this.lookRows=[],this.currentTab){case`symbol`:this.renderSymbolTab(this.currentSettings);break;case`statusLine`:this.renderStatusLineTab(this.currentSettings);break;case`scales`:this.renderScalesTab(this.currentSettings);break;case`appearance`:this.renderAppearanceTab(this.currentSettings);break;case`layers`:this.renderLayersTab(this.currentSettings);break;case`trading`:for(let t of e.d)(!t.trading||this.available.trading!==!1)&&this.renderLookSection(t);break}}renderSymbolTab(t){this.renderChartTypeSection(),this.addSection(void 0,[d(this.t(`settings.mainSeries`),t.mainSeriesVisible,e=>this.patch({mainSeriesVisible:e})),d(this.t(`settings.extendedHours`),t.extendedHours,e=>this.patch({extendedHours:e}))]);let n=this.t(`common.show`);this.renderLookSection(e.o),this.available.volume!==!1&&this.renderLookSection(e.f,[d(n,t.volumeVisible,e=>this.patch({volumeVisible:e}))]),this.renderLookSection(e.a,[d(n,t.highLowLines,e=>this.patch({highLowLines:e}))])}renderStatusLineTab(t){let n=this.available.legend!==!1,r=n?e.u:e.u.filter(t=>!e.s.includes(t));this.addSection(void 0,[...n?[d(this.t(`settings.ohlcLegend`),t.legendVisible,e=>this.patch({legendVisible:e}))]:[],...r.map(e=>this.lookRow(e))])}renderScalesTab(t){let n=[{value:`regular`,label:this.t(`settings.scale.regular`)},{value:`logarithmic`,label:this.t(`settings.scale.logarithmic`)},{value:`percentage`,label:this.t(`settings.scale.percentage`)},{value:`indexedTo100`,label:this.t(`settings.scale.indexedTo100`)}].filter(e=>e.value!==`logarithmic`||this.available.logScale!==!1),r=this.available.exchangeZone?.(),i=e.y(t.timezone,Date.now(),this.t(`settings.timezone.local`),r===void 0?void 0:{label:this.t(`settings.timezone.exchange`),zone:r});this.addSection(void 0,[f(this.t(`settings.priceScale`),t.scaleMode,n,e=>this.patch({scaleMode:e})),d(this.t(`settings.autoScale`),t.autoScale,e=>this.patch({autoScale:e})),d(this.t(`settings.invertScale`),t.invertScale,e=>this.patch({invertScale:e})),d(this.t(`settings.leftScale`),t.leftPriceScale,e=>this.patch({leftPriceScale:e})),d(this.t(`settings.indicatorValues`),t.indicatorValueLabels,e=>this.patch({indicatorValueLabels:e})),d(this.t(`settings.alignAxisLabels`),t.alignAxisLabels,e=>this.patch({alignAxisLabels:e})),...this.available.barCountdown===!1?[]:[d(this.t(`settings.barCountdown`),t.barCountdown,e=>this.patch({barCountdown:e}))],f(this.t(`settings.timezone`),t.timezone,i,e=>this.patch({timezone:e})),f(this.t(`settings.numberLocale`),t.numberLocale,e.r(t.numberLocale),e=>this.patch({numberLocale:e}))]),this.addSection(this.t(`settings.section.axes`),e.c.map(e=>this.lookRow(e)))}renderAppearanceTab(t){let[n,r,i,...a]=e.i;this.renderLookSection(n),this.renderLookSection(r,[d(this.t(`common.show`),t.gridVisible,e=>this.patch({gridVisible:e}))]),this.renderLookSection(i,[f(this.t(`settings.crosshairMode`),t.crosshairMode,[{label:this.t(`settings.crosshair.magnet`),value:`magnet`},{label:this.t(`settings.crosshair.normal`),value:`normal`},{label:this.t(`settings.crosshair.hidden`),value:`hidden`}],e=>this.patch({crosshairMode:e})),f(this.t(`settings.crosshairCursor`),t.crosshairCursor,[{label:this.t(`drawing.cursorCross`),value:`cross`},{label:this.t(`drawing.cursorDot`),value:`dot`},{label:this.t(`drawing.cursorArrow`),value:`arrow`}],e=>this.patch({crosshairCursor:e}))]);for(let e of a)this.renderLookSection(e)}renderLayersTab(e){let t=e=>`${Math.round(e*100)}%`,n=e=>this.t(e);this.addSection(void 0,[d(n(`settings.volumeProfile`),e.volumeProfileVisible,e=>this.patch({volumeProfileVisible:e}))]),this.addSection(void 0,[d(n(`settings.marketProfile`),e.marketProfileVisible,e=>this.patch({marketProfileVisible:e})),d(n(`settings.marketProfileSplit`),e.marketProfileSplit,e=>this.patch({marketProfileSplit:e})),d(n(`settings.marketProfileLetters`),e.marketProfileLetters,e=>this.patch({marketProfileLetters:e})),p(n(`settings.marketProfileBuckets`),e.marketProfileBuckets,{min:8,max:200,step:1},e=>this.patch({marketProfileBuckets:e})),p(n(`settings.marketProfileOpacity`),e.marketProfileOpacity,{min:.05,max:1,step:.05},e=>this.patch({marketProfileOpacity:e}),t)]),this.addSection(void 0,[d(n(`settings.depthHeatmap`),e.depthHeatmapVisible,e=>this.patch({depthHeatmapVisible:e})),p(n(`settings.depthHeatmapOpacity`),e.depthHeatmapOpacity,{min:.1,max:1,step:.05},e=>this.patch({depthHeatmapOpacity:e}),t)]),this.addSection(void 0,[d(n(`settings.swingMarkers`),e.pivotMarkersVisible,e=>this.patch({pivotMarkersVisible:e})),p(n(`settings.swingStrength`),e.pivotStrength,{min:2,max:20,step:1},e=>this.patch({pivotStrength:e})),d(n(`settings.swingStructure`),e.pivotStructureLabels,e=>this.patch({pivotStructureLabels:e}))]),this.addSection(void 0,[d(n(`settings.sessionShading`),e.sessionShadingVisible,e=>this.patch({sessionShadingVisible:e})),d(n(`settings.periodLevels`),e.periodLevelsVisible,e=>this.patch({periodLevelsVisible:e})),f(n(`settings.periodLevelsBasis`),e.periodLevelsPeriod,[{value:`day`,label:n(`settings.priorDay`)},{value:`week`,label:n(`settings.priorWeek`)}],e=>this.patch({periodLevelsPeriod:e}))])}addSection(e,t){let n=c(e);return n.append(...t),this.bodyEl?.appendChild(n),n}renderLookSection(e,t=[]){this.addSection(this.t(e.title),[...t,...e.rows.map(e=>this.lookRow(e))])}lookRow(e){let t=this.t(e.label),n=()=>this.callbacks.styleValue(e.keys[0]),r=()=>{let t=e.keys.map(e=>this.callbacks.styleValue(e));return t.every(e=>e===t[0])&&t[0]!==null?String(t[0]):``},a,o=t=>{this.callbacks.onStyleChange(Object.fromEntries(e.keys.map(e=>[e,t])));for(let e of this.lookRows)e.el!==a&&e.sync()},s=e.auto?[{value:``,label:this.t(`settings.auto`)}]:[],c;switch(i.CHART_STYLE_KEYS[e.keys[0]]){case`boolean`:{a=d(t,n()===!0,o);let e=a.querySelector(`button`);c=()=>{let t=n()===!0;e.classList.toggle(`tcw-on`,t),e.setAttribute(`aria-checked`,String(t))};break}case`lineStyle`:a=f(t,r(),[...s,...this.lineStyles()],e=>o(e===``?null:T(e))),c=()=>{a.querySelector(`select`).value=r()};break;case`width`:{let e=n(),i=typeof e==`number`&&!_.includes(e)?[..._,e].sort((e,t)=>e-t):_;a=f(t,r(),[...s,...i.map(e=>({value:String(e),label:`${e}px`}))],e=>o(e===``?null:Number(e))),c=()=>{a.querySelector(`select`).value=r()};break}default:{let r=n(),i=u(t,typeof r==`string`?r:null,o,{read:()=>{let e=n();return typeof e==`string`?e:null},start:e.auto?()=>(e.auto?.from?this.callbacks.styleValue(e.auto.from):e.auto?.hint)??null:void 0},this.t);a=i.row,c=i.sync}}return this.lookRows.push({el:a,sync:c}),a}lineStyles(){return[{value:`solid`,label:this.t(`drawingSettings.lineStyle.solid`)},{value:`dashed`,label:this.t(`drawingSettings.lineStyle.dashed`)},{value:`dotted`,label:this.t(`drawingSettings.lineStyle.dotted`)}]}renderChartTypeSection(){if(!this.bodyEl||!this.currentSettings||!this.chartType)return;let t=this.chartType,n=this.currentSettings.chartTypeOptions??{},r=e.m.find(e=>e.value===t),i=c(r?e.t(r,this.t):t),a=()=>this.currentSettings?.chartTypeOptions??{},o=(e,t)=>this.patch({chartTypeOptions:{...a(),[e]:t}}),s=(e,t,n,r)=>i.appendChild(h(this.t(e),t,n,r,this.t,this.currentSettings?.numberLocale||void 0));switch(t){case`renko`:{let e=n.renko??{};s(`settings.boxSize`,typeof e.boxSize==`number`?e.boxSize:null,y,e=>o(`renko`,{...a().renko??{},boxSize:e??`atr`})),s(`settings.atrPeriod`,e.atrPeriod??null,{step:`1`,max:500},e=>o(`renko`,w(a().renko,`atrPeriod`,e)));break}case`lineBreak`:s(`settings.lineBreakLines`,n.lineBreak?.lines??null,{step:`1`,max:10},e=>o(`lineBreak`,w(a().lineBreak,`lines`,e)));break;case`kagi`:s(`settings.reversal`,n.kagi?.reversal??null,y,e=>o(`kagi`,w(a().kagi,`reversal`,e))),i.appendChild(f(this.t(`settings.reversalType`),n.kagi?.reversalType??`percent`,[{value:`percent`,label:this.t(`settings.reversalType.percent`)},{value:`price`,label:this.t(`settings.reversalType.price`)}],e=>o(`kagi`,{...a().kagi??{},reversalType:e===`price`?`price`:`percent`})));break;case`pointAndFigure`:s(`settings.boxSize`,typeof n.pointAndFigure?.boxSize==`number`?n.pointAndFigure.boxSize:null,y,e=>o(`pointAndFigure`,{...a().pointAndFigure??{},boxSize:e??`auto`})),s(`settings.reversalBoxes`,n.pointAndFigure?.reversal??null,{step:`1`,max:10},e=>o(`pointAndFigure`,w(a().pointAndFigure,`reversal`,e)));break;case`rangeBars`:s(`settings.barRange`,typeof n.rangeBars?.range==`number`?n.rangeBars.range:null,y,e=>o(`rangeBars`,{range:e??`auto`}));break;default:break}for(let n of e.p(t))i.appendChild(this.lookRow(n));this.bodyEl.appendChild(i)}patch(e){this.currentSettings&&Object.assign(this.currentSettings,e),this.callbacks.onChange(e)}};function S(e,t){return C(e,t)}function C(e,t){if(e===t)return!0;if(typeof e!=`object`||typeof t!=`object`||e===null||t===null||Array.isArray(e)!==Array.isArray(t))return!1;let n=e,r=t,i=new Set([...Object.keys(n),...Object.keys(r)].filter(e=>n[e]!==void 0||r[e]!==void 0));for(let e of i)if(!C(n[e],r[e]))return!1;return!0}function w(e,t,n){let r={...e??{}};return n===null?delete r[t]:r[t]=n,r}function T(e){return e===`dashed`||e===`dotted`?e:`solid`}exports.WidgetSettings=x;
2
- //# sourceMappingURL=WidgetSettings-COljE3G_.cjs.map
1
+ const e=require(`./widgetLocales-BdRQu8wS.cjs`),t=require(`./focusTrap-DrhhmG0V.cjs`),n=require(`./settingsControls-Tn8_vJJv.cjs`),r=require(`./i18n-BFGknfTa.cjs`);let i=require(`@tradecanvas/commons`);var a=0,o=0,s=20;function c(e){let t=document.createElement(`div`);if(t.className=`tcw-settings-section`,e){let n=document.createElement(`div`);n.className=`tcw-settings-section-title`,n.textContent=e,t.appendChild(n),t.setAttribute(`role`,`group`),t.setAttribute(`aria-label`,e)}return t}function l(e){let t=document.createElement(`div`);t.className=`tcw-settings-row`;let n=document.createElement(`span`);return n.className=`tcw-settings-label`,n.textContent=e,t.appendChild(n),t}function u(e,t,r,i,o){let s=l(e),c=document.createElement(`div`);c.className=`tcw-color-picker-wrap`;let u=document.createElement(`input`);u.type=`color`,u.setAttribute(`aria-label`,e);let d=document.createElement(`span`);d.className=`tcw-color-hex`,d.id=`tcw-color-${++a}`,u.setAttribute(`aria-describedby`,d.id);let f=null,p=t=>{u.value=n.l(t??i.start?.()),d.textContent=t??o(`settings.auto`),s.classList.toggle(`tcw-color-auto`,t===null),t!==null&&i.start&&!f?(f=document.createElement(`button`),f.type=`button`,f.className=`tcw-color-auto-btn`,f.textContent=o(`settings.auto`),f.setAttribute(`aria-label`,`${e}: ${o(`settings.auto`)}`),f.addEventListener(`click`,()=>{r(null),u.focus(),p(i.read())}),c.appendChild(f)):t===null&&f&&(f.remove(),f=null)};return u.addEventListener(`input`,()=>{r(u.value),p(u.value)}),c.append(u,d),s.appendChild(c),p(t),{row:s,sync:()=>p(i.read())}}function d(e,t,n){let r=l(e),i=document.createElement(`button`);return i.type=`button`,i.className=`tcw-toggle${t?` tcw-on`:``}`,i.setAttribute(`role`,`switch`),i.setAttribute(`aria-checked`,String(t)),i.setAttribute(`aria-label`,e),i.addEventListener(`click`,()=>{let e=!i.classList.contains(`tcw-on`);i.classList.toggle(`tcw-on`,e),i.setAttribute(`aria-checked`,String(e)),n(e)}),r.appendChild(i),r}function f(e,t,n,r){let i=l(e),a=document.createElement(`select`);a.className=`tcw-settings-select`,a.setAttribute(`aria-label`,e);for(let e of n){let n=document.createElement(`option`);n.value=e.value,n.textContent=e.label,e.value===t&&(n.selected=!0),a.appendChild(n)}return n.some(e=>e.value===t)||(a.selectedIndex=-1),a.addEventListener(`change`,()=>r(a.value)),i.appendChild(a),i}function p(e,t,n,r,i=e=>String(e)){let a=l(e),o=document.createElement(`div`);o.className=`tcw-settings-range`;let s=document.createElement(`input`);s.type=`range`,s.min=String(n.min),s.max=String(n.max),s.step=String(n.step),s.value=String(t),s.setAttribute(`aria-label`,e);let c=document.createElement(`span`);return c.className=`tcw-settings-range-val`,c.textContent=i(t),s.addEventListener(`input`,()=>{let e=Number(s.value);c.textContent=i(e),r(e)}),o.append(s,c),a.appendChild(o),a}function m(e,t,n){let i=new Intl.NumberFormat(n,{maximumFractionDigits:s}).format;return e.step===`1`&&Number.isFinite(e.max)?r.r(t(`settings.numberWhole`),{min:i(Math.max(1,e.min??1)),max:i(e.max)}):r.r(t(`settings.numberAtLeast`),{min:i(e.min??0)})}function h(e,t,n,r,i,a=`en-US`){let s=document.createElement(`div`);s.className=`tcw-settings-row tcw-settings-row--number`;let c=document.createElement(`label`);c.className=`tcw-settings-label`,c.textContent=e,s.appendChild(c);let l=document.createElement(`input`);l.type=`number`,l.className=`tcw-settings-number`,l.min=`0`,l.step=n.step,Number.isFinite(n.max)&&(l.max=String(n.max)),l.placeholder=i(`settings.auto`),l.value=t===null?``:String(t),l.setAttribute(`aria-label`,e);let u=document.createElement(`div`);u.className=`tcw-settings-hint`,u.id=`tcw-number-hint-${++o}`,u.setAttribute(`role`,`status`),l.setAttribute(`aria-describedby`,u.id);let d=e=>{e?l.removeAttribute(`aria-invalid`):l.setAttribute(`aria-invalid`,`true`),u.textContent=e?``:m(n,i,a)};return l.addEventListener(`change`,()=>{if(l.value.trim()===``){d(!0),r(null);return}let e=Number(l.value),t=Number.isFinite(e)&&e>0&&e>=(n.min??0)&&e<=n.max&&(n.step!==`1`||Number.isInteger(e));d(t),t&&r(e)}),s.append(l,u),s}var g=[{id:`symbol`,icon:`chartType:candlestick`},{id:`statusLine`,icon:`type`},{id:`scales`,icon:`ruler`},{id:`appearance`,icon:`palette`},{id:`layers`,icon:`layers`},{id:`trading`,icon:`trendingUp`}],_=[1,2,3,4],v=`t:`,y={step:`any`,max:1/0,min:1e-8},b=1,x=class{callbacks;t;backdrop=null;modal=null;bodyEl=null;tabButtons=[];templateBtn=null;menu=null;currentTab=`symbol`;currentSettings=null;chartType=null;lookRows=[];returnFocus=null;uid=b++;constructor(e,t,n={},r=()=>document.body){this.available=n,this.host=r,this.callbacks=e,this.t=t}open(e,t=null,n=`symbol`){this.modal&&this.remove(),this.returnFocus=document.activeElement instanceof HTMLElement?document.activeElement:null,this.currentSettings={...e},this.chartType=t,this.currentTab=n,this.buildModal(),this.tabButtons.find(e=>e.dataset.tab===n)?.focus()}isOpen(){return this.modal!==null}follow(e){!this.modal||this.currentSettings&&S(this.currentSettings,e)||this.refresh(e)}refresh(e,t){if(!this.modal)return;this.currentSettings={...e},t!==void 0&&(this.chartType=t);let n=this.focusedControl();this.renderTabContent(),n!==null&&this.focusControl(n)}focusedControl(){let e=document.activeElement;if(!this.bodyEl||!(e instanceof HTMLElement)||!this.bodyEl.contains(e))return null;let t=this.panelControls().indexOf(e);return t<0?null:t}focusControl(e){let t=this.panelControls();(t[Math.min(e,t.length-1)]??this.tabButtons.find(e=>e.dataset.tab===this.currentTab))?.focus()}panelControls(){return this.bodyEl?[...this.bodyEl.querySelectorAll(t.t)]:[]}close(){this.finish(!0)}destroy(){this.remove()}finish(e){this.modal&&(e?this.callbacks.onClose():this.callbacks.onCancel?.(),this.remove(),this.returnFocus?.isConnected&&this.returnFocus.focus(),this.returnFocus=null)}remove(){this.menu?.destroy(),this.menu=null,this.backdrop?.remove(),this.backdrop=this.modal=this.bodyEl=this.templateBtn=null,this.tabButtons=[]}buildModal(){let e=document.createElement(`div`);e.className=`tcw-modal-backdrop`;let n=!1;e.addEventListener(`pointerdown`,t=>{n=t.target===e}),e.addEventListener(`click`,t=>{t.target===e&&n&&this.finish(!1),n=!1});let r=document.createElement(`div`);r.className=`tcw-modal tcw-set`,r.setAttribute(`role`,`dialog`),r.setAttribute(`aria-modal`,`true`),r.setAttribute(`aria-labelledby`,`tcw-set-title-${this.uid}`),r.tabIndex=-1,r.addEventListener(`keydown`,e=>{if(e.key===`Escape`){e.preventDefault(),e.stopPropagation(),this.finish(!1);return}t.n(e,r)}),this.backdrop=e,this.modal=r,r.append(this.buildHeader(),this.buildBody(),this.buildFooter()),e.appendChild(r),this.host().appendChild(e),this.markTabs(),this.renderTabContent()}buildHeader(){let e=document.createElement(`div`);e.className=`tcw-modal-header`;let n=document.createElement(`h3`);n.id=`tcw-set-title-${this.uid}`,n.textContent=this.t(`settings.title`);let r=document.createElement(`button`);return r.type=`button`,r.className=`tcw-modal-close`,r.setAttribute(`aria-label`,this.t(`common.close`)),r.innerHTML=t.i(`x`,16),r.addEventListener(`click`,()=>this.finish(!1)),e.append(n,r),e}buildBody(){let e=document.createElement(`div`);e.className=`tcw-set-body`;let n=document.createElement(`div`);n.className=`tcw-set-nav`,n.setAttribute(`role`,`tablist`),n.setAttribute(`aria-orientation`,`vertical`),n.setAttribute(`aria-label`,this.t(`settings.title`)),n.addEventListener(`keydown`,e=>this.onTabKey(e)),this.tabButtons=g.map(({id:e,icon:n})=>{let r=document.createElement(`button`);return r.type=`button`,r.className=`tcw-set-tab`,r.id=`tcw-set-tab-${this.uid}-${e}`,r.dataset.tab=e,r.setAttribute(`role`,`tab`),r.setAttribute(`aria-controls`,`tcw-set-panel-${this.uid}`),r.innerHTML=`${n.startsWith(`chartType:`)?t.r(n.slice(10),16):t.i(n,16)}<span></span>`,r.querySelector(`span`).textContent=this.t(`settings.tab.${e}`),r.addEventListener(`click`,()=>this.selectTab(e)),r}),n.append(...this.tabButtons);let r=document.createElement(`div`);return r.className=`tcw-modal-body tcw-set-panel`,r.id=`tcw-set-panel-${this.uid}`,r.setAttribute(`role`,`tabpanel`),this.bodyEl=r,e.append(n,r),e}buildFooter(){let e=document.createElement(`div`);e.className=`tcw-modal-footer`;let n=this.footerButton(`template`,`tcw-footer-menu`,()=>this.openTemplates());n.setAttribute(`aria-haspopup`,`menu`),n.setAttribute(`aria-expanded`,`false`),n.innerHTML=`<span></span>${t.i(`chevronDown`,12)}`,n.querySelector(`span`).textContent=this.t(`settings.template`),this.templateBtn=n;let r=document.createElement(`div`);return r.className=`tcw-footer-end`,r.append(this.footerButton(`cancel`,`tcw-footer-cancel`,()=>this.finish(!1),this.t(`common.cancel`)),this.footerButton(`ok`,`tcw-done-btn`,()=>this.finish(!0),this.t(`drawingSettings.ok`))),e.append(n,r),e}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}markTabs(){for(let e of this.tabButtons){let t=e.dataset.tab===this.currentTab;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.currentTab=e,this.markTabs(),this.renderTabContent(),t&&this.tabButtons.find(t=>t.dataset.tab===e)?.focus()}onTabKey(e){let t=g.findIndex(e=>e.id===this.currentTab),n=e.key===`ArrowDown`||e.key===`ArrowRight`?(t+1)%g.length:e.key===`ArrowUp`||e.key===`ArrowLeft`?(t-1+g.length)%g.length:e.key===`Home`?0:e.key===`End`?g.length-1:-1;n<0||(e.preventDefault(),this.selectTab(g[n].id,!0))}openTemplates(){let e=this.templateBtn;if(!this.modal||!e)return;if(this.menu?.isOpen()){this.menu.close();return}let t=this.callbacks.templates,i=(t?.list()??[]).map(e=>({id:`${v}${e}`,label:e,icon:`layers`,remove:r.r(this.t(`templates.delete`),{name:e})})),a=[...i,...i.length>0?[`separator`]:[],...t?[{id:`save`,label:this.t(`settings.saveTemplate`),icon:`save`}]:[],{id:`reset`,label:this.t(`settings.resetToDefaults`),icon:`reset`}];this.menu??=new n.f(this.modal,this.t(`settings.template`));let o=e.getBoundingClientRect(),s=this.modal.getBoundingClientRect();this.menu.open(a,o.left-s.left,o.top-s.top,e=>{e===`reset`?this.callbacks.onReset():e===`save`?t?.save():e.startsWith(v)&&t?.apply(e.slice(2))},e,e=>t?.remove(e.slice(2)))}renderTabContent(){if(!(!this.bodyEl||!this.currentSettings))switch(this.bodyEl.replaceChildren(),this.lookRows=[],this.currentTab){case`symbol`:this.renderSymbolTab(this.currentSettings);break;case`statusLine`:this.renderStatusLineTab(this.currentSettings);break;case`scales`:this.renderScalesTab(this.currentSettings);break;case`appearance`:this.renderAppearanceTab(this.currentSettings);break;case`layers`:this.renderLayersTab(this.currentSettings);break;case`trading`:for(let t of e.d)(!t.trading||this.available.trading!==!1)&&this.renderLookSection(t);break}}renderSymbolTab(t){this.renderChartTypeSection(),this.addSection(void 0,[d(this.t(`settings.mainSeries`),t.mainSeriesVisible,e=>this.patch({mainSeriesVisible:e})),d(this.t(`settings.extendedHours`),t.extendedHours,e=>this.patch({extendedHours:e}))]);let n=this.t(`common.show`);this.renderLookSection(e.o),this.available.volume!==!1&&this.renderLookSection(e.f,[d(n,t.volumeVisible,e=>this.patch({volumeVisible:e}))]),this.renderLookSection(e.a,[d(n,t.highLowLines,e=>this.patch({highLowLines:e}))])}renderStatusLineTab(t){let n=this.available.legend!==!1,r=n?e.u:e.u.filter(t=>!e.s.includes(t));this.addSection(void 0,[...n?[d(this.t(`settings.ohlcLegend`),t.legendVisible,e=>this.patch({legendVisible:e}))]:[],...r.map(e=>this.lookRow(e))])}renderScalesTab(t){let n=[{value:`regular`,label:this.t(`settings.scale.regular`)},{value:`logarithmic`,label:this.t(`settings.scale.logarithmic`)},{value:`percentage`,label:this.t(`settings.scale.percentage`)},{value:`indexedTo100`,label:this.t(`settings.scale.indexedTo100`)}].filter(e=>e.value!==`logarithmic`||this.available.logScale!==!1),r=this.available.exchangeZone?.(),i=e.y(t.timezone,Date.now(),this.t(`settings.timezone.local`),r===void 0?void 0:{label:this.t(`settings.timezone.exchange`),zone:r});this.addSection(void 0,[f(this.t(`settings.priceScale`),t.scaleMode,n,e=>this.patch({scaleMode:e})),d(this.t(`settings.autoScale`),t.autoScale,e=>this.patch({autoScale:e})),d(this.t(`settings.invertScale`),t.invertScale,e=>this.patch({invertScale:e})),d(this.t(`settings.leftScale`),t.leftPriceScale,e=>this.patch({leftPriceScale:e})),d(this.t(`settings.indicatorValues`),t.indicatorValueLabels,e=>this.patch({indicatorValueLabels:e})),d(this.t(`settings.alignAxisLabels`),t.alignAxisLabels,e=>this.patch({alignAxisLabels:e})),...this.available.barCountdown===!1?[]:[d(this.t(`settings.barCountdown`),t.barCountdown,e=>this.patch({barCountdown:e}))],f(this.t(`settings.timezone`),t.timezone,i,e=>this.patch({timezone:e})),f(this.t(`settings.numberLocale`),t.numberLocale,e.r(t.numberLocale),e=>this.patch({numberLocale:e}))]),this.addSection(this.t(`settings.section.axes`),e.c.map(e=>this.lookRow(e)))}renderAppearanceTab(t){let[n,r,i,...a]=e.i;this.renderLookSection(n),this.renderLookSection(r,[d(this.t(`common.show`),t.gridVisible,e=>this.patch({gridVisible:e}))]),this.renderLookSection(i,[f(this.t(`settings.crosshairMode`),t.crosshairMode,[{label:this.t(`settings.crosshair.magnet`),value:`magnet`},{label:this.t(`settings.crosshair.normal`),value:`normal`},{label:this.t(`settings.crosshair.hidden`),value:`hidden`}],e=>this.patch({crosshairMode:e})),f(this.t(`settings.crosshairCursor`),t.crosshairCursor,[{label:this.t(`drawing.cursorCross`),value:`cross`},{label:this.t(`drawing.cursorDot`),value:`dot`},{label:this.t(`drawing.cursorArrow`),value:`arrow`}],e=>this.patch({crosshairCursor:e}))]);for(let e of a)this.renderLookSection(e)}renderLayersTab(e){let t=e=>`${Math.round(e*100)}%`,n=e=>this.t(e);this.addSection(void 0,[d(n(`settings.volumeProfile`),e.volumeProfileVisible,e=>this.patch({volumeProfileVisible:e}))]),this.addSection(void 0,[d(n(`settings.marketProfile`),e.marketProfileVisible,e=>this.patch({marketProfileVisible:e})),d(n(`settings.marketProfileSplit`),e.marketProfileSplit,e=>this.patch({marketProfileSplit:e})),d(n(`settings.marketProfileLetters`),e.marketProfileLetters,e=>this.patch({marketProfileLetters:e})),p(n(`settings.marketProfileBuckets`),e.marketProfileBuckets,{min:8,max:200,step:1},e=>this.patch({marketProfileBuckets:e})),p(n(`settings.marketProfileOpacity`),e.marketProfileOpacity,{min:.05,max:1,step:.05},e=>this.patch({marketProfileOpacity:e}),t)]),this.addSection(void 0,[d(n(`settings.depthHeatmap`),e.depthHeatmapVisible,e=>this.patch({depthHeatmapVisible:e})),p(n(`settings.depthHeatmapOpacity`),e.depthHeatmapOpacity,{min:.1,max:1,step:.05},e=>this.patch({depthHeatmapOpacity:e}),t)]),this.addSection(void 0,[d(n(`settings.swingMarkers`),e.pivotMarkersVisible,e=>this.patch({pivotMarkersVisible:e})),p(n(`settings.swingStrength`),e.pivotStrength,{min:2,max:20,step:1},e=>this.patch({pivotStrength:e})),d(n(`settings.swingStructure`),e.pivotStructureLabels,e=>this.patch({pivotStructureLabels:e}))]),this.addSection(void 0,[d(n(`settings.sessionShading`),e.sessionShadingVisible,e=>this.patch({sessionShadingVisible:e})),d(n(`settings.periodLevels`),e.periodLevelsVisible,e=>this.patch({periodLevelsVisible:e})),f(n(`settings.periodLevelsBasis`),e.periodLevelsPeriod,[{value:`day`,label:n(`settings.priorDay`)},{value:`week`,label:n(`settings.priorWeek`)}],e=>this.patch({periodLevelsPeriod:e}))])}addSection(e,t){let n=c(e);return n.append(...t),this.bodyEl?.appendChild(n),n}renderLookSection(e,t=[]){this.addSection(this.t(e.title),[...t,...e.rows.map(e=>this.lookRow(e))])}lookRow(e){let t=this.t(e.label),n=()=>this.callbacks.styleValue(e.keys[0]),r=()=>{let t=e.keys.map(e=>this.callbacks.styleValue(e));return t.every(e=>e===t[0])&&t[0]!==null?String(t[0]):``},a,o=t=>{this.callbacks.onStyleChange(Object.fromEntries(e.keys.map(e=>[e,t])));for(let e of this.lookRows)e.el!==a&&e.sync()},s=e.auto?[{value:``,label:this.t(`settings.auto`)}]:[],c;switch(i.CHART_STYLE_KEYS[e.keys[0]]){case`boolean`:{a=d(t,n()===!0,o);let e=a.querySelector(`button`);c=()=>{let t=n()===!0;e.classList.toggle(`tcw-on`,t),e.setAttribute(`aria-checked`,String(t))};break}case`lineStyle`:a=f(t,r(),[...s,...this.lineStyles()],e=>o(e===``?null:T(e))),c=()=>{a.querySelector(`select`).value=r()};break;case`width`:{let e=n(),i=typeof e==`number`&&!_.includes(e)?[..._,e].sort((e,t)=>e-t):_;a=f(t,r(),[...s,...i.map(e=>({value:String(e),label:`${e}px`}))],e=>o(e===``?null:Number(e))),c=()=>{a.querySelector(`select`).value=r()};break}default:{let r=n(),i=u(t,typeof r==`string`?r:null,o,{read:()=>{let e=n();return typeof e==`string`?e:null},start:e.auto?()=>(e.auto?.from?this.callbacks.styleValue(e.auto.from):e.auto?.hint)??null:void 0},this.t);a=i.row,c=i.sync}}return this.lookRows.push({el:a,sync:c}),a}lineStyles(){return[{value:`solid`,label:this.t(`drawingSettings.lineStyle.solid`)},{value:`dashed`,label:this.t(`drawingSettings.lineStyle.dashed`)},{value:`dotted`,label:this.t(`drawingSettings.lineStyle.dotted`)}]}renderChartTypeSection(){if(!this.bodyEl||!this.currentSettings||!this.chartType)return;let t=this.chartType,n=this.currentSettings.chartTypeOptions??{},r=e.m.find(e=>e.value===t),i=c(r?e.t(r,this.t):t),a=()=>this.currentSettings?.chartTypeOptions??{},o=(e,t)=>this.patch({chartTypeOptions:{...a(),[e]:t}}),s=(e,t,n,r)=>i.appendChild(h(this.t(e),t,n,r,this.t,this.currentSettings?.numberLocale||void 0));switch(t){case`renko`:{let e=n.renko??{};s(`settings.boxSize`,typeof e.boxSize==`number`?e.boxSize:null,y,e=>o(`renko`,{...a().renko??{},boxSize:e??`atr`})),s(`settings.atrPeriod`,e.atrPeriod??null,{step:`1`,max:500},e=>o(`renko`,w(a().renko,`atrPeriod`,e)));break}case`lineBreak`:s(`settings.lineBreakLines`,n.lineBreak?.lines??null,{step:`1`,max:10},e=>o(`lineBreak`,w(a().lineBreak,`lines`,e)));break;case`kagi`:s(`settings.reversal`,n.kagi?.reversal??null,y,e=>o(`kagi`,w(a().kagi,`reversal`,e))),i.appendChild(f(this.t(`settings.reversalType`),n.kagi?.reversalType??`percent`,[{value:`percent`,label:this.t(`settings.reversalType.percent`)},{value:`price`,label:this.t(`settings.reversalType.price`)}],e=>o(`kagi`,{...a().kagi??{},reversalType:e===`price`?`price`:`percent`})));break;case`pointAndFigure`:s(`settings.boxSize`,typeof n.pointAndFigure?.boxSize==`number`?n.pointAndFigure.boxSize:null,y,e=>o(`pointAndFigure`,{...a().pointAndFigure??{},boxSize:e??`auto`})),s(`settings.reversalBoxes`,n.pointAndFigure?.reversal??null,{step:`1`,max:10},e=>o(`pointAndFigure`,w(a().pointAndFigure,`reversal`,e)));break;case`rangeBars`:s(`settings.barRange`,typeof n.rangeBars?.range==`number`?n.rangeBars.range:null,y,e=>o(`rangeBars`,{range:e??`auto`}));break;default:break}for(let n of e.p(t))i.appendChild(this.lookRow(n));this.bodyEl.appendChild(i)}patch(e){this.currentSettings&&Object.assign(this.currentSettings,e),this.callbacks.onChange(e)}};function S(e,t){return C(e,t)}function C(e,t){if(e===t)return!0;if(typeof e!=`object`||typeof t!=`object`||e===null||t===null||Array.isArray(e)!==Array.isArray(t))return!1;let n=e,r=t,i=new Set([...Object.keys(n),...Object.keys(r)].filter(e=>n[e]!==void 0||r[e]!==void 0));for(let e of i)if(!C(n[e],r[e]))return!1;return!0}function w(e,t,n){let r={...e??{}};return n===null?delete r[t]:r[t]=n,r}function T(e){return e===`dashed`||e===`dotted`?e:`solid`}exports.WidgetSettings=x;
2
+ //# sourceMappingURL=WidgetSettings-CBf6hUSV.cjs.map