@tradecanvas/chart 2.4.0 → 2.6.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 (57) hide show
  1. package/dist/Chart.d.ts +41 -0
  2. package/dist/Chart.d.ts.map +1 -1
  3. package/dist/{LayoutSession-D7ztdedn.js → LayoutSession-D8TcwPy1.js} +510 -436
  4. package/dist/LayoutSession-D8TcwPy1.js.map +1 -0
  5. package/dist/LayoutSession-DDs1N5h2.cjs +2 -0
  6. package/dist/LayoutSession-DDs1N5h2.cjs.map +1 -0
  7. package/dist/{WidgetGoToDate-hcDtezRm.js → WidgetGoToDate-DnQxxvf1.js} +2 -2
  8. package/dist/{WidgetGoToDate-hcDtezRm.js.map → WidgetGoToDate-DnQxxvf1.js.map} +1 -1
  9. package/dist/{WidgetGoToDate-BNdngHlg.cjs → WidgetGoToDate-hNVxz-Zb.cjs} +2 -2
  10. package/dist/{WidgetGoToDate-BNdngHlg.cjs.map → WidgetGoToDate-hNVxz-Zb.cjs.map} +1 -1
  11. package/dist/{WidgetIndicatorPicker-DJQ5taqX.cjs → WidgetIndicatorPicker-DKxoB4Un.cjs} +2 -2
  12. package/dist/{WidgetIndicatorPicker-DJQ5taqX.cjs.map → WidgetIndicatorPicker-DKxoB4Un.cjs.map} +1 -1
  13. package/dist/{WidgetIndicatorPicker-BzV4Mm_W.js → WidgetIndicatorPicker-eK03W3LR.js} +2 -2
  14. package/dist/{WidgetIndicatorPicker-BzV4Mm_W.js.map → WidgetIndicatorPicker-eK03W3LR.js.map} +1 -1
  15. package/dist/{WidgetSymbolSearch-BOgfBOV6.cjs → WidgetSymbolSearch-C_yw9mLo.cjs} +2 -2
  16. package/dist/{WidgetSymbolSearch-BOgfBOV6.cjs.map → WidgetSymbolSearch-C_yw9mLo.cjs.map} +1 -1
  17. package/dist/{WidgetSymbolSearch-BgFNnrV3.js → WidgetSymbolSearch-Dnkh_y4h.js} +2 -2
  18. package/dist/{WidgetSymbolSearch-BgFNnrV3.js.map → WidgetSymbolSearch-Dnkh_y4h.js.map} +1 -1
  19. package/dist/index.cjs +1 -1
  20. package/dist/index.d.ts +2 -0
  21. package/dist/index.d.ts.map +1 -1
  22. package/dist/index.js +80 -80
  23. package/dist/widget/ChartWidget.d.ts +5 -0
  24. package/dist/widget/ChartWidget.d.ts.map +1 -1
  25. package/dist/widget/WidgetChartNav.d.ts +8 -0
  26. package/dist/widget/WidgetChartNav.d.ts.map +1 -1
  27. package/dist/widget/WidgetDrawingEdit.d.ts +13 -0
  28. package/dist/widget/WidgetDrawingEdit.d.ts.map +1 -1
  29. package/dist/widget/WidgetMarks.d.ts +60 -0
  30. package/dist/widget/WidgetMarks.d.ts.map +1 -0
  31. package/dist/widget/WidgetMenus.d.ts +2 -0
  32. package/dist/widget/WidgetMenus.d.ts.map +1 -1
  33. package/dist/widget/WidgetSelectionToolbar.d.ts +4 -0
  34. package/dist/widget/WidgetSelectionToolbar.d.ts.map +1 -1
  35. package/dist/widget/drawingMenu.d.ts +3 -1
  36. package/dist/widget/drawingMenu.d.ts.map +1 -1
  37. package/dist/widget/index.cjs +4 -3
  38. package/dist/widget/index.cjs.map +1 -1
  39. package/dist/widget/index.js +1245 -1059
  40. package/dist/widget/index.js.map +1 -1
  41. package/dist/widget/symbolInfoView.d.ts +9 -1
  42. package/dist/widget/symbolInfoView.d.ts.map +1 -1
  43. package/dist/widget/types.d.ts +8 -0
  44. package/dist/widget/types.d.ts.map +1 -1
  45. package/dist/widget/widgetFeatures.d.ts +1 -1
  46. package/dist/widget/widgetFeatures.d.ts.map +1 -1
  47. package/dist/widgetFeatures-DpBWfQ8D.cjs +3 -0
  48. package/dist/widgetFeatures-DpBWfQ8D.cjs.map +1 -0
  49. package/dist/{widgetFeatures-BM6u0u74.js → widgetFeatures-sU-9JOSB.js} +3 -2
  50. package/dist/widgetFeatures-sU-9JOSB.js.map +1 -0
  51. package/package.json +3 -3
  52. package/dist/LayoutSession-D7ztdedn.js.map +0 -1
  53. package/dist/LayoutSession-ScBZ-Eci.cjs +0 -2
  54. package/dist/LayoutSession-ScBZ-Eci.cjs.map +0 -1
  55. package/dist/widgetFeatures-BM6u0u74.js.map +0 -1
  56. package/dist/widgetFeatures-BZ8OVPN2.cjs +0 -3
  57. package/dist/widgetFeatures-BZ8OVPN2.cjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"WidgetIndicatorPicker-BzV4Mm_W.js","names":[],"sources":["../src/widget/indicatorSearch.ts","../src/widget/WidgetIndicatorPicker.ts"],"sourcesContent":["/** What a search reads of an indicator. */\nexport interface SearchableIndicator {\n id: string;\n name: string;\n shortName: string;\n}\n\n/** Lower case without accents, so \"mômentum\" finds Momentum. */\nfunction fold(text: string): string {\n return text.normalize('NFD').replace(/[̀-ͯ]/g, '').toLowerCase();\n}\n\nconst WORD_BREAK = /[\\s/()%-]+/;\n\n/** How well an indicator matches `q` (folded): 0 best, null not at all. */\nfunction score(item: SearchableIndicator, q: string): number | null {\n const short = fold(item.shortName);\n const name = fold(item.name);\n if (short === q || fold(item.id) === q) return 0;\n if (short.startsWith(q) || name.startsWith(q)) return 1;\n if ([...name.split(WORD_BREAK), ...short.split(WORD_BREAK)].some((word) => word.startsWith(q))) return 2;\n if (name.includes(q) || short.includes(q)) return 3;\n return null;\n}\n\n/**\n * The indicators matching `query`, best first: the short name typed in full\n * (\"rsi\"), then names starting with it, then a word starting with it, then\n * any containing it. Ties go by name. Nothing typed finds nothing.\n */\nexport function searchIndicators<T extends SearchableIndicator>(items: readonly T[], query: string): T[] {\n const q = fold(query.trim());\n if (!q) return [];\n return items\n .map((item) => ({ item, rank: score(item, q) }))\n .filter((hit): hit is { item: T; rank: number } => hit.rank !== null)\n .sort((a, b) => a.rank - b.rank || a.item.name.localeCompare(b.item.name))\n .map((hit) => hit.item);\n}\n","import type { IndicatorCategory } from '@tradecanvas/commons';\nimport { INDICATOR_CATEGORIES } from '@tradecanvas/core';\nimport { createIcon } from './icons.js';\nimport { fill, type MessageKey, type Translator } from './i18n.js';\nimport { keepTabInside } from './focusTrap.js';\nimport { searchIndicators } from './indicatorSearch.js';\nimport { markPart } from './widgetFeatures.js';\n\n/** An indicator as the dialog lists it. */\nexport interface IndicatorPickerItem {\n id: string;\n name: string;\n shortName: string;\n placement: 'overlay' | 'panel';\n category: IndicatorCategory;\n}\n\nexport interface IndicatorPickerCallbacks {\n /** Add one; false when it wasn't added (nothing is announced then). */\n onAdd: (id: string) => boolean | void;\n onFavorite: (id: string, on: boolean) => void;\n /** The indicator templates; without them there is no Templates tab. */\n templates?: {\n onApply: (name: string) => void;\n onDelete: (name: string) => void;\n onSave: () => void;\n };\n onClose?: () => void;\n}\n\nexport interface IndicatorPickerContent {\n items: readonly IndicatorPickerItem[];\n favorites: readonly string[];\n /** The templates' names; null where they are switched off. */\n templates: readonly string[] | null;\n /** How many of each indicator are on the chart. */\n counts?: ReadonlyMap<string, number>;\n}\n\ntype View = 'favorites' | 'templates' | 'all' | IndicatorCategory;\n\nlet nextPickerId = 1;\n\nconst byName = (a: IndicatorPickerItem, b: IndicatorPickerItem) => a.name.localeCompare(b.name);\n\n/**\n * The indicators dialog: a search, the groups down the side (favourites,\n * templates, all, then each kind) and the list. A row adds its indicator and\n * the dialog stays open for the next; the star beside it keeps it in the\n * favourites. Mounts in the widget's overlay layer.\n */\nexport class WidgetIndicatorPicker {\n private backdrop: HTMLDivElement | null = null;\n private listEl: HTMLDivElement | null = null;\n private navEl: HTMLDivElement | null = null;\n private searchEl: HTMLInputElement | null = null;\n private liveEl: HTMLDivElement | null = null;\n private content: IndicatorPickerContent = { items: [], favorites: [], templates: [] };\n private favorites = new Set<string>();\n private counts: ReadonlyMap<string, number> = new Map();\n private view: View = 'all';\n /** The tab picked last, for the next opening. */\n private lastView: View | null = null;\n private query = '';\n private returnFocus: HTMLElement | null = null;\n private readonly uid = nextPickerId++;\n\n constructor(\n private readonly layer: () => HTMLElement,\n private readonly callbacks: IndicatorPickerCallbacks,\n private readonly t: Translator,\n ) {}\n\n open(content: IndicatorPickerContent): void {\n if (this.backdrop) this.close(false);\n this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n this.content = content;\n this.favorites = new Set(content.favorites);\n this.counts = content.counts ?? new Map();\n this.query = '';\n this.view = this.startView();\n this.build();\n this.searchEl?.focus();\n }\n\n close(giveFocusBack = true): void {\n if (!this.backdrop) return;\n this.backdrop.remove();\n this.backdrop = this.listEl = this.navEl = this.searchEl = this.liveEl = null;\n this.callbacks.onClose?.();\n if (giveFocusBack && this.returnFocus?.isConnected) this.returnFocus.focus();\n this.returnFocus = null;\n }\n\n isOpen(): boolean {\n return this.backdrop !== null;\n }\n\n /** The templates after one is saved or deleted; focus left on a deleted one goes to \"Save…\". */\n setTemplates(names: readonly string[]): void {\n this.content = { ...this.content, templates: [...names] };\n if (!this.listEl || this.view !== 'templates' || this.query) return;\n const hadFocus = this.listEl.contains(document.activeElement);\n this.renderList();\n if (hadFocus && !this.listEl.contains(document.activeElement)) {\n this.listEl.querySelector<HTMLButtonElement>('[data-tpl-save]')?.focus();\n }\n }\n\n /** How many of each indicator are on the chart, shown on their rows. */\n setCounts(counts: ReadonlyMap<string, number>): void {\n this.counts = counts;\n this.listEl?.querySelectorAll<HTMLElement>('.tcw-ip-row[data-ind]').forEach((row) => this.markCount(row));\n }\n\n destroy(): void {\n this.close(false);\n }\n\n private startView(): View {\n const views = this.views();\n if (this.lastView && views.includes(this.lastView) && !(this.lastView === 'favorites' && this.favorites.size === 0)) return this.lastView;\n return this.favorites.size > 0 ? 'favorites' : 'all';\n }\n\n /** The tabs down the side: favourites, templates, all, and each kind that has indicators. */\n private views(): View[] {\n const kinds = new Set(this.content.items.map((item) => item.category));\n return [\n 'favorites',\n ...(this.callbacks.templates && this.content.templates ? ['templates' as const] : []),\n 'all',\n ...INDICATOR_CATEGORIES.filter((category) => kinds.has(category)),\n ];\n }\n\n private viewLabel(view: View): string {\n if (view === 'favorites') return this.t('indicatorPicker.favorites');\n if (view === 'templates') return this.t('toolbar.indicators.templates');\n if (view === 'all') return this.t('toolbar.indicators.all');\n return this.t(`indicatorCategory.${view}` as MessageKey);\n }\n\n private build(): void {\n const backdrop = document.createElement('div');\n backdrop.className = 'tcw-modal-backdrop';\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) this.close();\n });\n const modal = document.createElement('div');\n modal.className = 'tcw-modal tcw-ip';\n modal.setAttribute('role', 'dialog');\n modal.setAttribute('aria-modal', 'true');\n modal.setAttribute('aria-labelledby', `tcw-ip-title-${this.uid}`);\n modal.tabIndex = -1;\n modal.addEventListener('keydown', (e) => this.onKeyDown(e, modal));\n\n const live = document.createElement('div');\n live.className = 'tcw-visually-hidden';\n live.setAttribute('aria-live', 'polite');\n modal.append(this.buildHeader(), this.buildSearch(), this.buildBody(), live);\n backdrop.appendChild(modal);\n this.layer().appendChild(backdrop);\n this.backdrop = backdrop;\n this.liveEl = live;\n this.renderNav();\n this.renderList();\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-ip-title-${this.uid}`;\n title.textContent = this.t('toolbar.indicators');\n const closeBtn = document.createElement('button');\n closeBtn.type = 'button';\n closeBtn.className = 'tcw-modal-close';\n closeBtn.setAttribute('aria-label', this.t('indicatorSettings.close'));\n closeBtn.innerHTML = createIcon('x', 16);\n closeBtn.addEventListener('click', () => this.close());\n header.append(title, closeBtn);\n return header;\n }\n\n private buildSearch(): HTMLLabelElement {\n const row = document.createElement('label');\n row.className = 'tcw-ip-search';\n const search = document.createElement('input');\n search.type = 'search';\n search.id = `tcw-ip-search-${this.uid}`;\n search.placeholder = this.t('indicatorPicker.search');\n search.setAttribute('aria-label', this.t('indicatorPicker.search'));\n search.autocomplete = 'off';\n search.spellcheck = false;\n search.addEventListener('input', () => {\n this.query = search.value;\n this.renderList();\n });\n search.addEventListener('keydown', (e) => this.onSearchKey(e));\n row.innerHTML = createIcon('search', 16);\n row.appendChild(search);\n this.searchEl = search;\n return row;\n }\n\n /** The groups down the side, and the list beside them. */\n private buildBody(): HTMLDivElement {\n const body = document.createElement('div');\n body.className = 'tcw-ip-body';\n const nav = document.createElement('div');\n nav.className = 'tcw-ip-nav';\n nav.setAttribute('role', 'tablist');\n nav.setAttribute('aria-orientation', 'vertical');\n nav.setAttribute('aria-label', this.t('indicatorPicker.groups'));\n nav.addEventListener('keydown', (e) => this.onNavKey(e));\n const list = document.createElement('div');\n list.className = 'tcw-ip-list';\n list.id = `tcw-ip-list-${this.uid}`;\n list.setAttribute('role', 'tabpanel');\n list.addEventListener('keydown', (e) => this.onListKey(e));\n list.addEventListener('focusin', (e) => this.rove(e.target));\n body.append(nav, list);\n this.navEl = nav;\n this.listEl = list;\n return body;\n }\n\n private renderNav(): void {\n const nav = this.navEl;\n if (!nav) return;\n nav.replaceChildren(...this.views().map((view) => {\n const tab = document.createElement('button');\n tab.type = 'button';\n tab.className = 'tcw-ip-tab';\n tab.id = `tcw-ip-tab-${this.uid}-${view}`;\n tab.dataset.view = view;\n tab.setAttribute('role', 'tab');\n tab.setAttribute('aria-controls', `tcw-ip-list-${this.uid}`);\n const icon = view === 'favorites' ? createIcon('star', 14) : view === 'templates' ? createIcon('layers', 14) : '';\n tab.innerHTML = `${icon}<span></span>`;\n tab.querySelector('span')!.textContent = this.viewLabel(view);\n if (view === 'templates') markPart(tab, 'indicatorTemplates');\n tab.addEventListener('click', () => this.select(view));\n return tab;\n }));\n this.markNav();\n }\n\n private markNav(): void {\n this.navEl?.querySelectorAll<HTMLButtonElement>('.tcw-ip-tab').forEach((tab) => {\n const on = tab.dataset.view === this.view;\n tab.setAttribute('aria-selected', String(on));\n tab.classList.toggle('tcw-active', on);\n tab.tabIndex = on ? 0 : -1;\n });\n this.labelList();\n }\n\n /** The list is named by its tab, or by the search while it shows the matches. */\n private labelList(): void {\n const searching = this.query.trim() !== '';\n this.listEl?.setAttribute('aria-labelledby', searching ? `tcw-ip-search-${this.uid}` : `tcw-ip-tab-${this.uid}-${this.view}`);\n }\n\n private select(view: View, focusTab = false): void {\n this.view = this.lastView = view;\n if (this.searchEl && this.query) this.searchEl.value = this.query = '';\n this.markNav();\n this.renderList();\n if (focusTab) this.navEl?.querySelector<HTMLButtonElement>(`[data-view=\"${view}\"]`)?.focus();\n }\n\n private renderList(): void {\n const list = this.listEl;\n if (!list) return;\n list.replaceChildren();\n const items = this.content.items;\n // While searching, the results come from every group: the one picked steps back.\n this.navEl?.classList.toggle('tcw-ip-nav--searching', this.query.trim() !== '');\n this.labelList();\n if (this.query.trim()) {\n const hits = searchIndicators(items, this.query);\n if (hits.length === 0) list.appendChild(this.note(fill(this.t('indicatorPicker.noMatch'), { query: this.query.trim() })));\n else list.append(...hits.map((item) => this.row(item)));\n } else if (this.view === 'templates') {\n this.renderTemplates(list);\n } else if (this.view === 'favorites') {\n const favorites = items.filter((item) => this.favorites.has(item.id)).sort(byName);\n if (favorites.length === 0) list.appendChild(this.note(this.t('indicatorPicker.noFavorites')));\n else list.append(...favorites.map((item) => this.row(item)));\n } else if (this.view === 'all') {\n for (const category of INDICATOR_CATEGORIES) {\n const group = items.filter((item) => item.category === category).sort(byName);\n if (group.length === 0) continue;\n const heading = document.createElement('div');\n heading.className = 'tcw-ip-heading';\n heading.textContent = this.viewLabel(category);\n list.append(heading, ...group.map((item) => this.row(item)));\n }\n } else {\n list.append(...items.filter((item) => item.category === this.view).sort(byName).map((item) => this.row(item)));\n }\n list.querySelector<HTMLButtonElement>('.tcw-ip-add')?.setAttribute('tabindex', '0');\n }\n\n private row(item: IndicatorPickerItem): HTMLDivElement {\n const row = document.createElement('div');\n row.className = 'tcw-ip-row';\n row.dataset.ind = item.id;\n const add = document.createElement('button');\n add.type = 'button';\n add.className = 'tcw-ip-add';\n add.dataset.ind = item.id;\n add.tabIndex = -1;\n const name = document.createElement('span');\n name.className = 'tcw-ip-name';\n name.textContent = item.name;\n add.appendChild(name);\n if (item.shortName && item.shortName !== item.name) add.appendChild(this.tag('tcw-ip-short', item.shortName));\n add.appendChild(this.tag('tcw-ip-kind', this.t(`indicatorType.${item.placement}`)));\n add.addEventListener('click', () => this.add(item));\n const star = document.createElement('button');\n star.type = 'button';\n star.className = 'tcw-ip-aside tcw-ip-star';\n star.tabIndex = -1;\n star.title = this.t('indicatorPicker.favorite');\n star.setAttribute('aria-label', `${this.t('indicatorPicker.favorite')}: ${item.name}`);\n star.setAttribute('aria-pressed', String(this.favorites.has(item.id)));\n star.innerHTML = createIcon('star', 14);\n star.addEventListener('click', () => this.toggleFavorite(item.id, star));\n row.append(add, star);\n this.markCount(row);\n return row;\n }\n\n private renderTemplates(list: HTMLElement): void {\n const save = document.createElement('button');\n save.type = 'button';\n save.className = 'tcw-ip-add tcw-ip-save';\n save.tabIndex = -1;\n save.dataset.tplSave = '';\n save.innerHTML = `${createIcon('save', 14)}<span class=\"tcw-ip-name\"></span>`;\n save.querySelector('span')!.textContent = this.t('templates.save');\n save.addEventListener('click', () => {\n this.close();\n this.callbacks.templates?.onSave();\n });\n list.appendChild(save);\n const names = this.content.templates ?? [];\n if (names.length === 0) list.appendChild(this.note(this.t('indicatorPicker.noTemplates')));\n for (const name of names) {\n const row = document.createElement('div');\n row.className = 'tcw-ip-row';\n const apply = document.createElement('button');\n apply.type = 'button';\n apply.className = 'tcw-ip-add';\n apply.tabIndex = -1;\n apply.dataset.tplApply = name;\n apply.innerHTML = `${createIcon('layers', 14)}<span class=\"tcw-ip-name\"></span>`;\n apply.querySelector('span')!.textContent = name;\n apply.addEventListener('click', () => {\n this.close();\n this.callbacks.templates?.onApply(name);\n });\n const remove = document.createElement('button');\n remove.type = 'button';\n remove.className = 'tcw-ip-aside tcw-ip-remove';\n remove.tabIndex = -1;\n remove.dataset.tplDelete = name;\n const label = fill(this.t('templates.delete'), { name });\n remove.title = label;\n remove.setAttribute('aria-label', label);\n remove.innerHTML = createIcon('x', 12);\n remove.addEventListener('click', () => this.callbacks.templates?.onDelete(name));\n row.append(apply, remove);\n list.appendChild(row);\n }\n }\n\n private add(item: IndicatorPickerItem): void {\n if (this.callbacks.onAdd(item.id) === false || !this.liveEl) return;\n const text = fill(this.t('indicatorPicker.added'), { name: item.name });\n // The same words again (a second RSI) are only read out when they change: a space tells them apart.\n this.liveEl.textContent = this.liveEl.textContent === text ? `${text}\\u00a0` : text;\n }\n\n private toggleFavorite(id: string, star: HTMLButtonElement): void {\n const on = !this.favorites.has(id);\n if (on) this.favorites.add(id);\n else this.favorites.delete(id);\n this.callbacks.onFavorite(id, on);\n star.setAttribute('aria-pressed', String(on));\n if (this.view !== 'favorites' || this.query || on) return;\n // Gone from the favourites: the keyboard moves to the next row's star.\n const stars = [...(this.listEl?.querySelectorAll<HTMLButtonElement>('.tcw-ip-star') ?? [])];\n const at = stars.indexOf(star);\n const hadFocus = document.activeElement === star;\n this.renderList();\n if (!hadFocus) return;\n const left = [...(this.listEl?.querySelectorAll<HTMLButtonElement>('.tcw-ip-star') ?? [])];\n (left[at] ?? left[left.length - 1] ?? this.searchEl)?.focus();\n }\n\n private markCount(row: HTMLElement): void {\n const n = this.counts.get(row.dataset.ind ?? '') ?? 0;\n const add = row.querySelector('.tcw-ip-add');\n let badge = row.querySelector<HTMLElement>('.tcw-ip-count');\n if (n === 0) {\n badge?.remove();\n return;\n }\n if (!badge) {\n badge = this.tag('tcw-ip-count', '');\n add?.appendChild(badge);\n }\n badge.textContent = String(n);\n badge.title = fill(this.t('indicatorPicker.onChart'), { count: String(n) });\n }\n\n private tag(className: string, text: string): HTMLSpanElement {\n const span = document.createElement('span');\n span.className = className;\n span.textContent = text;\n return span;\n }\n\n private note(text: string): HTMLDivElement {\n const el = document.createElement('div');\n el.className = 'tcw-ip-empty';\n el.textContent = text;\n return el;\n }\n\n /** One row in the list takes Tab: the one focused last. */\n private rove(target: EventTarget | null): void {\n if (!(target instanceof HTMLElement) || !target.classList.contains('tcw-ip-add')) return;\n this.listEl?.querySelectorAll<HTMLElement>('.tcw-ip-add[tabindex=\"0\"]').forEach((el) => {\n if (el !== target) el.tabIndex = -1;\n });\n target.tabIndex = 0;\n }\n\n private onKeyDown(e: KeyboardEvent, modal: HTMLElement): void {\n if (e.key === 'Escape') {\n e.preventDefault();\n e.stopPropagation();\n this.close();\n return;\n }\n keepTabInside(e, modal);\n }\n\n /** Down goes into the list; Enter adds the best match. */\n private onSearchKey(e: KeyboardEvent): void {\n const first = this.listEl?.querySelector<HTMLButtonElement>('.tcw-ip-add');\n if (e.key === 'ArrowDown' && first) {\n e.preventDefault();\n first.focus();\n } else if (e.key === 'Enter' && this.query.trim() && first) {\n e.preventDefault();\n first.click();\n }\n }\n\n /** Up and down through the tabs (Home, End), picking as they go. */\n private onNavKey(e: KeyboardEvent): void {\n const views = this.views();\n const at = views.indexOf(this.view);\n const next = e.key === 'ArrowDown' ? Math.min(views.length - 1, at + 1)\n : e.key === 'ArrowUp' ? Math.max(0, at - 1)\n : e.key === 'Home' ? 0\n : e.key === 'End' ? views.length - 1\n : -1;\n if (next < 0) return;\n e.preventDefault();\n this.select(views[next], true);\n }\n\n /** Up and down through the rows (from the top, back to the search); right to a row's star, left back. */\n private onListKey(e: KeyboardEvent): void {\n const target = e.target as HTMLElement;\n const row = target.closest('.tcw-ip-row, .tcw-ip-save');\n const adds = [...(this.listEl?.querySelectorAll<HTMLButtonElement>('.tcw-ip-add') ?? [])];\n const main = row?.classList.contains('tcw-ip-save') ? row as HTMLButtonElement : row?.querySelector<HTMLButtonElement>('.tcw-ip-add');\n const at = main ? adds.indexOf(main) : -1;\n let to: HTMLElement | null | undefined = null;\n if (e.key === 'ArrowDown') to = adds[at + 1];\n else if (e.key === 'ArrowUp') to = at > 0 ? adds[at - 1] : this.searchEl;\n else if (e.key === 'Home') to = adds[0];\n else if (e.key === 'End') to = adds[adds.length - 1];\n else if (e.key === 'ArrowRight' && target === main) to = row?.querySelector<HTMLButtonElement>('.tcw-ip-aside');\n else if (e.key === 'ArrowLeft' && target !== main) to = main;\n if (!to) return;\n e.preventDefault();\n to.focus();\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"WidgetIndicatorPicker-eK03W3LR.js","names":[],"sources":["../src/widget/indicatorSearch.ts","../src/widget/WidgetIndicatorPicker.ts"],"sourcesContent":["/** What a search reads of an indicator. */\nexport interface SearchableIndicator {\n id: string;\n name: string;\n shortName: string;\n}\n\n/** Lower case without accents, so \"mômentum\" finds Momentum. */\nfunction fold(text: string): string {\n return text.normalize('NFD').replace(/[̀-ͯ]/g, '').toLowerCase();\n}\n\nconst WORD_BREAK = /[\\s/()%-]+/;\n\n/** How well an indicator matches `q` (folded): 0 best, null not at all. */\nfunction score(item: SearchableIndicator, q: string): number | null {\n const short = fold(item.shortName);\n const name = fold(item.name);\n if (short === q || fold(item.id) === q) return 0;\n if (short.startsWith(q) || name.startsWith(q)) return 1;\n if ([...name.split(WORD_BREAK), ...short.split(WORD_BREAK)].some((word) => word.startsWith(q))) return 2;\n if (name.includes(q) || short.includes(q)) return 3;\n return null;\n}\n\n/**\n * The indicators matching `query`, best first: the short name typed in full\n * (\"rsi\"), then names starting with it, then a word starting with it, then\n * any containing it. Ties go by name. Nothing typed finds nothing.\n */\nexport function searchIndicators<T extends SearchableIndicator>(items: readonly T[], query: string): T[] {\n const q = fold(query.trim());\n if (!q) return [];\n return items\n .map((item) => ({ item, rank: score(item, q) }))\n .filter((hit): hit is { item: T; rank: number } => hit.rank !== null)\n .sort((a, b) => a.rank - b.rank || a.item.name.localeCompare(b.item.name))\n .map((hit) => hit.item);\n}\n","import type { IndicatorCategory } from '@tradecanvas/commons';\nimport { INDICATOR_CATEGORIES } from '@tradecanvas/core';\nimport { createIcon } from './icons.js';\nimport { fill, type MessageKey, type Translator } from './i18n.js';\nimport { keepTabInside } from './focusTrap.js';\nimport { searchIndicators } from './indicatorSearch.js';\nimport { markPart } from './widgetFeatures.js';\n\n/** An indicator as the dialog lists it. */\nexport interface IndicatorPickerItem {\n id: string;\n name: string;\n shortName: string;\n placement: 'overlay' | 'panel';\n category: IndicatorCategory;\n}\n\nexport interface IndicatorPickerCallbacks {\n /** Add one; false when it wasn't added (nothing is announced then). */\n onAdd: (id: string) => boolean | void;\n onFavorite: (id: string, on: boolean) => void;\n /** The indicator templates; without them there is no Templates tab. */\n templates?: {\n onApply: (name: string) => void;\n onDelete: (name: string) => void;\n onSave: () => void;\n };\n onClose?: () => void;\n}\n\nexport interface IndicatorPickerContent {\n items: readonly IndicatorPickerItem[];\n favorites: readonly string[];\n /** The templates' names; null where they are switched off. */\n templates: readonly string[] | null;\n /** How many of each indicator are on the chart. */\n counts?: ReadonlyMap<string, number>;\n}\n\ntype View = 'favorites' | 'templates' | 'all' | IndicatorCategory;\n\nlet nextPickerId = 1;\n\nconst byName = (a: IndicatorPickerItem, b: IndicatorPickerItem) => a.name.localeCompare(b.name);\n\n/**\n * The indicators dialog: a search, the groups down the side (favourites,\n * templates, all, then each kind) and the list. A row adds its indicator and\n * the dialog stays open for the next; the star beside it keeps it in the\n * favourites. Mounts in the widget's overlay layer.\n */\nexport class WidgetIndicatorPicker {\n private backdrop: HTMLDivElement | null = null;\n private listEl: HTMLDivElement | null = null;\n private navEl: HTMLDivElement | null = null;\n private searchEl: HTMLInputElement | null = null;\n private liveEl: HTMLDivElement | null = null;\n private content: IndicatorPickerContent = { items: [], favorites: [], templates: [] };\n private favorites = new Set<string>();\n private counts: ReadonlyMap<string, number> = new Map();\n private view: View = 'all';\n /** The tab picked last, for the next opening. */\n private lastView: View | null = null;\n private query = '';\n private returnFocus: HTMLElement | null = null;\n private readonly uid = nextPickerId++;\n\n constructor(\n private readonly layer: () => HTMLElement,\n private readonly callbacks: IndicatorPickerCallbacks,\n private readonly t: Translator,\n ) {}\n\n open(content: IndicatorPickerContent): void {\n if (this.backdrop) this.close(false);\n this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n this.content = content;\n this.favorites = new Set(content.favorites);\n this.counts = content.counts ?? new Map();\n this.query = '';\n this.view = this.startView();\n this.build();\n this.searchEl?.focus();\n }\n\n close(giveFocusBack = true): void {\n if (!this.backdrop) return;\n this.backdrop.remove();\n this.backdrop = this.listEl = this.navEl = this.searchEl = this.liveEl = null;\n this.callbacks.onClose?.();\n if (giveFocusBack && this.returnFocus?.isConnected) this.returnFocus.focus();\n this.returnFocus = null;\n }\n\n isOpen(): boolean {\n return this.backdrop !== null;\n }\n\n /** The templates after one is saved or deleted; focus left on a deleted one goes to \"Save…\". */\n setTemplates(names: readonly string[]): void {\n this.content = { ...this.content, templates: [...names] };\n if (!this.listEl || this.view !== 'templates' || this.query) return;\n const hadFocus = this.listEl.contains(document.activeElement);\n this.renderList();\n if (hadFocus && !this.listEl.contains(document.activeElement)) {\n this.listEl.querySelector<HTMLButtonElement>('[data-tpl-save]')?.focus();\n }\n }\n\n /** How many of each indicator are on the chart, shown on their rows. */\n setCounts(counts: ReadonlyMap<string, number>): void {\n this.counts = counts;\n this.listEl?.querySelectorAll<HTMLElement>('.tcw-ip-row[data-ind]').forEach((row) => this.markCount(row));\n }\n\n destroy(): void {\n this.close(false);\n }\n\n private startView(): View {\n const views = this.views();\n if (this.lastView && views.includes(this.lastView) && !(this.lastView === 'favorites' && this.favorites.size === 0)) return this.lastView;\n return this.favorites.size > 0 ? 'favorites' : 'all';\n }\n\n /** The tabs down the side: favourites, templates, all, and each kind that has indicators. */\n private views(): View[] {\n const kinds = new Set(this.content.items.map((item) => item.category));\n return [\n 'favorites',\n ...(this.callbacks.templates && this.content.templates ? ['templates' as const] : []),\n 'all',\n ...INDICATOR_CATEGORIES.filter((category) => kinds.has(category)),\n ];\n }\n\n private viewLabel(view: View): string {\n if (view === 'favorites') return this.t('indicatorPicker.favorites');\n if (view === 'templates') return this.t('toolbar.indicators.templates');\n if (view === 'all') return this.t('toolbar.indicators.all');\n return this.t(`indicatorCategory.${view}` as MessageKey);\n }\n\n private build(): void {\n const backdrop = document.createElement('div');\n backdrop.className = 'tcw-modal-backdrop';\n backdrop.addEventListener('click', (e) => {\n if (e.target === backdrop) this.close();\n });\n const modal = document.createElement('div');\n modal.className = 'tcw-modal tcw-ip';\n modal.setAttribute('role', 'dialog');\n modal.setAttribute('aria-modal', 'true');\n modal.setAttribute('aria-labelledby', `tcw-ip-title-${this.uid}`);\n modal.tabIndex = -1;\n modal.addEventListener('keydown', (e) => this.onKeyDown(e, modal));\n\n const live = document.createElement('div');\n live.className = 'tcw-visually-hidden';\n live.setAttribute('aria-live', 'polite');\n modal.append(this.buildHeader(), this.buildSearch(), this.buildBody(), live);\n backdrop.appendChild(modal);\n this.layer().appendChild(backdrop);\n this.backdrop = backdrop;\n this.liveEl = live;\n this.renderNav();\n this.renderList();\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-ip-title-${this.uid}`;\n title.textContent = this.t('toolbar.indicators');\n const closeBtn = document.createElement('button');\n closeBtn.type = 'button';\n closeBtn.className = 'tcw-modal-close';\n closeBtn.setAttribute('aria-label', this.t('indicatorSettings.close'));\n closeBtn.innerHTML = createIcon('x', 16);\n closeBtn.addEventListener('click', () => this.close());\n header.append(title, closeBtn);\n return header;\n }\n\n private buildSearch(): HTMLLabelElement {\n const row = document.createElement('label');\n row.className = 'tcw-ip-search';\n const search = document.createElement('input');\n search.type = 'search';\n search.id = `tcw-ip-search-${this.uid}`;\n search.placeholder = this.t('indicatorPicker.search');\n search.setAttribute('aria-label', this.t('indicatorPicker.search'));\n search.autocomplete = 'off';\n search.spellcheck = false;\n search.addEventListener('input', () => {\n this.query = search.value;\n this.renderList();\n });\n search.addEventListener('keydown', (e) => this.onSearchKey(e));\n row.innerHTML = createIcon('search', 16);\n row.appendChild(search);\n this.searchEl = search;\n return row;\n }\n\n /** The groups down the side, and the list beside them. */\n private buildBody(): HTMLDivElement {\n const body = document.createElement('div');\n body.className = 'tcw-ip-body';\n const nav = document.createElement('div');\n nav.className = 'tcw-ip-nav';\n nav.setAttribute('role', 'tablist');\n nav.setAttribute('aria-orientation', 'vertical');\n nav.setAttribute('aria-label', this.t('indicatorPicker.groups'));\n nav.addEventListener('keydown', (e) => this.onNavKey(e));\n const list = document.createElement('div');\n list.className = 'tcw-ip-list';\n list.id = `tcw-ip-list-${this.uid}`;\n list.setAttribute('role', 'tabpanel');\n list.addEventListener('keydown', (e) => this.onListKey(e));\n list.addEventListener('focusin', (e) => this.rove(e.target));\n body.append(nav, list);\n this.navEl = nav;\n this.listEl = list;\n return body;\n }\n\n private renderNav(): void {\n const nav = this.navEl;\n if (!nav) return;\n nav.replaceChildren(...this.views().map((view) => {\n const tab = document.createElement('button');\n tab.type = 'button';\n tab.className = 'tcw-ip-tab';\n tab.id = `tcw-ip-tab-${this.uid}-${view}`;\n tab.dataset.view = view;\n tab.setAttribute('role', 'tab');\n tab.setAttribute('aria-controls', `tcw-ip-list-${this.uid}`);\n const icon = view === 'favorites' ? createIcon('star', 14) : view === 'templates' ? createIcon('layers', 14) : '';\n tab.innerHTML = `${icon}<span></span>`;\n tab.querySelector('span')!.textContent = this.viewLabel(view);\n if (view === 'templates') markPart(tab, 'indicatorTemplates');\n tab.addEventListener('click', () => this.select(view));\n return tab;\n }));\n this.markNav();\n }\n\n private markNav(): void {\n this.navEl?.querySelectorAll<HTMLButtonElement>('.tcw-ip-tab').forEach((tab) => {\n const on = tab.dataset.view === this.view;\n tab.setAttribute('aria-selected', String(on));\n tab.classList.toggle('tcw-active', on);\n tab.tabIndex = on ? 0 : -1;\n });\n this.labelList();\n }\n\n /** The list is named by its tab, or by the search while it shows the matches. */\n private labelList(): void {\n const searching = this.query.trim() !== '';\n this.listEl?.setAttribute('aria-labelledby', searching ? `tcw-ip-search-${this.uid}` : `tcw-ip-tab-${this.uid}-${this.view}`);\n }\n\n private select(view: View, focusTab = false): void {\n this.view = this.lastView = view;\n if (this.searchEl && this.query) this.searchEl.value = this.query = '';\n this.markNav();\n this.renderList();\n if (focusTab) this.navEl?.querySelector<HTMLButtonElement>(`[data-view=\"${view}\"]`)?.focus();\n }\n\n private renderList(): void {\n const list = this.listEl;\n if (!list) return;\n list.replaceChildren();\n const items = this.content.items;\n // While searching, the results come from every group: the one picked steps back.\n this.navEl?.classList.toggle('tcw-ip-nav--searching', this.query.trim() !== '');\n this.labelList();\n if (this.query.trim()) {\n const hits = searchIndicators(items, this.query);\n if (hits.length === 0) list.appendChild(this.note(fill(this.t('indicatorPicker.noMatch'), { query: this.query.trim() })));\n else list.append(...hits.map((item) => this.row(item)));\n } else if (this.view === 'templates') {\n this.renderTemplates(list);\n } else if (this.view === 'favorites') {\n const favorites = items.filter((item) => this.favorites.has(item.id)).sort(byName);\n if (favorites.length === 0) list.appendChild(this.note(this.t('indicatorPicker.noFavorites')));\n else list.append(...favorites.map((item) => this.row(item)));\n } else if (this.view === 'all') {\n for (const category of INDICATOR_CATEGORIES) {\n const group = items.filter((item) => item.category === category).sort(byName);\n if (group.length === 0) continue;\n const heading = document.createElement('div');\n heading.className = 'tcw-ip-heading';\n heading.textContent = this.viewLabel(category);\n list.append(heading, ...group.map((item) => this.row(item)));\n }\n } else {\n list.append(...items.filter((item) => item.category === this.view).sort(byName).map((item) => this.row(item)));\n }\n list.querySelector<HTMLButtonElement>('.tcw-ip-add')?.setAttribute('tabindex', '0');\n }\n\n private row(item: IndicatorPickerItem): HTMLDivElement {\n const row = document.createElement('div');\n row.className = 'tcw-ip-row';\n row.dataset.ind = item.id;\n const add = document.createElement('button');\n add.type = 'button';\n add.className = 'tcw-ip-add';\n add.dataset.ind = item.id;\n add.tabIndex = -1;\n const name = document.createElement('span');\n name.className = 'tcw-ip-name';\n name.textContent = item.name;\n add.appendChild(name);\n if (item.shortName && item.shortName !== item.name) add.appendChild(this.tag('tcw-ip-short', item.shortName));\n add.appendChild(this.tag('tcw-ip-kind', this.t(`indicatorType.${item.placement}`)));\n add.addEventListener('click', () => this.add(item));\n const star = document.createElement('button');\n star.type = 'button';\n star.className = 'tcw-ip-aside tcw-ip-star';\n star.tabIndex = -1;\n star.title = this.t('indicatorPicker.favorite');\n star.setAttribute('aria-label', `${this.t('indicatorPicker.favorite')}: ${item.name}`);\n star.setAttribute('aria-pressed', String(this.favorites.has(item.id)));\n star.innerHTML = createIcon('star', 14);\n star.addEventListener('click', () => this.toggleFavorite(item.id, star));\n row.append(add, star);\n this.markCount(row);\n return row;\n }\n\n private renderTemplates(list: HTMLElement): void {\n const save = document.createElement('button');\n save.type = 'button';\n save.className = 'tcw-ip-add tcw-ip-save';\n save.tabIndex = -1;\n save.dataset.tplSave = '';\n save.innerHTML = `${createIcon('save', 14)}<span class=\"tcw-ip-name\"></span>`;\n save.querySelector('span')!.textContent = this.t('templates.save');\n save.addEventListener('click', () => {\n this.close();\n this.callbacks.templates?.onSave();\n });\n list.appendChild(save);\n const names = this.content.templates ?? [];\n if (names.length === 0) list.appendChild(this.note(this.t('indicatorPicker.noTemplates')));\n for (const name of names) {\n const row = document.createElement('div');\n row.className = 'tcw-ip-row';\n const apply = document.createElement('button');\n apply.type = 'button';\n apply.className = 'tcw-ip-add';\n apply.tabIndex = -1;\n apply.dataset.tplApply = name;\n apply.innerHTML = `${createIcon('layers', 14)}<span class=\"tcw-ip-name\"></span>`;\n apply.querySelector('span')!.textContent = name;\n apply.addEventListener('click', () => {\n this.close();\n this.callbacks.templates?.onApply(name);\n });\n const remove = document.createElement('button');\n remove.type = 'button';\n remove.className = 'tcw-ip-aside tcw-ip-remove';\n remove.tabIndex = -1;\n remove.dataset.tplDelete = name;\n const label = fill(this.t('templates.delete'), { name });\n remove.title = label;\n remove.setAttribute('aria-label', label);\n remove.innerHTML = createIcon('x', 12);\n remove.addEventListener('click', () => this.callbacks.templates?.onDelete(name));\n row.append(apply, remove);\n list.appendChild(row);\n }\n }\n\n private add(item: IndicatorPickerItem): void {\n if (this.callbacks.onAdd(item.id) === false || !this.liveEl) return;\n const text = fill(this.t('indicatorPicker.added'), { name: item.name });\n // The same words again (a second RSI) are only read out when they change: a space tells them apart.\n this.liveEl.textContent = this.liveEl.textContent === text ? `${text}\\u00a0` : text;\n }\n\n private toggleFavorite(id: string, star: HTMLButtonElement): void {\n const on = !this.favorites.has(id);\n if (on) this.favorites.add(id);\n else this.favorites.delete(id);\n this.callbacks.onFavorite(id, on);\n star.setAttribute('aria-pressed', String(on));\n if (this.view !== 'favorites' || this.query || on) return;\n // Gone from the favourites: the keyboard moves to the next row's star.\n const stars = [...(this.listEl?.querySelectorAll<HTMLButtonElement>('.tcw-ip-star') ?? [])];\n const at = stars.indexOf(star);\n const hadFocus = document.activeElement === star;\n this.renderList();\n if (!hadFocus) return;\n const left = [...(this.listEl?.querySelectorAll<HTMLButtonElement>('.tcw-ip-star') ?? [])];\n (left[at] ?? left[left.length - 1] ?? this.searchEl)?.focus();\n }\n\n private markCount(row: HTMLElement): void {\n const n = this.counts.get(row.dataset.ind ?? '') ?? 0;\n const add = row.querySelector('.tcw-ip-add');\n let badge = row.querySelector<HTMLElement>('.tcw-ip-count');\n if (n === 0) {\n badge?.remove();\n return;\n }\n if (!badge) {\n badge = this.tag('tcw-ip-count', '');\n add?.appendChild(badge);\n }\n badge.textContent = String(n);\n badge.title = fill(this.t('indicatorPicker.onChart'), { count: String(n) });\n }\n\n private tag(className: string, text: string): HTMLSpanElement {\n const span = document.createElement('span');\n span.className = className;\n span.textContent = text;\n return span;\n }\n\n private note(text: string): HTMLDivElement {\n const el = document.createElement('div');\n el.className = 'tcw-ip-empty';\n el.textContent = text;\n return el;\n }\n\n /** One row in the list takes Tab: the one focused last. */\n private rove(target: EventTarget | null): void {\n if (!(target instanceof HTMLElement) || !target.classList.contains('tcw-ip-add')) return;\n this.listEl?.querySelectorAll<HTMLElement>('.tcw-ip-add[tabindex=\"0\"]').forEach((el) => {\n if (el !== target) el.tabIndex = -1;\n });\n target.tabIndex = 0;\n }\n\n private onKeyDown(e: KeyboardEvent, modal: HTMLElement): void {\n if (e.key === 'Escape') {\n e.preventDefault();\n e.stopPropagation();\n this.close();\n return;\n }\n keepTabInside(e, modal);\n }\n\n /** Down goes into the list; Enter adds the best match. */\n private onSearchKey(e: KeyboardEvent): void {\n const first = this.listEl?.querySelector<HTMLButtonElement>('.tcw-ip-add');\n if (e.key === 'ArrowDown' && first) {\n e.preventDefault();\n first.focus();\n } else if (e.key === 'Enter' && this.query.trim() && first) {\n e.preventDefault();\n first.click();\n }\n }\n\n /** Up and down through the tabs (Home, End), picking as they go. */\n private onNavKey(e: KeyboardEvent): void {\n const views = this.views();\n const at = views.indexOf(this.view);\n const next = e.key === 'ArrowDown' ? Math.min(views.length - 1, at + 1)\n : e.key === 'ArrowUp' ? Math.max(0, at - 1)\n : e.key === 'Home' ? 0\n : e.key === 'End' ? views.length - 1\n : -1;\n if (next < 0) return;\n e.preventDefault();\n this.select(views[next], true);\n }\n\n /** Up and down through the rows (from the top, back to the search); right to a row's star, left back. */\n private onListKey(e: KeyboardEvent): void {\n const target = e.target as HTMLElement;\n const row = target.closest('.tcw-ip-row, .tcw-ip-save');\n const adds = [...(this.listEl?.querySelectorAll<HTMLButtonElement>('.tcw-ip-add') ?? [])];\n const main = row?.classList.contains('tcw-ip-save') ? row as HTMLButtonElement : row?.querySelector<HTMLButtonElement>('.tcw-ip-add');\n const at = main ? adds.indexOf(main) : -1;\n let to: HTMLElement | null | undefined = null;\n if (e.key === 'ArrowDown') to = adds[at + 1];\n else if (e.key === 'ArrowUp') to = at > 0 ? adds[at - 1] : this.searchEl;\n else if (e.key === 'Home') to = adds[0];\n else if (e.key === 'End') to = adds[adds.length - 1];\n else if (e.key === 'ArrowRight' && target === main) to = row?.querySelector<HTMLButtonElement>('.tcw-ip-aside');\n else if (e.key === 'ArrowLeft' && target !== main) to = main;\n if (!to) return;\n e.preventDefault();\n to.focus();\n }\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- const e=require(`./widgetFeatures-BZ8OVPN2.cjs`),t=require(`./focusTrap-DrhhmG0V.cjs`),n=require(`./symbolCatalog-CXqRu23x.cjs`),r=require(`./i18n-fgAwciRT.cjs`);var i=20,a=1e3,o=new Set,s={stock:1,stocks:1,equity:1,share:1,shares:1,"cổ phiếu":1,株式:1,株:1,股票:1,주식:1,futures:2,future:2,derivative:2,derivatives:2,option:2,options:2,"phái sinh":2,先物:2,期货:2,期貨:2,선물:2,warrant:2,warrants:2,"covered warrant":2,"chứng quyền":2,index:3,indices:3,"chỉ số":3,指数:3,指數:3,지수:3,fund:3,funds:3,etf:3,etfs:3,"chứng chỉ quỹ":3,crypto:4,cryptocurrency:4,perpetual:4,perpetuals:4,perp:4,perps:4,"tiền mã hóa":4,"tiền mã hoá":4,"tiền điện tử":4,暗号資産:4,仮想通貨:4,加密货币:4,加密貨幣:4,数字货币:4,數字貨幣:4,虚拟货币:4,虛擬貨幣:4,암호화폐:4,가상자산:4,가상화폐:4,forex:5,fx:5,currency:5,"ngoại hối":5,為替:5,外国為替:5,外汇:5,外匯:5,외환:5,bond:5,bonds:5,"trái phiếu":5},c=1e3,l=new Map,u=/i\u0307|\u0131/g;function d(e){if(typeof e!=`string`)return``;let t=l.get(e);return t===void 0&&(t=e.trim().normalize(`NFC`).toLowerCase().replace(u,`i`),l.size>=c&&l.clear(),l.set(e,t)),t}function f(e){let t=d(e);return t?Object.prototype.hasOwnProperty.call(s,t)?s[t]:1+p(t)%5:0}function p(e){let t=2166136261;for(let n of e)t^=n.codePointAt(0),t=Math.imul(t,16777619)>>>0;return t}function m(e){let{ticker:t}=n.c(e),r=/[\p{L}\p{N}]/u.exec(t);return r?r[0].toUpperCase():``}function h(e,t){let r=n.i(t?.logo);if(!r||o.has(r))return _(e,t);let a=document.createElement(`img`);return a.className=`tcw-ss-badge`,a.alt=``,a.width=i,a.height=i,a.draggable=!1,a.setAttribute(`aria-hidden`,`true`),a.setAttribute(`loading`,`lazy`),a.setAttribute(`decoding`,`async`),a.setAttribute(`referrerpolicy`,`no-referrer`),a.addEventListener(`error`,()=>{g(r),a.replaceWith(_(e,t))},{once:!0}),a.src=r,a}function g(e){o.size>=a&&o.clear(),o.add(e)}function _(e,t){let n=document.createElement(`span`);return n.className=`tcw-ss-badge`,n.setAttribute(`aria-hidden`,`true`),n.dataset.kind=String(f(t?.type)),n.textContent=m(e),n}var v=180,y=150,b=50;function x(e){return{upper:e.toUpperCase(),folded:T(e)}}function S(e,t,n){return Math.max(C(e.toUpperCase(),n.upper),w(t,n.folded))}function C(e,t){if(e===t)return 1e3;if(e.startsWith(t))return 500+(50-Math.min(50,e.length-t.length));if(e.includes(t))return 200+(50-Math.min(50,e.length-t.length));let n=0,r=-1,i=0;for(let a=0;a<e.length&&n<t.length;a++)e[a]===t[n]&&(r>=0&&(i+=a-r-1),r=a,n++);return n<t.length?0:100-Math.min(99,i)}function w(e,t){if(!e||!t)return 0;if(e.startsWith(t))return v;let n=e.indexOf(t);return n<0?0:y-Math.min(b,n)}function T(e){return e.normalize(`NFD`).replace(/\p{M}+/gu,``).replace(/[đĐ]/g,`D`).toUpperCase()}function E(e,t,r=0,i=e.length){let a=t?D(e.toUpperCase(),t):new Set,o=``;for(let t=r;t<i;t++)o+=a.has(t)?`<mark>${n.u(e[t])}</mark>`:n.u(e[t]);return o}function D(e,t){let n=new Set,r=e.indexOf(t);if(r>=0){for(let e=r;e<r+t.length;e++)n.add(e);return n}let i=0;for(let r=0;r<e.length&&i<t.length;r++)e[r]===t[i]&&(n.add(r),i++);return i<t.length?new Set:n}function O(e,t){let r=document.createElement(`span`);r.className=`tcw-ss-symbol`,r.dir=`ltr`;let{venue:i}=n.c(e);i&&(r.title=e);let a=document.createElement(`span`);return a.className=`tcw-ss-ticker`,a.innerHTML=E(e,t,i.length,e.length),r.appendChild(a),r}function k(e){return n.c(e).venue.replace(/:$/,``).replace(/:/g,` `)}var A=d,j=2,M=1,N=class{el;kindsEl;exchangeEl;kinds=new Map;exchanges=new Map;kind=null;exchange=null;resize;constructor(e,t){this.t=e,this.onChange=t,this.el=document.createElement(`div`),this.el.className=`tcw-ss-filters`,this.el.hidden=!0,this.kindsEl=document.createElement(`div`),this.kindsEl.className=`tcw-ss-kinds`,this.kindsEl.setAttribute(`role`,`group`),this.kindsEl.setAttribute(`aria-label`,e(`symbolSearch.kinds`)),this.kindsEl.hidden=!0,this.kindsEl.addEventListener(`scroll`,()=>this.markMore(),{passive:!0}),this.resize=typeof ResizeObserver>`u`?null:new ResizeObserver(()=>this.markMore()),this.resize?.observe(this.kindsEl),this.exchangeEl=document.createElement(`select`),this.exchangeEl.className=`tcw-settings-select tcw-ss-exchange-filter`,this.exchangeEl.setAttribute(`aria-label`,e(`symbolSearch.exchange`)),this.exchangeEl.hidden=!0,this.exchangeEl.addEventListener(`change`,()=>{this.exchange=A(this.exchangeEl.value)||null,this.onChange(!1)}),this.el.append(this.kindsEl,this.exchangeEl)}see(e){let t=this.kinds.size,n=this.exchanges.size;for(let t of e)P(this.kinds,t?.type),P(this.exchanges,t?.exchange);this.exchanges.size!==n&&this.renderExchanges(),this.exchangeEl.hidden=this.exchanges.size<j,(this.kinds.size!==t||!this.exchangeEl.hidden&&this.kindsEl.childElementCount===0)&&this.renderKinds(),this.kindsEl.hidden=this.kinds.size===0&&this.exchangeEl.hidden,this.el.hidden=this.kindsEl.hidden&&this.exchangeEl.hidden,this.markMore()}destroy(){this.resize?.disconnect()}markMore(){let e=this.kindsEl,t=Math.abs(e.scrollLeft),n=e.scrollWidth-e.clientWidth,r=[t>M?`start`:``,t<n-M?`end`:``].filter(Boolean);r.length>0?e.dataset.more=r.join(` `):delete e.dataset.more}passes(e,t){return F(this.kind,A(e?.type),t)&&F(this.exchange,A(e?.exchange),t)}renderKinds(){let e=(e,t)=>{let n=document.createElement(`button`);return n.type=`button`,n.className=`tcw-ss-type`,n.textContent=t,e!==null&&(n.dir=`auto`),n.setAttribute(`aria-pressed`,String(this.kind===e)),n.addEventListener(`click`,()=>{this.kind=e;for(let e of this.kindsEl.children)e.setAttribute(`aria-pressed`,String(e===n));this.onChange(!0)}),n},t=[...this.kinds].map(([t,n])=>e(t,n));this.kindsEl.replaceChildren(e(null,this.t(`symbolSearch.allKinds`)),...t)}renderExchanges(){let e=(e,t)=>{let n=document.createElement(`option`);return n.value=e,n.textContent=t,e&&(n.dir=`auto`),n},t=[...this.exchanges.values()].map(t=>e(t,t));this.exchangeEl.replaceChildren(e(``,this.t(`symbolSearch.allExchanges`)),...t),this.exchangeEl.value=this.exchange===null?``:this.exchanges.get(this.exchange)??``}};function P(e,t){let n=A(t);n&&!e.has(n)&&e.set(n,t.trim())}function F(e,t,n){return e===null||t===e||n&&t===``}var I=150,L=229,R=200,z=1;function B(e){return e.info?.exchange?.trim()||k(e.symbol)}function V(e){let t=B(e);return t?{...e.info??{symbol:e.symbol},exchange:t}:e.info}var H=class{backdrop=null;input=null;list=null;results=null;live=null;columns=null;filters=null;mode=null;given=[];rows=[];rowsGiven=!1;shown=[];compared=[];way=``;selectedIndex=0;searchFn=null;searchTimer=null;searchAbort=null;status=`idle`;pickOnResults=!1;heard=new Map;givenInfo=new Map;foldedNames=new Map;returnFocus=null;uid=z++;constructor(e,t=()=>document.body,n=r.t){this.callbacks=e,this.host=t,this.t=n}open(e){this.begin({kind:`search`,start:e})}openCompare(e){this.compared=e.compared,this.way=e.ways.some(t=>t.id===e.way)?e.way:e.ways[0]?.id??``,this.begin({kind:`compare`,start:e})}setCompared(e){if(this.compared=e,this.mode?.kind!==`compare`||!this.results)return;let t=this.results.contains(document.activeElement);this.renderList(),t&&!this.results.contains(document.activeElement)&&this.input?.focus()}close(){if(!this.backdrop)return;this.cancelSearch(),this.pickOnResults=!1,this.searchFn=null,this.backdrop.remove(),this.backdrop=this.input=this.list=this.results=this.live=this.columns=null,this.filters?.destroy(),this.filters=null,this.mode=null,this.callbacks.onClose();let e=this.returnFocus;this.returnFocus=null,e?.isConnected&&e.focus()}isOpen(){return this.backdrop!==null}isComparing(){return this.mode?.kind===`compare`}destroy(){this.close()}begin(e){this.backdrop&&this.close(),this.returnFocus=document.activeElement instanceof HTMLElement?document.activeElement:null,this.mode=e,this.searchFn=e.start.search??null,this.status=`idle`,this.learnGiven(e),this.build(e);let t=e.kind===`search`?e.start.query??``:``;this.input&&(this.input.value=t),t?(this.filter(),this.searchFn&&this.searchNow()):this.listGiven(),this.input?.focus()}learnGiven(e){let t=n.o(e.start.symbols);this.given=t.names,this.givenInfo=t.info,this.foldedNames=new Map;let r=e.start.current,i=e.kind===`search`?e.start.currentInfo:null;if(i&&typeof i==`object`&&r){let{description:e,logo:t}=n.r(i,r);this.givenInfo.set(r,n.a({symbol:r,description:e,logo:t},this.givenInfo.get(r)))}}infoOf(e){return n.a(this.givenInfo.get(e),this.heard.get(e))}build(t){let n=document.createElement(`div`);n.className=`tcw-modal-backdrop`;let r=!1;n.addEventListener(`pointerdown`,e=>{r=e.target===n}),n.addEventListener(`click`,e=>{e.target===n&&r&&this.close(),r=!1});let i=document.createElement(`div`);i.className=`tcw-modal tcw-ss${t.kind===`compare`?` tcw-ss--compare`:``}`,e.o(i,t.kind===`compare`?`compare`:`symbolSearch`),i.setAttribute(`role`,`dialog`),i.setAttribute(`aria-modal`,`true`),i.setAttribute(`aria-labelledby`,`tcw-ss-title-${this.uid}`),i.tabIndex=-1,i.addEventListener(`keydown`,e=>this.onKeyDown(e,i)),i.append(this.buildHeader(t),this.buildSearch()),t.kind===`compare`&&i.appendChild(this.buildWay(t.start));let a=new N(this.t,e=>{this.afterResults(!1),e&&this.input?.focus()}),o=document.createElement(`div`);o.className=`tcw-ss-list`,o.id=`tcw-ss-list-${this.uid}`,o.setAttribute(`role`,`listbox`);let s=document.createElement(`div`);s.className=`tcw-ss-results`;let c=this.buildColumns();s.append(c,o),s.addEventListener(`mousedown`,e=>{e.target.closest(`button`)||e.preventDefault()});let l=document.createElement(`div`);l.className=`tcw-ss-live tcw-visually-hidden`,l.setAttribute(`aria-live`,`polite`),i.append(a.el,s,l);let u=t.kind===`search`?t.start.hint:void 0;if(u){let e=document.createElement(`div`);e.className=`tcw-ss-foot`,e.textContent=u,i.appendChild(e)}n.appendChild(i),this.host().appendChild(n),this.backdrop=n,this.filters=a,this.columns=c,this.list=o,this.results=s,this.live=l}buildColumns(){let e=document.createElement(`div`);e.className=`tcw-ss-columns`,e.setAttribute(`aria-hidden`,`true`);let t=[``,this.t(`symbolSearch.symbol`),this.t(`symbolSearch.description`),this.t(`symbolSearch.type`),this.t(`symbolSearch.exchange`)];return e.append(...t.map(e=>this.tag(`tcw-ss-head`,e))),e}buildHeader(e){let n=document.createElement(`div`);n.className=`tcw-modal-header`;let r=document.createElement(`h3`);r.id=`tcw-ss-title-${this.uid}`,r.textContent=this.t(e.kind===`compare`?`compare.title`:`symbolSearch.title`);let i=document.createElement(`button`);return i.type=`button`,i.className=`tcw-modal-close`,i.setAttribute(`aria-label`,this.t(`common.close`)),i.innerHTML=t.i(`x`,16),i.addEventListener(`click`,()=>this.close()),n.append(r,i),n}buildSearch(){let e=document.createElement(`label`);e.className=`tcw-ss-search`,e.innerHTML=t.i(`search`,16);let n=document.createElement(`input`);return n.type=`search`,n.className=`tcw-ss-input`,n.placeholder=this.t(`symbolSearch.placeholder`),n.setAttribute(`aria-label`,this.t(`symbolSearch.placeholder`)),n.setAttribute(`role`,`combobox`),n.setAttribute(`aria-expanded`,`true`),n.setAttribute(`aria-controls`,`tcw-ss-list-${this.uid}`),n.setAttribute(`aria-autocomplete`,`list`),n.autocomplete=`off`,n.spellcheck=!1,n.addEventListener(`input`,()=>this.filter()),e.appendChild(n),this.input=n,e}buildWay(e){let t=document.createElement(`label`);t.className=`tcw-ss-way`;let n=document.createElement(`span`);n.textContent=this.t(`compare.addAs`);let r=document.createElement(`select`);r.className=`tcw-settings-select tcw-ss-way-select`;for(let t of e.ways){let e=document.createElement(`option`);e.value=t.id,e.textContent=t.label,r.appendChild(e)}return r.value=this.way,r.addEventListener(`change`,()=>{this.way=r.value}),t.append(n,r),t}listGiven(){this.rows=this.given.map(e=>({symbol:e,score:0,info:this.infoOf(e)})),this.rowsGiven=!0,this.afterResults(!0)}filter(){this.pickOnResults=!1;let e=this.input?.value.trim()??``;if(this.searchFn&&e){this.scheduleSearch(e);return}if(this.cancelSearch(),this.status=`idle`,!e){this.listGiven();return}let t=x(e);this.rows=this.given.map(e=>{let n=this.infoOf(e);return{symbol:e,score:S(e,this.foldedName(n?.description),t),info:n}}).filter(e=>e.score>0).sort((e,t)=>t.score-e.score),this.rowsGiven=!0,this.afterResults(!1)}foldedName(e){if(!e)return``;let t=this.foldedNames.get(e);return t===void 0&&(t=T(e),this.foldedNames.set(e,t)),t}scheduleSearch(e){this.searchTimer!==null&&clearTimeout(this.searchTimer),this.searchTimer=setTimeout(()=>{this.searchTimer=null,this.runSearch(e)},150)}searchNow(){this.searchTimer!==null&&clearTimeout(this.searchTimer),this.searchTimer=null,this.runSearch(this.input?.value.trim()??``)}async runSearch(e){let t=this.searchFn;if(!t)return;this.searchAbort?.abort();let r=new AbortController;this.searchAbort=r,this.status=`searching`,this.shown.length===0&&this.renderList();try{let i=await t(e,r.signal);if(r.signal.aborted)return;let a=n.s(i);for(let e of a)this.heard.set(e.symbol,n.a(this.heard.get(e.symbol),e));this.rows=a.map(e=>({symbol:e.symbol,score:0,info:this.infoOf(e.symbol)})),this.status=`idle`}catch{if(r.signal.aborted)return;this.rows=[],this.status=`failed`}this.rowsGiven=!1,this.afterResults(!1),this.pickOnResults&&(this.pickOnResults=!1,this.pick(0))}cancelSearch(){this.searchTimer!==null&&clearTimeout(this.searchTimer),this.searchTimer=null,this.searchAbort?.abort(),this.searchAbort=null}afterResults(e){let t=this.listableRows();this.filters?.see(t.map(V)),this.shown=this.visibleRows(t);let n=e?this.shown.findIndex(e=>e.symbol===this.mode?.start.current):-1;this.selectedIndex=n>=0&&n<this.listedCount()?n:0,this.renderList()}listedCount(){return Math.min(this.shown.length,200)}listableRows(){if(this.mode?.kind!==`compare`)return this.rows;let e=this.mode.start.current;return this.rows.filter(t=>t.symbol!==e)}visibleRows(e){let t=this.filters;return t?e.filter(e=>t.passes(V(e),this.rowsGiven)):[...e]}renderList(){let e=this.list,t=this.results;if(!e||!t)return;let n=(this.input?.value??``).trim(),r=this.mode?.kind===`compare`,i=[];if(r&&!n&&this.compared.length>0){let t=this.heading(this.t(`compare.onChart`),`added`),n=document.createElement(`div`);n.className=`tcw-ss-added`,n.setAttribute(`role`,`group`),n.setAttribute(`aria-labelledby`,t.id),n.append(...this.compared.map(e=>this.addedRow(e)));let r=this.heading(this.t(`compare.symbols`),`symbols`);r.hidden=this.shown.length===0,i.push(t,n,r),e.setAttribute(`aria-labelledby`,r.id)}else e.setAttribute(`aria-labelledby`,`tcw-ss-title-${this.uid}`);let a=n.toUpperCase(),o=new Set(this.compared.map(e=>e.symbol)),s=this.shown.slice(0,200);e.replaceChildren(...s.map((e,t)=>this.row(e,t,a,r&&o.has(e.symbol))));let c=this.shown.length===0?this.emptyNote(n,r):this.moreNote(this.shown.length-s.length);t.replaceChildren(...this.columns?[this.columns]:[],...i,e,...c?[c]:[]),this.live&&(this.live.textContent=this.shown.length===0?c?.textContent??``:``),this.markSelection()}emptyNote(e,t){let n;if(this.status===`searching`)n=this.t(`symbolSearch.searching`);else if(this.status===`failed`)n=this.t(`symbolSearch.failed`);else if(t&&!e){if(this.compared.length>0)return null;n=this.t(`compare.empty`)}else n=this.t(`symbolSearch.empty`);let r=document.createElement(`div`);return r.className=`tcw-ss-empty`,r.textContent=n,r}moreNote(e){if(e<=0)return null;let t=document.createElement(`div`);return t.className=`tcw-ss-more`,t.textContent=r.r(this.t(`symbolSearch.more`),{count:e}),t}heading(e,t){let n=document.createElement(`div`);return n.className=`tcw-ss-heading`,n.id=`tcw-ss-${t}-${this.uid}`,n.textContent=e,n}row(e,n,r,i){let a=document.createElement(`div`);a.className=`tcw-ss-row`,a.id=`tcw-ss-opt-${this.uid}-${n}`,a.dataset.symbol=e.symbol,a.setAttribute(`role`,`option`);let o=this.mode?.kind===`search`&&e.symbol===this.mode.start.current;a.classList.toggle(`tcw-current`,o),a.classList.toggle(`tcw-on-chart`,i),o&&a.setAttribute(`aria-current`,`true`);let s=this.tag(`tcw-ss-kind`,e.info?.type?.trim()??``),c=this.tag(`tcw-ss-exchange`,B(e));if(s.dir=c.dir=`auto`,a.append(h(e.symbol,e.info),O(e.symbol,r),this.descriptionCell(e),s,c),o||i){let e=document.createElement(`span`);e.className=`tcw-ss-check`,e.innerHTML=t.i(`check`,14),a.appendChild(e)}return i&&a.appendChild(this.tag(`tcw-visually-hidden`,this.t(`compare.onChart`))),a.addEventListener(`click`,()=>this.pick(n)),a.addEventListener(`mousemove`,()=>{this.selectedIndex!==n&&(this.selectedIndex=n,this.markSelection())}),a}descriptionCell(e){let t=document.createElement(`span`);t.className=`tcw-ss-desc-cell`;let n=e.info?.description&&e.info.description!==e.symbol?e.info.description:``;if(n){let e=this.tag(`tcw-ss-desc`,n);e.dir=`auto`,t.appendChild(e)}return t}addedRow(e){let n=document.createElement(`div`);if(n.className=`tcw-ss-added-row`,n.setAttribute(`role`,`presentation`),e.color){let t=document.createElement(`span`);t.className=`tcw-ss-swatch`,t.style.background=e.color,n.appendChild(t)}let i=document.createElement(`span`);i.className=`tcw-ss-way-cell`,i.appendChild(this.tag(`tcw-ss-way-label`,e.way));let a=document.createElement(`button`);a.type=`button`,a.className=`tcw-ss-remove`;let o=r.r(this.t(`compare.remove`),{symbol:e.symbol});return a.title=o,a.setAttribute(`aria-label`,o),a.innerHTML=t.i(`x`,12),a.addEventListener(`click`,()=>{this.mode?.kind===`compare`&&this.mode.start.onRemove(e.id)}),n.append(O(e.symbol,``),i,a),n}tag(e,t){let n=document.createElement(`span`);return n.className=e,n.textContent=t,n}markSelection(){let e=this.list?.querySelectorAll(`.tcw-ss-row`)??[],t=null;e.forEach((e,n)=>{let r=n===this.selectedIndex;e.setAttribute(`aria-selected`,String(r)),e.classList.toggle(`tcw-selected`,r),r&&(t=e)});let n=t;n?(this.input?.setAttribute(`aria-activedescendant`,n.id),n.scrollIntoView?.({block:`nearest`})):this.input?.removeAttribute(`aria-activedescendant`)}pick(e){let t=this.shown[e],n=this.mode;if(!t||!n)return;if(n.kind===`compare`){this.selectedIndex=e,this.markSelection(),n.start.onAdd(t.symbol,this.way);return}let r=n.start.onPick??this.callbacks.onPick;this.close(),r(t.symbol)}onKeyDown(e,n){if(e.stopPropagation(),e.isComposing||e.keyCode===L)return;if(e.key===`Escape`){e.preventDefault(),this.close();return}if(t.n(e,n),e.target!==this.input)return;let r=this.listedCount();if(e.key===`ArrowDown`||e.key===`ArrowUp`){if(e.preventDefault(),r===0)return;this.selectedIndex=(this.selectedIndex+(e.key===`ArrowDown`?1:-1)+r)%r,this.markSelection()}else if(e.key===`Enter`){if(e.preventDefault(),e.repeat&&this.mode?.kind===`compare`)return;if(this.searchTimer!==null||this.status===`searching`){this.pickOnResults=!0,this.searchTimer!==null&&this.searchNow();return}this.pick(this.selectedIndex)}}};exports.MAX_LISTED_ROWS=R,exports.SYMBOL_SEARCH_DEBOUNCE_MS=I,exports.WidgetSymbolSearch=H;
2
- //# sourceMappingURL=WidgetSymbolSearch-BOgfBOV6.cjs.map
1
+ const e=require(`./widgetFeatures-DpBWfQ8D.cjs`),t=require(`./focusTrap-DrhhmG0V.cjs`),n=require(`./symbolCatalog-CXqRu23x.cjs`),r=require(`./i18n-fgAwciRT.cjs`);var i=20,a=1e3,o=new Set,s={stock:1,stocks:1,equity:1,share:1,shares:1,"cổ phiếu":1,株式:1,株:1,股票:1,주식:1,futures:2,future:2,derivative:2,derivatives:2,option:2,options:2,"phái sinh":2,先物:2,期货:2,期貨:2,선물:2,warrant:2,warrants:2,"covered warrant":2,"chứng quyền":2,index:3,indices:3,"chỉ số":3,指数:3,指數:3,지수:3,fund:3,funds:3,etf:3,etfs:3,"chứng chỉ quỹ":3,crypto:4,cryptocurrency:4,perpetual:4,perpetuals:4,perp:4,perps:4,"tiền mã hóa":4,"tiền mã hoá":4,"tiền điện tử":4,暗号資産:4,仮想通貨:4,加密货币:4,加密貨幣:4,数字货币:4,數字貨幣:4,虚拟货币:4,虛擬貨幣:4,암호화폐:4,가상자산:4,가상화폐:4,forex:5,fx:5,currency:5,"ngoại hối":5,為替:5,外国為替:5,外汇:5,外匯:5,외환:5,bond:5,bonds:5,"trái phiếu":5},c=1e3,l=new Map,u=/i\u0307|\u0131/g;function d(e){if(typeof e!=`string`)return``;let t=l.get(e);return t===void 0&&(t=e.trim().normalize(`NFC`).toLowerCase().replace(u,`i`),l.size>=c&&l.clear(),l.set(e,t)),t}function f(e){let t=d(e);return t?Object.prototype.hasOwnProperty.call(s,t)?s[t]:1+p(t)%5:0}function p(e){let t=2166136261;for(let n of e)t^=n.codePointAt(0),t=Math.imul(t,16777619)>>>0;return t}function m(e){let{ticker:t}=n.c(e),r=/[\p{L}\p{N}]/u.exec(t);return r?r[0].toUpperCase():``}function h(e,t){let r=n.i(t?.logo);if(!r||o.has(r))return _(e,t);let a=document.createElement(`img`);return a.className=`tcw-ss-badge`,a.alt=``,a.width=i,a.height=i,a.draggable=!1,a.setAttribute(`aria-hidden`,`true`),a.setAttribute(`loading`,`lazy`),a.setAttribute(`decoding`,`async`),a.setAttribute(`referrerpolicy`,`no-referrer`),a.addEventListener(`error`,()=>{g(r),a.replaceWith(_(e,t))},{once:!0}),a.src=r,a}function g(e){o.size>=a&&o.clear(),o.add(e)}function _(e,t){let n=document.createElement(`span`);return n.className=`tcw-ss-badge`,n.setAttribute(`aria-hidden`,`true`),n.dataset.kind=String(f(t?.type)),n.textContent=m(e),n}var v=180,y=150,b=50;function x(e){return{upper:e.toUpperCase(),folded:T(e)}}function S(e,t,n){return Math.max(C(e.toUpperCase(),n.upper),w(t,n.folded))}function C(e,t){if(e===t)return 1e3;if(e.startsWith(t))return 500+(50-Math.min(50,e.length-t.length));if(e.includes(t))return 200+(50-Math.min(50,e.length-t.length));let n=0,r=-1,i=0;for(let a=0;a<e.length&&n<t.length;a++)e[a]===t[n]&&(r>=0&&(i+=a-r-1),r=a,n++);return n<t.length?0:100-Math.min(99,i)}function w(e,t){if(!e||!t)return 0;if(e.startsWith(t))return v;let n=e.indexOf(t);return n<0?0:y-Math.min(b,n)}function T(e){return e.normalize(`NFD`).replace(/\p{M}+/gu,``).replace(/[đĐ]/g,`D`).toUpperCase()}function E(e,t,r=0,i=e.length){let a=t?D(e.toUpperCase(),t):new Set,o=``;for(let t=r;t<i;t++)o+=a.has(t)?`<mark>${n.u(e[t])}</mark>`:n.u(e[t]);return o}function D(e,t){let n=new Set,r=e.indexOf(t);if(r>=0){for(let e=r;e<r+t.length;e++)n.add(e);return n}let i=0;for(let r=0;r<e.length&&i<t.length;r++)e[r]===t[i]&&(n.add(r),i++);return i<t.length?new Set:n}function O(e,t){let r=document.createElement(`span`);r.className=`tcw-ss-symbol`,r.dir=`ltr`;let{venue:i}=n.c(e);i&&(r.title=e);let a=document.createElement(`span`);return a.className=`tcw-ss-ticker`,a.innerHTML=E(e,t,i.length,e.length),r.appendChild(a),r}function k(e){return n.c(e).venue.replace(/:$/,``).replace(/:/g,` `)}var A=d,j=2,M=1,N=class{el;kindsEl;exchangeEl;kinds=new Map;exchanges=new Map;kind=null;exchange=null;resize;constructor(e,t){this.t=e,this.onChange=t,this.el=document.createElement(`div`),this.el.className=`tcw-ss-filters`,this.el.hidden=!0,this.kindsEl=document.createElement(`div`),this.kindsEl.className=`tcw-ss-kinds`,this.kindsEl.setAttribute(`role`,`group`),this.kindsEl.setAttribute(`aria-label`,e(`symbolSearch.kinds`)),this.kindsEl.hidden=!0,this.kindsEl.addEventListener(`scroll`,()=>this.markMore(),{passive:!0}),this.resize=typeof ResizeObserver>`u`?null:new ResizeObserver(()=>this.markMore()),this.resize?.observe(this.kindsEl),this.exchangeEl=document.createElement(`select`),this.exchangeEl.className=`tcw-settings-select tcw-ss-exchange-filter`,this.exchangeEl.setAttribute(`aria-label`,e(`symbolSearch.exchange`)),this.exchangeEl.hidden=!0,this.exchangeEl.addEventListener(`change`,()=>{this.exchange=A(this.exchangeEl.value)||null,this.onChange(!1)}),this.el.append(this.kindsEl,this.exchangeEl)}see(e){let t=this.kinds.size,n=this.exchanges.size;for(let t of e)P(this.kinds,t?.type),P(this.exchanges,t?.exchange);this.exchanges.size!==n&&this.renderExchanges(),this.exchangeEl.hidden=this.exchanges.size<j,(this.kinds.size!==t||!this.exchangeEl.hidden&&this.kindsEl.childElementCount===0)&&this.renderKinds(),this.kindsEl.hidden=this.kinds.size===0&&this.exchangeEl.hidden,this.el.hidden=this.kindsEl.hidden&&this.exchangeEl.hidden,this.markMore()}destroy(){this.resize?.disconnect()}markMore(){let e=this.kindsEl,t=Math.abs(e.scrollLeft),n=e.scrollWidth-e.clientWidth,r=[t>M?`start`:``,t<n-M?`end`:``].filter(Boolean);r.length>0?e.dataset.more=r.join(` `):delete e.dataset.more}passes(e,t){return F(this.kind,A(e?.type),t)&&F(this.exchange,A(e?.exchange),t)}renderKinds(){let e=(e,t)=>{let n=document.createElement(`button`);return n.type=`button`,n.className=`tcw-ss-type`,n.textContent=t,e!==null&&(n.dir=`auto`),n.setAttribute(`aria-pressed`,String(this.kind===e)),n.addEventListener(`click`,()=>{this.kind=e;for(let e of this.kindsEl.children)e.setAttribute(`aria-pressed`,String(e===n));this.onChange(!0)}),n},t=[...this.kinds].map(([t,n])=>e(t,n));this.kindsEl.replaceChildren(e(null,this.t(`symbolSearch.allKinds`)),...t)}renderExchanges(){let e=(e,t)=>{let n=document.createElement(`option`);return n.value=e,n.textContent=t,e&&(n.dir=`auto`),n},t=[...this.exchanges.values()].map(t=>e(t,t));this.exchangeEl.replaceChildren(e(``,this.t(`symbolSearch.allExchanges`)),...t),this.exchangeEl.value=this.exchange===null?``:this.exchanges.get(this.exchange)??``}};function P(e,t){let n=A(t);n&&!e.has(n)&&e.set(n,t.trim())}function F(e,t,n){return e===null||t===e||n&&t===``}var I=150,L=229,R=200,z=1;function B(e){return e.info?.exchange?.trim()||k(e.symbol)}function V(e){let t=B(e);return t?{...e.info??{symbol:e.symbol},exchange:t}:e.info}var H=class{backdrop=null;input=null;list=null;results=null;live=null;columns=null;filters=null;mode=null;given=[];rows=[];rowsGiven=!1;shown=[];compared=[];way=``;selectedIndex=0;searchFn=null;searchTimer=null;searchAbort=null;status=`idle`;pickOnResults=!1;heard=new Map;givenInfo=new Map;foldedNames=new Map;returnFocus=null;uid=z++;constructor(e,t=()=>document.body,n=r.t){this.callbacks=e,this.host=t,this.t=n}open(e){this.begin({kind:`search`,start:e})}openCompare(e){this.compared=e.compared,this.way=e.ways.some(t=>t.id===e.way)?e.way:e.ways[0]?.id??``,this.begin({kind:`compare`,start:e})}setCompared(e){if(this.compared=e,this.mode?.kind!==`compare`||!this.results)return;let t=this.results.contains(document.activeElement);this.renderList(),t&&!this.results.contains(document.activeElement)&&this.input?.focus()}close(){if(!this.backdrop)return;this.cancelSearch(),this.pickOnResults=!1,this.searchFn=null,this.backdrop.remove(),this.backdrop=this.input=this.list=this.results=this.live=this.columns=null,this.filters?.destroy(),this.filters=null,this.mode=null,this.callbacks.onClose();let e=this.returnFocus;this.returnFocus=null,e?.isConnected&&e.focus()}isOpen(){return this.backdrop!==null}isComparing(){return this.mode?.kind===`compare`}destroy(){this.close()}begin(e){this.backdrop&&this.close(),this.returnFocus=document.activeElement instanceof HTMLElement?document.activeElement:null,this.mode=e,this.searchFn=e.start.search??null,this.status=`idle`,this.learnGiven(e),this.build(e);let t=e.kind===`search`?e.start.query??``:``;this.input&&(this.input.value=t),t?(this.filter(),this.searchFn&&this.searchNow()):this.listGiven(),this.input?.focus()}learnGiven(e){let t=n.o(e.start.symbols);this.given=t.names,this.givenInfo=t.info,this.foldedNames=new Map;let r=e.start.current,i=e.kind===`search`?e.start.currentInfo:null;if(i&&typeof i==`object`&&r){let{description:e,logo:t}=n.r(i,r);this.givenInfo.set(r,n.a({symbol:r,description:e,logo:t},this.givenInfo.get(r)))}}infoOf(e){return n.a(this.givenInfo.get(e),this.heard.get(e))}build(t){let n=document.createElement(`div`);n.className=`tcw-modal-backdrop`;let r=!1;n.addEventListener(`pointerdown`,e=>{r=e.target===n}),n.addEventListener(`click`,e=>{e.target===n&&r&&this.close(),r=!1});let i=document.createElement(`div`);i.className=`tcw-modal tcw-ss${t.kind===`compare`?` tcw-ss--compare`:``}`,e.o(i,t.kind===`compare`?`compare`:`symbolSearch`),i.setAttribute(`role`,`dialog`),i.setAttribute(`aria-modal`,`true`),i.setAttribute(`aria-labelledby`,`tcw-ss-title-${this.uid}`),i.tabIndex=-1,i.addEventListener(`keydown`,e=>this.onKeyDown(e,i)),i.append(this.buildHeader(t),this.buildSearch()),t.kind===`compare`&&i.appendChild(this.buildWay(t.start));let a=new N(this.t,e=>{this.afterResults(!1),e&&this.input?.focus()}),o=document.createElement(`div`);o.className=`tcw-ss-list`,o.id=`tcw-ss-list-${this.uid}`,o.setAttribute(`role`,`listbox`);let s=document.createElement(`div`);s.className=`tcw-ss-results`;let c=this.buildColumns();s.append(c,o),s.addEventListener(`mousedown`,e=>{e.target.closest(`button`)||e.preventDefault()});let l=document.createElement(`div`);l.className=`tcw-ss-live tcw-visually-hidden`,l.setAttribute(`aria-live`,`polite`),i.append(a.el,s,l);let u=t.kind===`search`?t.start.hint:void 0;if(u){let e=document.createElement(`div`);e.className=`tcw-ss-foot`,e.textContent=u,i.appendChild(e)}n.appendChild(i),this.host().appendChild(n),this.backdrop=n,this.filters=a,this.columns=c,this.list=o,this.results=s,this.live=l}buildColumns(){let e=document.createElement(`div`);e.className=`tcw-ss-columns`,e.setAttribute(`aria-hidden`,`true`);let t=[``,this.t(`symbolSearch.symbol`),this.t(`symbolSearch.description`),this.t(`symbolSearch.type`),this.t(`symbolSearch.exchange`)];return e.append(...t.map(e=>this.tag(`tcw-ss-head`,e))),e}buildHeader(e){let n=document.createElement(`div`);n.className=`tcw-modal-header`;let r=document.createElement(`h3`);r.id=`tcw-ss-title-${this.uid}`,r.textContent=this.t(e.kind===`compare`?`compare.title`:`symbolSearch.title`);let i=document.createElement(`button`);return i.type=`button`,i.className=`tcw-modal-close`,i.setAttribute(`aria-label`,this.t(`common.close`)),i.innerHTML=t.i(`x`,16),i.addEventListener(`click`,()=>this.close()),n.append(r,i),n}buildSearch(){let e=document.createElement(`label`);e.className=`tcw-ss-search`,e.innerHTML=t.i(`search`,16);let n=document.createElement(`input`);return n.type=`search`,n.className=`tcw-ss-input`,n.placeholder=this.t(`symbolSearch.placeholder`),n.setAttribute(`aria-label`,this.t(`symbolSearch.placeholder`)),n.setAttribute(`role`,`combobox`),n.setAttribute(`aria-expanded`,`true`),n.setAttribute(`aria-controls`,`tcw-ss-list-${this.uid}`),n.setAttribute(`aria-autocomplete`,`list`),n.autocomplete=`off`,n.spellcheck=!1,n.addEventListener(`input`,()=>this.filter()),e.appendChild(n),this.input=n,e}buildWay(e){let t=document.createElement(`label`);t.className=`tcw-ss-way`;let n=document.createElement(`span`);n.textContent=this.t(`compare.addAs`);let r=document.createElement(`select`);r.className=`tcw-settings-select tcw-ss-way-select`;for(let t of e.ways){let e=document.createElement(`option`);e.value=t.id,e.textContent=t.label,r.appendChild(e)}return r.value=this.way,r.addEventListener(`change`,()=>{this.way=r.value}),t.append(n,r),t}listGiven(){this.rows=this.given.map(e=>({symbol:e,score:0,info:this.infoOf(e)})),this.rowsGiven=!0,this.afterResults(!0)}filter(){this.pickOnResults=!1;let e=this.input?.value.trim()??``;if(this.searchFn&&e){this.scheduleSearch(e);return}if(this.cancelSearch(),this.status=`idle`,!e){this.listGiven();return}let t=x(e);this.rows=this.given.map(e=>{let n=this.infoOf(e);return{symbol:e,score:S(e,this.foldedName(n?.description),t),info:n}}).filter(e=>e.score>0).sort((e,t)=>t.score-e.score),this.rowsGiven=!0,this.afterResults(!1)}foldedName(e){if(!e)return``;let t=this.foldedNames.get(e);return t===void 0&&(t=T(e),this.foldedNames.set(e,t)),t}scheduleSearch(e){this.searchTimer!==null&&clearTimeout(this.searchTimer),this.searchTimer=setTimeout(()=>{this.searchTimer=null,this.runSearch(e)},150)}searchNow(){this.searchTimer!==null&&clearTimeout(this.searchTimer),this.searchTimer=null,this.runSearch(this.input?.value.trim()??``)}async runSearch(e){let t=this.searchFn;if(!t)return;this.searchAbort?.abort();let r=new AbortController;this.searchAbort=r,this.status=`searching`,this.shown.length===0&&this.renderList();try{let i=await t(e,r.signal);if(r.signal.aborted)return;let a=n.s(i);for(let e of a)this.heard.set(e.symbol,n.a(this.heard.get(e.symbol),e));this.rows=a.map(e=>({symbol:e.symbol,score:0,info:this.infoOf(e.symbol)})),this.status=`idle`}catch{if(r.signal.aborted)return;this.rows=[],this.status=`failed`}this.rowsGiven=!1,this.afterResults(!1),this.pickOnResults&&(this.pickOnResults=!1,this.pick(0))}cancelSearch(){this.searchTimer!==null&&clearTimeout(this.searchTimer),this.searchTimer=null,this.searchAbort?.abort(),this.searchAbort=null}afterResults(e){let t=this.listableRows();this.filters?.see(t.map(V)),this.shown=this.visibleRows(t);let n=e?this.shown.findIndex(e=>e.symbol===this.mode?.start.current):-1;this.selectedIndex=n>=0&&n<this.listedCount()?n:0,this.renderList()}listedCount(){return Math.min(this.shown.length,200)}listableRows(){if(this.mode?.kind!==`compare`)return this.rows;let e=this.mode.start.current;return this.rows.filter(t=>t.symbol!==e)}visibleRows(e){let t=this.filters;return t?e.filter(e=>t.passes(V(e),this.rowsGiven)):[...e]}renderList(){let e=this.list,t=this.results;if(!e||!t)return;let n=(this.input?.value??``).trim(),r=this.mode?.kind===`compare`,i=[];if(r&&!n&&this.compared.length>0){let t=this.heading(this.t(`compare.onChart`),`added`),n=document.createElement(`div`);n.className=`tcw-ss-added`,n.setAttribute(`role`,`group`),n.setAttribute(`aria-labelledby`,t.id),n.append(...this.compared.map(e=>this.addedRow(e)));let r=this.heading(this.t(`compare.symbols`),`symbols`);r.hidden=this.shown.length===0,i.push(t,n,r),e.setAttribute(`aria-labelledby`,r.id)}else e.setAttribute(`aria-labelledby`,`tcw-ss-title-${this.uid}`);let a=n.toUpperCase(),o=new Set(this.compared.map(e=>e.symbol)),s=this.shown.slice(0,200);e.replaceChildren(...s.map((e,t)=>this.row(e,t,a,r&&o.has(e.symbol))));let c=this.shown.length===0?this.emptyNote(n,r):this.moreNote(this.shown.length-s.length);t.replaceChildren(...this.columns?[this.columns]:[],...i,e,...c?[c]:[]),this.live&&(this.live.textContent=this.shown.length===0?c?.textContent??``:``),this.markSelection()}emptyNote(e,t){let n;if(this.status===`searching`)n=this.t(`symbolSearch.searching`);else if(this.status===`failed`)n=this.t(`symbolSearch.failed`);else if(t&&!e){if(this.compared.length>0)return null;n=this.t(`compare.empty`)}else n=this.t(`symbolSearch.empty`);let r=document.createElement(`div`);return r.className=`tcw-ss-empty`,r.textContent=n,r}moreNote(e){if(e<=0)return null;let t=document.createElement(`div`);return t.className=`tcw-ss-more`,t.textContent=r.r(this.t(`symbolSearch.more`),{count:e}),t}heading(e,t){let n=document.createElement(`div`);return n.className=`tcw-ss-heading`,n.id=`tcw-ss-${t}-${this.uid}`,n.textContent=e,n}row(e,n,r,i){let a=document.createElement(`div`);a.className=`tcw-ss-row`,a.id=`tcw-ss-opt-${this.uid}-${n}`,a.dataset.symbol=e.symbol,a.setAttribute(`role`,`option`);let o=this.mode?.kind===`search`&&e.symbol===this.mode.start.current;a.classList.toggle(`tcw-current`,o),a.classList.toggle(`tcw-on-chart`,i),o&&a.setAttribute(`aria-current`,`true`);let s=this.tag(`tcw-ss-kind`,e.info?.type?.trim()??``),c=this.tag(`tcw-ss-exchange`,B(e));if(s.dir=c.dir=`auto`,a.append(h(e.symbol,e.info),O(e.symbol,r),this.descriptionCell(e),s,c),o||i){let e=document.createElement(`span`);e.className=`tcw-ss-check`,e.innerHTML=t.i(`check`,14),a.appendChild(e)}return i&&a.appendChild(this.tag(`tcw-visually-hidden`,this.t(`compare.onChart`))),a.addEventListener(`click`,()=>this.pick(n)),a.addEventListener(`mousemove`,()=>{this.selectedIndex!==n&&(this.selectedIndex=n,this.markSelection())}),a}descriptionCell(e){let t=document.createElement(`span`);t.className=`tcw-ss-desc-cell`;let n=e.info?.description&&e.info.description!==e.symbol?e.info.description:``;if(n){let e=this.tag(`tcw-ss-desc`,n);e.dir=`auto`,t.appendChild(e)}return t}addedRow(e){let n=document.createElement(`div`);if(n.className=`tcw-ss-added-row`,n.setAttribute(`role`,`presentation`),e.color){let t=document.createElement(`span`);t.className=`tcw-ss-swatch`,t.style.background=e.color,n.appendChild(t)}let i=document.createElement(`span`);i.className=`tcw-ss-way-cell`,i.appendChild(this.tag(`tcw-ss-way-label`,e.way));let a=document.createElement(`button`);a.type=`button`,a.className=`tcw-ss-remove`;let o=r.r(this.t(`compare.remove`),{symbol:e.symbol});return a.title=o,a.setAttribute(`aria-label`,o),a.innerHTML=t.i(`x`,12),a.addEventListener(`click`,()=>{this.mode?.kind===`compare`&&this.mode.start.onRemove(e.id)}),n.append(O(e.symbol,``),i,a),n}tag(e,t){let n=document.createElement(`span`);return n.className=e,n.textContent=t,n}markSelection(){let e=this.list?.querySelectorAll(`.tcw-ss-row`)??[],t=null;e.forEach((e,n)=>{let r=n===this.selectedIndex;e.setAttribute(`aria-selected`,String(r)),e.classList.toggle(`tcw-selected`,r),r&&(t=e)});let n=t;n?(this.input?.setAttribute(`aria-activedescendant`,n.id),n.scrollIntoView?.({block:`nearest`})):this.input?.removeAttribute(`aria-activedescendant`)}pick(e){let t=this.shown[e],n=this.mode;if(!t||!n)return;if(n.kind===`compare`){this.selectedIndex=e,this.markSelection(),n.start.onAdd(t.symbol,this.way);return}let r=n.start.onPick??this.callbacks.onPick;this.close(),r(t.symbol)}onKeyDown(e,n){if(e.stopPropagation(),e.isComposing||e.keyCode===L)return;if(e.key===`Escape`){e.preventDefault(),this.close();return}if(t.n(e,n),e.target!==this.input)return;let r=this.listedCount();if(e.key===`ArrowDown`||e.key===`ArrowUp`){if(e.preventDefault(),r===0)return;this.selectedIndex=(this.selectedIndex+(e.key===`ArrowDown`?1:-1)+r)%r,this.markSelection()}else if(e.key===`Enter`){if(e.preventDefault(),e.repeat&&this.mode?.kind===`compare`)return;if(this.searchTimer!==null||this.status===`searching`){this.pickOnResults=!0,this.searchTimer!==null&&this.searchNow();return}this.pick(this.selectedIndex)}}};exports.MAX_LISTED_ROWS=R,exports.SYMBOL_SEARCH_DEBOUNCE_MS=I,exports.WidgetSymbolSearch=H;
2
+ //# sourceMappingURL=WidgetSymbolSearch-C_yw9mLo.cjs.map