@tradecanvas/chart 1.76.0 → 1.78.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.
- package/README.md +7 -1
- package/dist/{LayoutSession-Di5_gC6i.cjs → LayoutSession-BzJQfrYw.cjs} +2 -2
- package/dist/{LayoutSession-Di5_gC6i.cjs.map → LayoutSession-BzJQfrYw.cjs.map} +1 -1
- package/dist/{LayoutSession-k8eo2c64.js → LayoutSession-CehL1zj4.js} +2 -2
- package/dist/{LayoutSession-k8eo2c64.js.map → LayoutSession-CehL1zj4.js.map} +1 -1
- package/dist/{WidgetCommandPalette-ZZNbWwCZ.cjs → WidgetCommandPalette-B1jaXJ-I.cjs} +2 -2
- package/dist/{WidgetCommandPalette-ZZNbWwCZ.cjs.map → WidgetCommandPalette-B1jaXJ-I.cjs.map} +1 -1
- package/dist/{WidgetCommandPalette-CeCLHPy1.js → WidgetCommandPalette-Bvr6Od3p.js} +2 -2
- package/dist/{WidgetCommandPalette-CeCLHPy1.js.map → WidgetCommandPalette-Bvr6Od3p.js.map} +1 -1
- package/dist/{WidgetDrawingSettings-B_mi8DUh.cjs → WidgetDrawingSettings-B8JKpke1.cjs} +2 -2
- package/dist/{WidgetDrawingSettings-B_mi8DUh.cjs.map → WidgetDrawingSettings-B8JKpke1.cjs.map} +1 -1
- package/dist/{WidgetDrawingSettings-CJsNm1Bf.js → WidgetDrawingSettings-CsR3GuFG.js} +2 -2
- package/dist/{WidgetDrawingSettings-CJsNm1Bf.js.map → WidgetDrawingSettings-CsR3GuFG.js.map} +1 -1
- package/dist/{WidgetIndicatorPicker-DuKJFPRC.cjs → WidgetIndicatorPicker-B72LdJy1.cjs} +2 -2
- package/dist/{WidgetIndicatorPicker-DuKJFPRC.cjs.map → WidgetIndicatorPicker-B72LdJy1.cjs.map} +1 -1
- package/dist/{WidgetIndicatorPicker-CGvZ5kYd.js → WidgetIndicatorPicker-Cb2m62oH.js} +2 -2
- package/dist/{WidgetIndicatorPicker-CGvZ5kYd.js.map → WidgetIndicatorPicker-Cb2m62oH.js.map} +1 -1
- package/dist/{WidgetIndicatorSettings-dDkqzzYo.js → WidgetIndicatorSettings-C4S0QgW-.js} +3 -3
- package/dist/{WidgetIndicatorSettings-dDkqzzYo.js.map → WidgetIndicatorSettings-C4S0QgW-.js.map} +1 -1
- package/dist/{WidgetIndicatorSettings-C7vpco6e.cjs → WidgetIndicatorSettings-C9fM5_KF.cjs} +2 -2
- package/dist/{WidgetIndicatorSettings-C7vpco6e.cjs.map → WidgetIndicatorSettings-C9fM5_KF.cjs.map} +1 -1
- package/dist/{WidgetSettings-C0fnWGdY.cjs → WidgetSettings-CL-sRVF2.cjs} +2 -2
- package/dist/{WidgetSettings-C0fnWGdY.cjs.map → WidgetSettings-CL-sRVF2.cjs.map} +1 -1
- package/dist/{WidgetSettings--XzDx515.js → WidgetSettings-D1xKl3Gl.js} +2 -2
- package/dist/{WidgetSettings--XzDx515.js.map → WidgetSettings-D1xKl3Gl.js.map} +1 -1
- package/dist/{WidgetSymbolSearch-C4OR42nZ.cjs → WidgetSymbolSearch-BFQsqzQD.cjs} +2 -2
- package/dist/{WidgetSymbolSearch-C4OR42nZ.cjs.map → WidgetSymbolSearch-BFQsqzQD.cjs.map} +1 -1
- package/dist/{WidgetSymbolSearch-CvPpjIwa.js → WidgetSymbolSearch-CrVAWg8Y.js} +2 -2
- package/dist/{WidgetSymbolSearch-CvPpjIwa.js.map → WidgetSymbolSearch-CrVAWg8Y.js.map} +1 -1
- package/dist/brand/poweredBy.d.ts +44 -0
- package/dist/brand/poweredBy.d.ts.map +1 -0
- package/dist/{i18n-C5v6Tzp1.js → i18n-Ci4pfuXw.js} +9 -1
- package/dist/i18n-Ci4pfuXw.js.map +1 -0
- package/dist/i18n-hMXCt55K.cjs +2 -0
- package/dist/i18n-hMXCt55K.cjs.map +1 -0
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +140 -104
- package/dist/index.js.map +1 -1
- package/dist/{indicatorInputWords-CTA4IcJR.cjs → indicatorInputWords-fiLxkWio.cjs} +2 -2
- package/dist/{indicatorInputWords-CTA4IcJR.cjs.map → indicatorInputWords-fiLxkWio.cjs.map} +1 -1
- package/dist/{indicatorInputWords-Bd9Pt6qp.js → indicatorInputWords-yN99aPYU.js} +2 -2
- package/dist/{indicatorInputWords-Bd9Pt6qp.js.map → indicatorInputWords-yN99aPYU.js.map} +1 -1
- package/dist/widget/WidgetWatchlist.d.ts +19 -3
- package/dist/widget/WidgetWatchlist.d.ts.map +1 -1
- package/dist/widget/WidgetWatchlists.d.ts.map +1 -1
- package/dist/widget/index.cjs +81 -32
- package/dist/widget/index.cjs.map +1 -1
- package/dist/widget/index.js +891 -848
- package/dist/widget/index.js.map +1 -1
- package/dist/widget/locales/ar.d.ts.map +1 -1
- package/dist/widget/locales/cs.d.ts.map +1 -1
- package/dist/widget/locales/da.d.ts.map +1 -1
- package/dist/widget/locales/de.d.ts.map +1 -1
- package/dist/widget/locales/el.d.ts.map +1 -1
- package/dist/widget/locales/en.d.ts +4 -0
- package/dist/widget/locales/en.d.ts.map +1 -1
- package/dist/widget/locales/es.d.ts.map +1 -1
- package/dist/widget/locales/et.d.ts.map +1 -1
- package/dist/widget/locales/fa.d.ts.map +1 -1
- package/dist/widget/locales/fr.d.ts.map +1 -1
- package/dist/widget/locales/he.d.ts.map +1 -1
- package/dist/widget/locales/hu.d.ts.map +1 -1
- package/dist/widget/locales/id.d.ts.map +1 -1
- package/dist/widget/locales/index.cjs +1 -1
- package/dist/widget/locales/index.cjs.map +1 -1
- package/dist/widget/locales/index.js +113 -1
- package/dist/widget/locales/index.js.map +1 -1
- package/dist/widget/locales/it.d.ts.map +1 -1
- package/dist/widget/locales/ja.d.ts.map +1 -1
- package/dist/widget/locales/ko.d.ts.map +1 -1
- package/dist/widget/locales/ms.d.ts.map +1 -1
- package/dist/widget/locales/nb.d.ts.map +1 -1
- package/dist/widget/locales/nl.d.ts.map +1 -1
- package/dist/widget/locales/pl.d.ts.map +1 -1
- package/dist/widget/locales/pt.d.ts.map +1 -1
- package/dist/widget/locales/ro.d.ts.map +1 -1
- package/dist/widget/locales/ru.d.ts.map +1 -1
- package/dist/widget/locales/sk.d.ts.map +1 -1
- package/dist/widget/locales/sv.d.ts.map +1 -1
- package/dist/widget/locales/th.d.ts.map +1 -1
- package/dist/widget/locales/tr.d.ts.map +1 -1
- package/dist/widget/locales/vi.d.ts.map +1 -1
- package/dist/widget/locales/zh.d.ts.map +1 -1
- package/dist/widget/locales/zhHant.d.ts.map +1 -1
- package/dist/widget/types.d.ts +9 -2
- package/dist/widget/types.d.ts.map +1 -1
- package/package.json +3 -3
- package/dist/i18n-C2nQBZTY.cjs +0 -2
- package/dist/i18n-C2nQBZTY.cjs.map +0 -1
- package/dist/i18n-C5v6Tzp1.js.map +0 -1
package/dist/{WidgetDrawingSettings-B_mi8DUh.cjs.map → WidgetDrawingSettings-B8JKpke1.cjs.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WidgetDrawingSettings-B_mi8DUh.cjs","names":[],"sources":["../src/widget/drawingSettingsTabs.ts","../src/widget/WidgetDrawingSettings.ts"],"sourcesContent":["import type { AnchorPoint, DrawingLevel, DrawingOptionDef, DrawingOptionDefs, DrawingOptions, DrawingStyle } from '@tradecanvas/commons';\nimport { ownFillColor } from '@tradecanvas/commons';\nimport { createIcon } from './icons.js';\nimport { fill, type MessageKey, type Translator } from './i18n.js';\nimport type { TextLayout } from './drawingText.js';\nimport { checkRow, colorAlpha, colorInput, numberInput, selectInput, settingsRow, toHex, withAlpha } from './settingsControls.js';\n\nexport type { TextLayout };\n\nconst LINE_WIDTHS = [1, 2, 3, 4];\nconst LINE_STYLES: DrawingStyle['lineStyle'][] = ['solid', 'dashed', 'dotted'];\n/**\n * The sizes offered for a drawing's text. Not 12: drawings saved with the old default\n * all carry it, so the chart reads it as no size of their own and draws its default.\n */\nconst FONT_SIZES = [10, 11, 13, 14, 16, 18, 20, 24, 28, 32];\n/** The size a text tool without a layout of its own draws at (a price label, an arrow's label). */\nconst DEFAULT_FONT_SIZE = 14;\n/** The old default every drawing was saved with: the chart draws its own default for it. */\nconst LEGACY_FONT_SIZE = 12;\n/** Most levels the editor offers to add, like the chart keeps. */\nconst MAX_LEVELS = 48;\n/** A new level sits this far past the last one. */\nconst LEVEL_STEP = 0.5;\n/** The fill's opacity a drawing without one starts from. */\nconst DEFAULT_FILL_ALPHA = 0.12;\n/** Options set in the line's own row, not listed with the tool's others. */\nconst END_KEYS = ['leftEnd', 'rightEnd'] as const;\n\n/** What the Style tab shows. */\nexport interface StyleTabModel {\n /** The style and the options as they are now (a row edits what the last edit left). */\n style: () => DrawingStyle;\n options: () => DrawingOptions;\n defs: DrawingOptionDefs;\n /** Whether the tool fills an area (the Fill row). */\n fill: boolean;\n}\n\n/** What the Style tab changes. */\nexport interface StyleTabActions {\n style(patch: Partial<DrawingStyle>): void;\n options(patch: DrawingOptions): void;\n /** Draw the tab again (a level added or removed), the keyboard on the first of `focus` there is. */\n redraw(focus?: readonly string[]): void;\n}\n\n/** Told the line's new colour: what takes it while it has none of its own (the fill, a level). */\ntype ColorFollower = (color: string) => void;\n\n/** A label from the widget's strings (`drawingOption.<key>`), else the tool's own. */\nfunction optionLabel(t: Translator, key: string, fallback: string): string {\n const messageKey = `drawingOption.${key}` as MessageKey;\n const text = t(messageKey);\n return text === messageKey ? fallback : text;\n}\n\nfunction section(): HTMLDivElement {\n const el = document.createElement('div');\n el.className = 'tcw-settings-section';\n return el;\n}\n\n/** A row of several controls after a label (a `<label>` would only reach the first). */\nfunction controlsRow(label: string, ...controls: HTMLElement[]): HTMLDivElement {\n const row = document.createElement('div');\n row.className = 'tcw-settings-row';\n const text = document.createElement('span');\n text.className = 'tcw-settings-label';\n text.textContent = label;\n const box = document.createElement('span');\n box.className = 'tcw-indi-plot-controls';\n box.append(...controls);\n row.append(text, box);\n return row;\n}\n\nfunction named<T extends HTMLElement>(el: T, label: string): T {\n el.setAttribute('aria-label', label);\n return el;\n}\n\n/**\n * The Style tab: the line (colour, width, dash), its ends, the fill, then\n * the tool's own switches and choices, and its levels last.\n */\nexport function renderStyleTab(body: HTMLElement, model: StyleTabModel, actions: StyleTabActions, t: Translator): void {\n const followers: ColorFollower[] = [];\n const look = section();\n look.appendChild(lineRow(model.style(), actions, followers, t));\n // A tool's ends only when they are the choice of plain or arrow; another option of that name is listed with the rest.\n const ends: string[] = END_KEYS.filter((key) => model.defs[key]?.kind === 'choice');\n if (ends.length > 0) {\n look.appendChild(controlsRow(t('drawingSettings.lineEnds'), ...ends.map((key) => named(selectInput(\n [{ value: 'normal', label: t('drawingSettings.lineEnd.normal') }, { value: 'arrow', label: t('drawingSettings.lineEnd.arrow') }],\n String(model.options()[key] ?? 'normal'),\n (v) => actions.options({ [key]: v }),\n ), optionLabel(t, key, model.defs[key].label)))));\n }\n if (model.fill) look.appendChild(fillRow(model.style(), actions, followers, t));\n body.appendChild(look);\n\n const rest = Object.entries(model.defs).filter(([key, def]) => def.kind !== 'levels' && !ends.includes(key));\n if (rest.length > 0) {\n const own = section();\n for (const [key, def] of rest) own.appendChild(optionRow(key, def as Exclude<DrawingOptionDef, { kind: 'levels' }>, model.options(), actions, t));\n body.appendChild(own);\n }\n for (const [key, def] of Object.entries(model.defs)) {\n if (def.kind === 'levels') body.appendChild(levelsEditor(key, def, model, actions, followers, t));\n }\n}\n\nfunction lineRow(style: DrawingStyle, actions: StyleTabActions, followers: readonly ColorFollower[], t: Translator): HTMLDivElement {\n const color = named(colorInput(style.color, (v) => {\n actions.style({ color: v });\n for (const follow of followers) follow(v);\n }), t('drawingSettings.color'));\n const width = named(selectInput(\n LINE_WIDTHS.map((w) => ({ value: String(w), label: `${w} px` })),\n String(style.lineWidth),\n (v) => actions.style({ lineWidth: Number(v) }),\n ), t('drawingSettings.lineWidth'));\n const dash = named(selectInput(\n LINE_STYLES.map((s) => ({ value: s, label: t(`drawingSettings.lineStyle.${s}`) })),\n style.lineStyle,\n (v) => actions.style({ lineStyle: v as DrawingStyle['lineStyle'] }),\n ), t('drawingSettings.lineStyle'));\n return controlsRow(t('drawingSettings.line'), color, width, dash);\n}\n\nfunction fillRow(style: DrawingStyle, actions: StyleTabActions, followers: ColorFollower[], t: Translator): HTMLDivElement {\n const current = ownFillColor(style) ?? withAlpha(style.color, DEFAULT_FILL_ALPHA);\n let hex = toHex(current);\n let alpha = colorAlpha(current);\n // Without a fill of its own the drawing fills in its line's colour, until one is set here.\n let own = ownFillColor(style) !== undefined;\n const apply = () => {\n own = true;\n actions.style({ fillColor: withAlpha(hex, alpha), fillOpacity: alpha });\n };\n const color = named(colorInput(hex, (v) => {\n hex = v;\n apply();\n }), t('drawingSettings.fill'));\n followers.push((line) => {\n if (own) return;\n hex = toHex(line);\n color.value = hex;\n });\n const opacity = named(numberInput(Math.round(alpha * 100), { min: 0, max: 100, step: 5 }, (v) => {\n alpha = v / 100;\n apply();\n }), t('drawingSettings.opacity'));\n const percent = document.createElement('span');\n percent.className = 'tcw-unit';\n percent.setAttribute('aria-hidden', 'true');\n percent.textContent = '%';\n return controlsRow(t('drawingSettings.fill'), color, opacity, percent);\n}\n\nfunction optionRow(\n key: string,\n def: Exclude<DrawingOptionDef, { kind: 'levels' }>,\n options: DrawingOptions,\n actions: StyleTabActions,\n t: Translator,\n): HTMLElement {\n const label = optionLabel(t, key, def.label);\n const value = options[key];\n switch (def.kind) {\n case 'boolean':\n return checkRow(label, Boolean(value), (v) => actions.options({ [key]: v }));\n case 'number':\n return settingsRow(label, numberInput(Number(value), { min: def.min, max: def.max, step: def.step }, (v) => actions.options({ [key]: v })));\n case 'choice':\n return settingsRow(label, selectInput(\n def.choices.map((c) => ({ value: c.value, label: optionLabel(t, `${key}.${c.value}`, c.label) })),\n String(value),\n (v) => actions.options({ [key]: v }),\n ));\n case 'text': {\n const input = document.createElement('input');\n input.type = 'text';\n input.className = 'tcw-indi-input';\n input.value = String(value ?? '');\n input.addEventListener('change', () => actions.options({ [key]: input.value }));\n return settingsRow(label, input);\n }\n }\n}\n\n/** One row per level: shown or not, its ratio, its colour, remove; and a button to add one. */\nfunction levelsEditor(\n key: string,\n def: Extract<DrawingOptionDef, { kind: 'levels' }>,\n model: StyleTabModel,\n actions: StyleTabActions,\n followers: ColorFollower[],\n t: Translator,\n): HTMLElement {\n const wrap = document.createElement('div');\n wrap.className = 'tcw-settings-section tcw-levels-editor';\n const head = document.createElement('div');\n head.className = 'tcw-settings-section-title';\n head.textContent = optionLabel(t, key, def.label);\n wrap.appendChild(head);\n\n const levels = (): DrawingLevel[] => {\n const value = model.options()[key];\n return Array.isArray(value) ? (value as DrawingLevel[]) : [];\n };\n const commit = (next: DrawingLevel[]) => actions.options({ [key]: next });\n const grid = document.createElement('div');\n grid.className = 'tcw-levels-grid';\n levels().forEach((level, index) => {\n const row = document.createElement('div');\n row.className = 'tcw-level-row';\n const nth = ` ${index + 1}`; // rows share labels; the number tells them apart\n const visible = document.createElement('input');\n visible.type = 'checkbox';\n visible.checked = level.visible;\n visible.setAttribute('aria-label', t('drawingSettings.levelVisible') + nth);\n visible.addEventListener('change', () => commit(levels().map((l, i) => (i === index ? { ...l, visible: visible.checked } : l))));\n const value = named(numberInput(level.value, { step: 0.001 }, (v) => commit(levels().map((l, i) => (i === index ? { ...l, value: v } : l)))), t('drawingSettings.levelValue') + nth);\n const color = named(colorInput(level.color ?? model.style().color, (v) => commit(levels().map((l, i) => (i === index ? { ...l, color: v } : l)))), t('drawingSettings.levelColor') + nth);\n // A level without a colour of its own is drawn in the line's.\n followers.push((line) => {\n if (levels()[index]?.color === undefined) color.value = toHex(line);\n });\n const remove = document.createElement('button');\n remove.type = 'button';\n remove.className = 'tcw-level-remove';\n remove.setAttribute('aria-label', t('drawingSettings.removeLevel') + nth);\n remove.innerHTML = createIcon('x', 12);\n remove.addEventListener('click', () => {\n commit(levels().filter((_, i) => i !== index));\n // The keyboard stays where it was: on the next level's remove button, else the last one's, else Add.\n actions.redraw([\n `.tcw-level-row:nth-child(${index + 1}) .tcw-level-remove`,\n '.tcw-level-row:last-child .tcw-level-remove',\n '.tcw-level-add',\n ]);\n });\n row.append(visible, value, color, remove);\n grid.appendChild(row);\n });\n wrap.appendChild(grid);\n\n const add = document.createElement('button');\n add.type = 'button';\n add.className = 'tcw-reset-link tcw-level-add';\n add.textContent = t('drawingSettings.addLevel');\n add.disabled = levels().length >= MAX_LEVELS;\n add.addEventListener('click', () => {\n const last = levels().at(-1)?.value ?? 0;\n commit([...levels(), { value: Math.round((last + LEVEL_STEP) * 1000) / 1000, visible: true }]);\n actions.redraw(['.tcw-level-row:last-child input[type=\"number\"]']);\n });\n wrap.appendChild(add);\n return wrap;\n}\n\n/** The width a text wraps at when wrapping is turned on and it has none of its own. */\nconst DEFAULT_WRAP = 240;\nconst MIN_WRAP = 40;\nconst MAX_WRAP = 4000;\nconst WRAP_STEP = 10;\nconst ALIGNS = ['left', 'center', 'right'] as const;\nconst VALIGNS = ['top', 'middle', 'bottom'] as const;\n\n/**\n * A box ticked or not inside a row of controls, its name written after it\n * unless the row already says it (`said`): a screen reader hears it either way.\n */\nfunction inlineCheck(label: string, value: boolean, onChange: (value: boolean) => void, said = false): HTMLLabelElement {\n const wrap = document.createElement('label');\n wrap.className = 'tcw-inline-check';\n const box = document.createElement('input');\n box.type = 'checkbox';\n box.checked = value;\n box.setAttribute('aria-label', label);\n box.addEventListener('change', () => onChange(box.checked));\n wrap.append(box);\n if (!said) {\n const text = document.createElement('span');\n text.textContent = label;\n wrap.append(text);\n }\n return wrap;\n}\n\n/**\n * The Text tab: what the drawing writes, its size, bold and italics, and its\n * colour; for a text box (`layout`), its alignment, background, border and\n * the width it wraps at; for a line's or a box's text (`place`), where it sits.\n */\nexport function renderTextTab(\n body: HTMLElement,\n style: DrawingStyle,\n onStyle: (patch: Partial<DrawingStyle>) => void,\n t: Translator,\n layout?: TextLayout,\n textColor?: string,\n place = false,\n): void {\n const block = section();\n const text = document.createElement('textarea');\n text.className = 'tcw-indi-input tcw-drawing-text';\n text.rows = 3;\n text.value = style.text ?? '';\n text.addEventListener('input', () => onStyle({ text: text.value }));\n const textRow = settingsRow(t('drawingSettings.text'), text);\n textRow.classList.add('tcw-text-row');\n block.appendChild(textRow);\n const size = named(selectInput(\n FONT_SIZES.map((s) => ({ value: String(s), label: `${s} px` })),\n String((style.fontSize !== LEGACY_FONT_SIZE ? style.fontSize : undefined) ?? layout?.fontSize ?? DEFAULT_FONT_SIZE),\n (v) => onStyle({ fontSize: Number(v) }),\n ), t('drawingSettings.fontSize'));\n block.appendChild(controlsRow(\n t('drawingSettings.fontSize'),\n size,\n inlineCheck(t('drawingSettings.bold'), style.bold === true, (on) => onStyle({ bold: on })),\n inlineCheck(t('drawingSettings.italic'), style.italic === true, (on) => onStyle({ italic: on })),\n ));\n block.appendChild(controlsRow(t('drawingSettings.textColor'), named(\n colorInput(style.textColor ?? textColor ?? style.color, (v) => onStyle({ textColor: v })),\n t('drawingSettings.textColor'),\n )));\n body.appendChild(block);\n if (layout) body.appendChild(textBoxSection(style, onStyle, t, layout));\n if (place) body.appendChild(textPlaceSection(style, onStyle, t));\n}\n\n/** Where a line's or a box's text sits: at an end or the middle, and above, on or under (at the top, middle or bottom). */\nfunction textPlaceSection(style: DrawingStyle, onStyle: (patch: Partial<DrawingStyle>) => void, t: Translator): HTMLElement {\n const place = section();\n place.appendChild(controlsRow(t('drawingSettings.align'), named(selectInput(\n ALIGNS.map((a) => ({ value: a, label: t(`drawingSettings.align.${a}`) })),\n style.textAlign ?? 'center',\n (v) => onStyle({ textAlign: v as DrawingStyle['textAlign'] }),\n ), t('drawingSettings.align'))));\n place.appendChild(controlsRow(t('drawingSettings.vAlign'), named(selectInput(\n VALIGNS.map((a) => ({ value: a, label: t(`drawingSettings.vAlign.${a}`) })),\n style.textVAlign ?? 'top',\n (v) => onStyle({ textVAlign: v as DrawingStyle['textVAlign'] }),\n ), t('drawingSettings.vAlign'))));\n return place;\n}\n\n/** A text box's rows: alignment, background, border, and the width it wraps at. */\nfunction textBoxSection(style: DrawingStyle, onStyle: (patch: Partial<DrawingStyle>) => void, t: Translator, layout: TextLayout): HTMLElement {\n const box = section();\n box.appendChild(controlsRow(t('drawingSettings.align'), named(selectInput(\n ALIGNS.map((a) => ({ value: a, label: t(`drawingSettings.align.${a}`) })),\n style.textAlign ?? 'left',\n (v) => onStyle({ textAlign: v as DrawingStyle['textAlign'] }),\n ), t('drawingSettings.align'))));\n\n const background = ownFillColor(style) ?? withAlpha(style.color, DEFAULT_FILL_ALPHA);\n box.appendChild(controlsRow(\n t('drawingSettings.background'),\n inlineCheck(t('drawingSettings.background'), style.textBackground ?? layout.box, (on) => onStyle({ textBackground: on }), true),\n named(colorInput(background, (v) => onStyle({ fillColor: withAlpha(v, colorAlpha(background)) })), t('drawingSettings.backgroundColor')),\n ));\n box.appendChild(controlsRow(\n t('drawingSettings.border'),\n inlineCheck(t('drawingSettings.border'), style.textBorder ?? layout.border, (on) => onStyle({ textBorder: on }), true),\n named(colorInput(style.borderColor ?? style.color, (v) => onStyle({ borderColor: v })), t('drawingSettings.borderColor')),\n ));\n\n // The width shows what wrapping on would use: the text's own, else the tool's, else a default.\n const own = style.textWrap ?? layout.wrap;\n let width = own > 0 ? own : layout.wrap > 0 ? layout.wrap : DEFAULT_WRAP;\n let wrapping = own > 0;\n const widthInput = named(numberInput(width, { min: MIN_WRAP, max: MAX_WRAP, step: WRAP_STEP }, (v) => {\n width = v;\n if (wrapping) onStyle({ textWrap: v });\n }), t('drawingSettings.wrapWidth'));\n // A width means something only while the text wraps.\n widthInput.disabled = !wrapping;\n box.appendChild(controlsRow(\n t('drawingSettings.wrap'),\n inlineCheck(t('drawingSettings.wrap'), wrapping, (on) => {\n wrapping = on;\n widthInput.disabled = !on;\n onStyle({ textWrap: on ? width : 0 });\n }, true),\n widthInput,\n ));\n return box;\n}\n\n/** What the Coordinates tab reads and changes. */\nexport interface CoordinatesTabActions {\n /** An anchor's time as the date and time fields show it (the chart's zone), and back. */\n toWallTime(time: number): { date: string; time: string };\n fromWallTime(date: string, time: string): number | null;\n /** A price on the market's grid. */\n roundPrice?(price: number): number;\n /** The market's smallest price step, for the price fields' arrows. */\n priceStep?(): number;\n move(index: number, patch: Partial<AnchorPoint>): void;\n}\n\n/** The Coordinates tab: a row per point, its price, date and time. */\nexport function renderCoordinatesTab(body: HTMLElement, anchors: readonly AnchorPoint[], actions: CoordinatesTabActions, t: Translator): void {\n const block = section();\n anchors.forEach((anchor, index) => {\n const point = fill(t('drawingSettings.point'), { n: index + 1 });\n const wall = actions.toWallTime(anchor.time);\n const date = document.createElement('input');\n date.type = 'date';\n date.className = 'tcw-indi-input';\n date.value = wall.date;\n const time = document.createElement('input');\n time.type = 'time';\n time.className = 'tcw-indi-input';\n time.value = wall.time;\n const onTime = () => {\n const at = actions.fromWallTime(date.value, time.value);\n if (at !== null) actions.move(index, { time: at });\n };\n date.addEventListener('change', onTime);\n time.addEventListener('change', onTime);\n const price = priceInput(anchor.price, actions, (p) => actions.move(index, { price: p }));\n const row = controlsRow(point,\n named(price, `${point}: ${t('drawingSettings.price')}`),\n named(date, `${point}: ${t('drawingSettings.date')}`),\n named(time, `${point}: ${t('drawingSettings.time')}`));\n row.classList.add('tcw-draw-point');\n block.appendChild(row);\n });\n body.appendChild(block);\n}\n\n/**\n * A price field on the market's grid. It shows the price rounded, and leaves\n * the point where it is until the field is edited.\n */\nfunction priceInput(price: number, actions: CoordinatesTabActions, onChange: (price: number) => void): HTMLInputElement {\n const round = actions.roundPrice ?? ((p: number) => p);\n const step = actions.priceStep?.();\n const input = numberInput(round(price), { step: step !== undefined && step > 0 ? step : 'any' }, (typed) => {\n const onGrid = round(typed);\n input.value = String(onGrid);\n onChange(onGrid);\n });\n return input;\n}\n","import type {\n AnchorPoint,\n DrawingOptionDefs,\n DrawingOptions,\n DrawingStyle,\n DrawingToolType,\n IndicatorIntervals,\n} from '@tradecanvas/commons';\nimport { sanitizeDrawingOptions } from '@tradecanvas/commons';\nimport { createIcon } from './icons.js';\nimport { keepTabInside } from './focusTrap.js';\nimport { EN_TRANSLATOR, fill, type Translator } from './i18n.js';\nimport { WidgetContextMenu, type ContextMenuEntry } from './WidgetContextMenu.js';\nimport type { DrawingStyleTemplate } from './DrawingTemplateStore.js';\nimport { renderCoordinatesTab, renderStyleTab, renderTextTab, type TextLayout } from './drawingSettingsTabs.js';\nimport { renderVisibilityTab } from './indicatorSettingsTabs.js';\n\n/** The drawing a settings dialog edits. */\nexport interface DrawingSettingsTarget {\n id: string;\n type: DrawingToolType;\n /** The tool's name in the widget's language. */\n name: string;\n style: DrawingStyle;\n /** Every option, defaults filled in. */\n options: DrawingOptions;\n defs: DrawingOptionDefs;\n anchors: AnchorPoint[];\n /** Whether the tool fills an area and draws text (the Fill row, the Text tab). */\n fill: boolean;\n text: boolean;\n /** How the tool lays its text out in a box (the Text tab's alignment, background, border and wrap rows); unset: font rows only. */\n textLayout?: TextLayout;\n /** The colour the tool writes in without one of its own, when it isn't the line's. */\n textColor?: string;\n /** It writes its text along a line or in a box: the Text tab offers where (`textAlign`, `textVAlign`). */\n textPlace?: boolean;\n /** False for a drawing kept to the screen: its points are places on the plot, not times and prices to edit. */\n coordinates?: boolean;\n /** The intervals it shows on; unset or null: all of them. */\n intervals?: IndicatorIntervals | null;\n}\n\nexport interface DrawingSettingsPatch {\n anchors?: AnchorPoint[];\n style?: Partial<DrawingStyle>;\n options?: DrawingOptions;\n /** Null: every interval. */\n intervals?: IndicatorIntervals | null;\n}\n\n/** A drawing's look as a template keeps it: its style, and its tool's options. */\nexport interface DrawingTemplateLook {\n type: DrawingToolType;\n style: Partial<DrawingStyle>;\n options: DrawingOptions;\n}\n\nexport interface DrawingSettingsCallbacks {\n /** The dialog opened on a drawing: edits until `onEnd` are one undo step. */\n onBegin: (id: string) => void;\n /** An edit, shown on the chart at once. */\n onChange: (id: string, patch: DrawingSettingsPatch) => void;\n /** OK keeps the edits; Cancel, Escape or the close button put the drawing back. */\n onEnd: (id: string, cancel: boolean) => void;\n /** An anchor's time as the date and time fields show it (the chart's zone), and back. */\n toWallTime: (time: number) => { date: string; time: string };\n fromWallTime: (date: string, time: string) => number | null;\n /** A price on the market's grid; the Coordinates tab shows and takes prices on it. */\n roundPrice?: (price: number) => number;\n /** The market's smallest price step, for the price fields' arrows. */\n priceStep?: () => number;\n /** Make these the options new drawings of the tool start with. */\n onSaveDefault?: (type: DrawingToolType, options: DrawingOptions) => void;\n /** Saved templates: listed and deleted in the Template menu, and \"Save as template…\" (which asks for a name). */\n templates?: {\n list: (type: DrawingToolType) => DrawingStyleTemplate[];\n save: (look: DrawingTemplateLook) => void;\n remove: (name: string, type?: DrawingToolType) => void;\n };\n}\n\ntype Tab = 'style' | 'text' | 'coordinates' | 'visibility';\n\n/** Most points the Coordinates tab lists. */\nconst MAX_COORDINATE_ROWS = 12;\n/** A saved template's entry in the Template menu, by its place in the list. */\nconst TEMPLATE_ID = 't:';\n\nlet nextDialogId = 1;\n\n/**\n * A drawing's settings, in tabs: Style (the line, its ends, the fill, the\n * tool's own switches and levels), Text, Coordinates (its points by price,\n * date and time) and Visibility (the intervals it shows on). Edits show on\n * the chart at once; OK keeps them as one undo step, Cancel puts it back.\n * The Template menu applies, saves and deletes templates, keeps the options\n * as the tool's default, or resets them.\n */\nexport class WidgetDrawingSettings {\n private backdrop: HTMLDivElement;\n private modal: HTMLDivElement;\n private titleEl: HTMLHeadingElement;\n private tabsEl: HTMLDivElement;\n private bodyEl: HTMLDivElement;\n private templateBtn: HTMLButtonElement;\n private menu: WidgetContextMenu | null = null;\n private tabButtons: HTMLButtonElement[] = [];\n private target: DrawingSettingsTarget | null = null;\n private style!: DrawingStyle;\n private options: DrawingOptions = {};\n private anchors: AnchorPoint[] = [];\n private intervals: IndicatorIntervals | null = null;\n private tab: Tab = 'style';\n private returnFocus: HTMLElement | null = null;\n private readonly uid = nextDialogId++;\n\n constructor(\n host: HTMLElement,\n private readonly callbacks: DrawingSettingsCallbacks,\n private readonly t: Translator = EN_TRANSLATOR,\n ) {\n this.backdrop = document.createElement('div');\n this.backdrop.className = 'tcw-modal-backdrop';\n this.backdrop.hidden = true;\n // A press that starts in the dialog (selecting text, say) and ends on the\n // backdrop doesn't close it.\n let pressedBackdrop = false;\n this.backdrop.addEventListener('pointerdown', (e) => {\n pressedBackdrop = e.target === this.backdrop;\n });\n this.backdrop.addEventListener('click', (e) => {\n if (e.target === this.backdrop && pressedBackdrop) this.close(true);\n pressedBackdrop = false;\n });\n\n this.modal = document.createElement('div');\n this.modal.className = 'tcw-modal tcw-modal-narrow tcw-drawing-settings';\n this.modal.setAttribute('role', 'dialog');\n this.modal.setAttribute('aria-modal', 'true');\n this.modal.setAttribute('aria-labelledby', `tcw-draw-title-${this.uid}`);\n this.modal.tabIndex = -1;\n this.modal.addEventListener('keydown', (e) => this.onKeyDown(e));\n\n const header = document.createElement('div');\n header.className = 'tcw-modal-header';\n this.titleEl = document.createElement('h3');\n this.titleEl.id = `tcw-draw-title-${this.uid}`;\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.close(true));\n header.append(this.titleEl, closeBtn);\n\n this.tabsEl = document.createElement('div');\n this.tabsEl.className = 'tcw-modal-tabs';\n this.tabsEl.setAttribute('role', 'tablist');\n this.tabsEl.addEventListener('keydown', (e) => this.onTabKey(e));\n\n this.bodyEl = document.createElement('div');\n this.bodyEl.className = 'tcw-modal-body';\n this.bodyEl.id = `tcw-draw-panel-${this.uid}`;\n this.bodyEl.setAttribute('role', 'tabpanel');\n\n this.templateBtn = this.footerButton('template', 'tcw-footer-menu', () => this.openTemplates());\n this.modal.append(header, this.tabsEl, this.bodyEl, this.buildFooter());\n this.backdrop.appendChild(this.modal);\n host.appendChild(this.backdrop);\n }\n\n /** Template on the left; Cancel and OK on the right. */\n private buildFooter(): HTMLDivElement {\n this.templateBtn.setAttribute('aria-haspopup', 'menu');\n this.templateBtn.setAttribute('aria-expanded', 'false');\n this.templateBtn.innerHTML = `<span></span>${createIcon('chevronDown', 12)}`;\n this.templateBtn.querySelector('span')!.textContent = this.t('settings.template');\n const end = document.createElement('div');\n end.className = 'tcw-footer-end';\n end.append(\n this.footerButton('cancel', 'tcw-footer-cancel', () => this.close(true), this.t('common.cancel')),\n this.footerButton('ok', 'tcw-done-btn', () => this.close(false), this.t('drawingSettings.ok')),\n );\n const footer = document.createElement('div');\n footer.className = 'tcw-modal-footer';\n footer.append(this.templateBtn, end);\n return footer;\n }\n\n /**\n * Open on `target`. With `tab: 'text'` it opens on the Text tab (a tool\n * that writes), the text selected so typing replaces it.\n */\n open(target: DrawingSettingsTarget, how: { tab?: 'text' } = {}): void {\n if (this.target) this.close(false);\n this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n this.target = target;\n this.style = { ...target.style };\n this.options = structuredClone(target.options);\n this.anchors = target.anchors.map((a) => ({ ...a }));\n this.intervals = target.intervals ?? null;\n this.titleEl.textContent = target.name;\n this.tab = how.tab === 'text' && target.text ? 'text' : 'style';\n this.callbacks.onBegin(target.id);\n try {\n this.renderTabs();\n this.renderBody();\n } catch (err) {\n // A drawing the dialog can't show: end the edit it began.\n this.target = null;\n this.callbacks.onEnd(target.id, true);\n throw err;\n }\n this.backdrop.hidden = false;\n const text = this.tab === 'text' ? this.bodyEl.querySelector<HTMLTextAreaElement>('textarea') : null;\n if (text) {\n text.focus();\n text.select();\n } else {\n (this.tabButtons[0] ?? this.modal).focus();\n }\n }\n\n /** Close the dialog, keeping the edits or (with `cancel`) putting the drawing back. */\n close(cancel: boolean): void {\n const target = this.target;\n if (!target) return;\n // A value typed but not yet committed still applies on OK.\n const active = document.activeElement;\n if (!cancel && (active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement) && this.modal.contains(active)) {\n active.dispatchEvent(new Event('change'));\n }\n this.target = null;\n this.menu?.close();\n this.backdrop.hidden = true;\n this.callbacks.onEnd(target.id, cancel);\n if (this.returnFocus?.isConnected) this.returnFocus.focus();\n this.returnFocus = null;\n }\n\n isOpen(): boolean {\n return this.target !== null;\n }\n\n /** The drawing being edited, if any. */\n editing(): string | null {\n return this.target?.id ?? null;\n }\n\n destroy(): void {\n this.close(true);\n this.menu?.destroy();\n this.backdrop.remove();\n }\n\n // --- Tabs ---\n\n private tabs(): Tab[] {\n const target = this.target;\n if (!target) return [];\n return [\n 'style',\n ...(target.text ? ['text' as const] : []),\n // A freehand stroke has hundreds of points: no table of them.\n ...(target.coordinates !== false && target.anchors.length <= MAX_COORDINATE_ROWS ? ['coordinates' as const] : []),\n 'visibility',\n ];\n }\n\n private renderTabs(): void {\n this.tabButtons = this.tabs().map((tab) => {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'tcw-modal-tab';\n btn.id = `tcw-draw-tab-${this.uid}-${tab}`;\n btn.setAttribute('role', 'tab');\n btn.setAttribute('aria-controls', this.bodyEl.id);\n btn.dataset.tab = tab;\n btn.textContent = this.t(`drawingSettings.tab.${tab}`);\n btn.addEventListener('click', () => this.selectTab(tab));\n return btn;\n });\n this.tabsEl.replaceChildren(...this.tabButtons);\n this.markTabs();\n }\n\n private markTabs(): void {\n for (const btn of this.tabButtons) {\n const selected = btn.dataset.tab === this.tab;\n btn.classList.toggle('tcw-active', selected);\n btn.setAttribute('aria-selected', String(selected));\n btn.tabIndex = selected ? 0 : -1;\n if (selected) this.bodyEl.setAttribute('aria-labelledby', btn.id);\n }\n }\n\n private selectTab(tab: Tab, focus = false): void {\n this.tab = tab;\n this.markTabs();\n this.renderBody();\n if (focus) this.tabButtons.find((b) => b.dataset.tab === tab)?.focus();\n }\n\n /** Arrow keys (the other way right to left), Home and End move between tabs. */\n private onTabKey(e: KeyboardEvent): void {\n const tabs = this.tabButtons.map((b) => b.dataset.tab as Tab);\n const at = tabs.indexOf(this.tab);\n const rtl = this.modal.closest('[dir]')?.getAttribute('dir') === 'rtl';\n const [forward, back] = rtl ? ['ArrowLeft', 'ArrowRight'] : ['ArrowRight', 'ArrowLeft'];\n const next = e.key === forward ? (at + 1) % tabs.length\n : e.key === back ? (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], true);\n }\n\n /** Escape cancels; Tab stays inside the dialog. */\n private onKeyDown(e: KeyboardEvent): void {\n if (e.key === 'Escape') {\n e.preventDefault();\n e.stopPropagation();\n this.close(true);\n return;\n }\n keepTabInside(e, this.modal);\n }\n\n private renderBody(): void {\n this.bodyEl.replaceChildren();\n const target = this.target;\n if (!target) return;\n switch (this.tab) {\n case 'text':\n renderTextTab(this.bodyEl, this.style, (patch) => this.setStyle(patch), this.t, target.textLayout, target.textColor, target.textPlace);\n break;\n case 'coordinates':\n renderCoordinatesTab(this.bodyEl, this.anchors, {\n toWallTime: this.callbacks.toWallTime,\n fromWallTime: this.callbacks.fromWallTime,\n roundPrice: this.callbacks.roundPrice,\n priceStep: this.callbacks.priceStep,\n move: (index, patch) => this.setAnchor(index, patch),\n }, this.t);\n break;\n case 'visibility':\n renderVisibilityTab(this.bodyEl, this.intervals, (next) => this.setIntervals(next), this.t);\n break;\n default:\n renderStyleTab(this.bodyEl, { style: () => this.style, options: () => this.options, defs: target.defs, fill: target.fill }, {\n style: (patch) => this.setStyle(patch),\n options: (patch) => this.setOptions(patch),\n redraw: (focus = []) => {\n this.renderBody();\n for (const selector of focus) {\n const el = this.bodyEl.querySelector<HTMLElement>(selector);\n if (el) {\n el.focus();\n break;\n }\n }\n },\n }, this.t);\n }\n }\n\n // --- Edits ---\n\n private change(patch: DrawingSettingsPatch): void {\n if (this.target) this.callbacks.onChange(this.target.id, patch);\n }\n\n private setStyle(style: Partial<DrawingStyle>): void {\n if (!this.target) return;\n this.style = { ...this.style, ...style };\n this.change({ style });\n }\n\n private setOptions(options: DrawingOptions): void {\n if (!this.target) return;\n this.options = { ...this.options, ...structuredClone(options) };\n this.change({ options });\n }\n\n private setAnchor(index: number, patch: Partial<AnchorPoint>): void {\n if (!this.target) return;\n this.anchors = this.anchors.map((a, i) => (i === index ? { ...a, ...patch } : a));\n this.change({ anchors: this.anchors.map((a) => ({ ...a })) });\n }\n\n private setIntervals(intervals: IndicatorIntervals | null): void {\n if (!this.target) return;\n this.intervals = intervals;\n this.change({ intervals });\n }\n\n // --- Template ---\n\n /** The Template menu: the saved templates (each removable), Save as template, Save as default, Reset to defaults. */\n private openTemplates(): void {\n const target = this.target;\n if (!target) return;\n if (this.menu?.isOpen()) {\n this.menu.close();\n return;\n }\n const store = this.callbacks.templates;\n const saved = store?.list(target.type) ?? [];\n const entries: ContextMenuEntry[] = [\n ...saved.map((template, i): ContextMenuEntry => ({\n id: `${TEMPLATE_ID}${i}`, label: template.name, icon: 'layers', remove: fill(this.t('templates.delete'), { name: template.name }),\n })),\n ...(saved.length > 0 ? ['separator' as const] : []),\n ...(store ? [{ id: 'save', label: this.t('settings.saveTemplate'), icon: 'save' }] : []),\n ...(this.callbacks.onSaveDefault ? [{ id: 'default', label: this.t('drawingSettings.saveDefault'), icon: 'pin' }] : []),\n { id: 'reset', label: this.t('settings.resetToDefaults'), icon: 'reset' },\n ];\n const savedAt = (id: string) => saved[Number(id.slice(TEMPLATE_ID.length))];\n this.menu ??= new WidgetContextMenu(this.modal, this.t('settings.template'));\n const at = this.templateBtn.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 === 'save') store?.save({ type: target.type, style: { ...this.style }, options: structuredClone(this.options) });\n else if (id === 'default') this.callbacks.onSaveDefault?.(target.type, structuredClone(this.options));\n else if (id === 'reset') this.resetOptions();\n else if (id.startsWith(TEMPLATE_ID)) this.applyTemplate(savedAt(id));\n }, this.templateBtn, (id) => {\n const template = savedAt(id);\n if (template) store?.remove(template.name, template.type);\n });\n }\n\n private applyTemplate(template: DrawingStyleTemplate | undefined): void {\n const target = this.target;\n if (!template || !target) return;\n if (Object.keys(template.style).length > 0) this.setStyle(template.style);\n // Templates come from storage: only options the tool takes apply.\n if (template.options) this.setOptions(sanitizeDrawingOptions(target.defs, template.options));\n this.renderBody();\n }\n\n /** The tool's options back to its defaults. */\n private resetOptions(): void {\n const target = this.target;\n if (!target) return;\n const defaults: DrawingOptions = {};\n for (const [key, def] of Object.entries(target.defs)) defaults[key] = structuredClone(def.default) as DrawingOptions[string];\n this.setOptions(defaults);\n this.renderBody();\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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WidgetDrawingSettings-B8JKpke1.cjs","names":[],"sources":["../src/widget/drawingSettingsTabs.ts","../src/widget/WidgetDrawingSettings.ts"],"sourcesContent":["import type { AnchorPoint, DrawingLevel, DrawingOptionDef, DrawingOptionDefs, DrawingOptions, DrawingStyle } from '@tradecanvas/commons';\nimport { ownFillColor } from '@tradecanvas/commons';\nimport { createIcon } from './icons.js';\nimport { fill, type MessageKey, type Translator } from './i18n.js';\nimport type { TextLayout } from './drawingText.js';\nimport { checkRow, colorAlpha, colorInput, numberInput, selectInput, settingsRow, toHex, withAlpha } from './settingsControls.js';\n\nexport type { TextLayout };\n\nconst LINE_WIDTHS = [1, 2, 3, 4];\nconst LINE_STYLES: DrawingStyle['lineStyle'][] = ['solid', 'dashed', 'dotted'];\n/**\n * The sizes offered for a drawing's text. Not 12: drawings saved with the old default\n * all carry it, so the chart reads it as no size of their own and draws its default.\n */\nconst FONT_SIZES = [10, 11, 13, 14, 16, 18, 20, 24, 28, 32];\n/** The size a text tool without a layout of its own draws at (a price label, an arrow's label). */\nconst DEFAULT_FONT_SIZE = 14;\n/** The old default every drawing was saved with: the chart draws its own default for it. */\nconst LEGACY_FONT_SIZE = 12;\n/** Most levels the editor offers to add, like the chart keeps. */\nconst MAX_LEVELS = 48;\n/** A new level sits this far past the last one. */\nconst LEVEL_STEP = 0.5;\n/** The fill's opacity a drawing without one starts from. */\nconst DEFAULT_FILL_ALPHA = 0.12;\n/** Options set in the line's own row, not listed with the tool's others. */\nconst END_KEYS = ['leftEnd', 'rightEnd'] as const;\n\n/** What the Style tab shows. */\nexport interface StyleTabModel {\n /** The style and the options as they are now (a row edits what the last edit left). */\n style: () => DrawingStyle;\n options: () => DrawingOptions;\n defs: DrawingOptionDefs;\n /** Whether the tool fills an area (the Fill row). */\n fill: boolean;\n}\n\n/** What the Style tab changes. */\nexport interface StyleTabActions {\n style(patch: Partial<DrawingStyle>): void;\n options(patch: DrawingOptions): void;\n /** Draw the tab again (a level added or removed), the keyboard on the first of `focus` there is. */\n redraw(focus?: readonly string[]): void;\n}\n\n/** Told the line's new colour: what takes it while it has none of its own (the fill, a level). */\ntype ColorFollower = (color: string) => void;\n\n/** A label from the widget's strings (`drawingOption.<key>`), else the tool's own. */\nfunction optionLabel(t: Translator, key: string, fallback: string): string {\n const messageKey = `drawingOption.${key}` as MessageKey;\n const text = t(messageKey);\n return text === messageKey ? fallback : text;\n}\n\nfunction section(): HTMLDivElement {\n const el = document.createElement('div');\n el.className = 'tcw-settings-section';\n return el;\n}\n\n/** A row of several controls after a label (a `<label>` would only reach the first). */\nfunction controlsRow(label: string, ...controls: HTMLElement[]): HTMLDivElement {\n const row = document.createElement('div');\n row.className = 'tcw-settings-row';\n const text = document.createElement('span');\n text.className = 'tcw-settings-label';\n text.textContent = label;\n const box = document.createElement('span');\n box.className = 'tcw-indi-plot-controls';\n box.append(...controls);\n row.append(text, box);\n return row;\n}\n\nfunction named<T extends HTMLElement>(el: T, label: string): T {\n el.setAttribute('aria-label', label);\n return el;\n}\n\n/**\n * The Style tab: the line (colour, width, dash), its ends, the fill, then\n * the tool's own switches and choices, and its levels last.\n */\nexport function renderStyleTab(body: HTMLElement, model: StyleTabModel, actions: StyleTabActions, t: Translator): void {\n const followers: ColorFollower[] = [];\n const look = section();\n look.appendChild(lineRow(model.style(), actions, followers, t));\n // A tool's ends only when they are the choice of plain or arrow; another option of that name is listed with the rest.\n const ends: string[] = END_KEYS.filter((key) => model.defs[key]?.kind === 'choice');\n if (ends.length > 0) {\n look.appendChild(controlsRow(t('drawingSettings.lineEnds'), ...ends.map((key) => named(selectInput(\n [{ value: 'normal', label: t('drawingSettings.lineEnd.normal') }, { value: 'arrow', label: t('drawingSettings.lineEnd.arrow') }],\n String(model.options()[key] ?? 'normal'),\n (v) => actions.options({ [key]: v }),\n ), optionLabel(t, key, model.defs[key].label)))));\n }\n if (model.fill) look.appendChild(fillRow(model.style(), actions, followers, t));\n body.appendChild(look);\n\n const rest = Object.entries(model.defs).filter(([key, def]) => def.kind !== 'levels' && !ends.includes(key));\n if (rest.length > 0) {\n const own = section();\n for (const [key, def] of rest) own.appendChild(optionRow(key, def as Exclude<DrawingOptionDef, { kind: 'levels' }>, model.options(), actions, t));\n body.appendChild(own);\n }\n for (const [key, def] of Object.entries(model.defs)) {\n if (def.kind === 'levels') body.appendChild(levelsEditor(key, def, model, actions, followers, t));\n }\n}\n\nfunction lineRow(style: DrawingStyle, actions: StyleTabActions, followers: readonly ColorFollower[], t: Translator): HTMLDivElement {\n const color = named(colorInput(style.color, (v) => {\n actions.style({ color: v });\n for (const follow of followers) follow(v);\n }), t('drawingSettings.color'));\n const width = named(selectInput(\n LINE_WIDTHS.map((w) => ({ value: String(w), label: `${w} px` })),\n String(style.lineWidth),\n (v) => actions.style({ lineWidth: Number(v) }),\n ), t('drawingSettings.lineWidth'));\n const dash = named(selectInput(\n LINE_STYLES.map((s) => ({ value: s, label: t(`drawingSettings.lineStyle.${s}`) })),\n style.lineStyle,\n (v) => actions.style({ lineStyle: v as DrawingStyle['lineStyle'] }),\n ), t('drawingSettings.lineStyle'));\n return controlsRow(t('drawingSettings.line'), color, width, dash);\n}\n\nfunction fillRow(style: DrawingStyle, actions: StyleTabActions, followers: ColorFollower[], t: Translator): HTMLDivElement {\n const current = ownFillColor(style) ?? withAlpha(style.color, DEFAULT_FILL_ALPHA);\n let hex = toHex(current);\n let alpha = colorAlpha(current);\n // Without a fill of its own the drawing fills in its line's colour, until one is set here.\n let own = ownFillColor(style) !== undefined;\n const apply = () => {\n own = true;\n actions.style({ fillColor: withAlpha(hex, alpha), fillOpacity: alpha });\n };\n const color = named(colorInput(hex, (v) => {\n hex = v;\n apply();\n }), t('drawingSettings.fill'));\n followers.push((line) => {\n if (own) return;\n hex = toHex(line);\n color.value = hex;\n });\n const opacity = named(numberInput(Math.round(alpha * 100), { min: 0, max: 100, step: 5 }, (v) => {\n alpha = v / 100;\n apply();\n }), t('drawingSettings.opacity'));\n const percent = document.createElement('span');\n percent.className = 'tcw-unit';\n percent.setAttribute('aria-hidden', 'true');\n percent.textContent = '%';\n return controlsRow(t('drawingSettings.fill'), color, opacity, percent);\n}\n\nfunction optionRow(\n key: string,\n def: Exclude<DrawingOptionDef, { kind: 'levels' }>,\n options: DrawingOptions,\n actions: StyleTabActions,\n t: Translator,\n): HTMLElement {\n const label = optionLabel(t, key, def.label);\n const value = options[key];\n switch (def.kind) {\n case 'boolean':\n return checkRow(label, Boolean(value), (v) => actions.options({ [key]: v }));\n case 'number':\n return settingsRow(label, numberInput(Number(value), { min: def.min, max: def.max, step: def.step }, (v) => actions.options({ [key]: v })));\n case 'choice':\n return settingsRow(label, selectInput(\n def.choices.map((c) => ({ value: c.value, label: optionLabel(t, `${key}.${c.value}`, c.label) })),\n String(value),\n (v) => actions.options({ [key]: v }),\n ));\n case 'text': {\n const input = document.createElement('input');\n input.type = 'text';\n input.className = 'tcw-indi-input';\n input.value = String(value ?? '');\n input.addEventListener('change', () => actions.options({ [key]: input.value }));\n return settingsRow(label, input);\n }\n }\n}\n\n/** One row per level: shown or not, its ratio, its colour, remove; and a button to add one. */\nfunction levelsEditor(\n key: string,\n def: Extract<DrawingOptionDef, { kind: 'levels' }>,\n model: StyleTabModel,\n actions: StyleTabActions,\n followers: ColorFollower[],\n t: Translator,\n): HTMLElement {\n const wrap = document.createElement('div');\n wrap.className = 'tcw-settings-section tcw-levels-editor';\n const head = document.createElement('div');\n head.className = 'tcw-settings-section-title';\n head.textContent = optionLabel(t, key, def.label);\n wrap.appendChild(head);\n\n const levels = (): DrawingLevel[] => {\n const value = model.options()[key];\n return Array.isArray(value) ? (value as DrawingLevel[]) : [];\n };\n const commit = (next: DrawingLevel[]) => actions.options({ [key]: next });\n const grid = document.createElement('div');\n grid.className = 'tcw-levels-grid';\n levels().forEach((level, index) => {\n const row = document.createElement('div');\n row.className = 'tcw-level-row';\n const nth = ` ${index + 1}`; // rows share labels; the number tells them apart\n const visible = document.createElement('input');\n visible.type = 'checkbox';\n visible.checked = level.visible;\n visible.setAttribute('aria-label', t('drawingSettings.levelVisible') + nth);\n visible.addEventListener('change', () => commit(levels().map((l, i) => (i === index ? { ...l, visible: visible.checked } : l))));\n const value = named(numberInput(level.value, { step: 0.001 }, (v) => commit(levels().map((l, i) => (i === index ? { ...l, value: v } : l)))), t('drawingSettings.levelValue') + nth);\n const color = named(colorInput(level.color ?? model.style().color, (v) => commit(levels().map((l, i) => (i === index ? { ...l, color: v } : l)))), t('drawingSettings.levelColor') + nth);\n // A level without a colour of its own is drawn in the line's.\n followers.push((line) => {\n if (levels()[index]?.color === undefined) color.value = toHex(line);\n });\n const remove = document.createElement('button');\n remove.type = 'button';\n remove.className = 'tcw-level-remove';\n remove.setAttribute('aria-label', t('drawingSettings.removeLevel') + nth);\n remove.innerHTML = createIcon('x', 12);\n remove.addEventListener('click', () => {\n commit(levels().filter((_, i) => i !== index));\n // The keyboard stays where it was: on the next level's remove button, else the last one's, else Add.\n actions.redraw([\n `.tcw-level-row:nth-child(${index + 1}) .tcw-level-remove`,\n '.tcw-level-row:last-child .tcw-level-remove',\n '.tcw-level-add',\n ]);\n });\n row.append(visible, value, color, remove);\n grid.appendChild(row);\n });\n wrap.appendChild(grid);\n\n const add = document.createElement('button');\n add.type = 'button';\n add.className = 'tcw-reset-link tcw-level-add';\n add.textContent = t('drawingSettings.addLevel');\n add.disabled = levels().length >= MAX_LEVELS;\n add.addEventListener('click', () => {\n const last = levels().at(-1)?.value ?? 0;\n commit([...levels(), { value: Math.round((last + LEVEL_STEP) * 1000) / 1000, visible: true }]);\n actions.redraw(['.tcw-level-row:last-child input[type=\"number\"]']);\n });\n wrap.appendChild(add);\n return wrap;\n}\n\n/** The width a text wraps at when wrapping is turned on and it has none of its own. */\nconst DEFAULT_WRAP = 240;\nconst MIN_WRAP = 40;\nconst MAX_WRAP = 4000;\nconst WRAP_STEP = 10;\nconst ALIGNS = ['left', 'center', 'right'] as const;\nconst VALIGNS = ['top', 'middle', 'bottom'] as const;\n\n/**\n * A box ticked or not inside a row of controls, its name written after it\n * unless the row already says it (`said`): a screen reader hears it either way.\n */\nfunction inlineCheck(label: string, value: boolean, onChange: (value: boolean) => void, said = false): HTMLLabelElement {\n const wrap = document.createElement('label');\n wrap.className = 'tcw-inline-check';\n const box = document.createElement('input');\n box.type = 'checkbox';\n box.checked = value;\n box.setAttribute('aria-label', label);\n box.addEventListener('change', () => onChange(box.checked));\n wrap.append(box);\n if (!said) {\n const text = document.createElement('span');\n text.textContent = label;\n wrap.append(text);\n }\n return wrap;\n}\n\n/**\n * The Text tab: what the drawing writes, its size, bold and italics, and its\n * colour; for a text box (`layout`), its alignment, background, border and\n * the width it wraps at; for a line's or a box's text (`place`), where it sits.\n */\nexport function renderTextTab(\n body: HTMLElement,\n style: DrawingStyle,\n onStyle: (patch: Partial<DrawingStyle>) => void,\n t: Translator,\n layout?: TextLayout,\n textColor?: string,\n place = false,\n): void {\n const block = section();\n const text = document.createElement('textarea');\n text.className = 'tcw-indi-input tcw-drawing-text';\n text.rows = 3;\n text.value = style.text ?? '';\n text.addEventListener('input', () => onStyle({ text: text.value }));\n const textRow = settingsRow(t('drawingSettings.text'), text);\n textRow.classList.add('tcw-text-row');\n block.appendChild(textRow);\n const size = named(selectInput(\n FONT_SIZES.map((s) => ({ value: String(s), label: `${s} px` })),\n String((style.fontSize !== LEGACY_FONT_SIZE ? style.fontSize : undefined) ?? layout?.fontSize ?? DEFAULT_FONT_SIZE),\n (v) => onStyle({ fontSize: Number(v) }),\n ), t('drawingSettings.fontSize'));\n block.appendChild(controlsRow(\n t('drawingSettings.fontSize'),\n size,\n inlineCheck(t('drawingSettings.bold'), style.bold === true, (on) => onStyle({ bold: on })),\n inlineCheck(t('drawingSettings.italic'), style.italic === true, (on) => onStyle({ italic: on })),\n ));\n block.appendChild(controlsRow(t('drawingSettings.textColor'), named(\n colorInput(style.textColor ?? textColor ?? style.color, (v) => onStyle({ textColor: v })),\n t('drawingSettings.textColor'),\n )));\n body.appendChild(block);\n if (layout) body.appendChild(textBoxSection(style, onStyle, t, layout));\n if (place) body.appendChild(textPlaceSection(style, onStyle, t));\n}\n\n/** Where a line's or a box's text sits: at an end or the middle, and above, on or under (at the top, middle or bottom). */\nfunction textPlaceSection(style: DrawingStyle, onStyle: (patch: Partial<DrawingStyle>) => void, t: Translator): HTMLElement {\n const place = section();\n place.appendChild(controlsRow(t('drawingSettings.align'), named(selectInput(\n ALIGNS.map((a) => ({ value: a, label: t(`drawingSettings.align.${a}`) })),\n style.textAlign ?? 'center',\n (v) => onStyle({ textAlign: v as DrawingStyle['textAlign'] }),\n ), t('drawingSettings.align'))));\n place.appendChild(controlsRow(t('drawingSettings.vAlign'), named(selectInput(\n VALIGNS.map((a) => ({ value: a, label: t(`drawingSettings.vAlign.${a}`) })),\n style.textVAlign ?? 'top',\n (v) => onStyle({ textVAlign: v as DrawingStyle['textVAlign'] }),\n ), t('drawingSettings.vAlign'))));\n return place;\n}\n\n/** A text box's rows: alignment, background, border, and the width it wraps at. */\nfunction textBoxSection(style: DrawingStyle, onStyle: (patch: Partial<DrawingStyle>) => void, t: Translator, layout: TextLayout): HTMLElement {\n const box = section();\n box.appendChild(controlsRow(t('drawingSettings.align'), named(selectInput(\n ALIGNS.map((a) => ({ value: a, label: t(`drawingSettings.align.${a}`) })),\n style.textAlign ?? 'left',\n (v) => onStyle({ textAlign: v as DrawingStyle['textAlign'] }),\n ), t('drawingSettings.align'))));\n\n const background = ownFillColor(style) ?? withAlpha(style.color, DEFAULT_FILL_ALPHA);\n box.appendChild(controlsRow(\n t('drawingSettings.background'),\n inlineCheck(t('drawingSettings.background'), style.textBackground ?? layout.box, (on) => onStyle({ textBackground: on }), true),\n named(colorInput(background, (v) => onStyle({ fillColor: withAlpha(v, colorAlpha(background)) })), t('drawingSettings.backgroundColor')),\n ));\n box.appendChild(controlsRow(\n t('drawingSettings.border'),\n inlineCheck(t('drawingSettings.border'), style.textBorder ?? layout.border, (on) => onStyle({ textBorder: on }), true),\n named(colorInput(style.borderColor ?? style.color, (v) => onStyle({ borderColor: v })), t('drawingSettings.borderColor')),\n ));\n\n // The width shows what wrapping on would use: the text's own, else the tool's, else a default.\n const own = style.textWrap ?? layout.wrap;\n let width = own > 0 ? own : layout.wrap > 0 ? layout.wrap : DEFAULT_WRAP;\n let wrapping = own > 0;\n const widthInput = named(numberInput(width, { min: MIN_WRAP, max: MAX_WRAP, step: WRAP_STEP }, (v) => {\n width = v;\n if (wrapping) onStyle({ textWrap: v });\n }), t('drawingSettings.wrapWidth'));\n // A width means something only while the text wraps.\n widthInput.disabled = !wrapping;\n box.appendChild(controlsRow(\n t('drawingSettings.wrap'),\n inlineCheck(t('drawingSettings.wrap'), wrapping, (on) => {\n wrapping = on;\n widthInput.disabled = !on;\n onStyle({ textWrap: on ? width : 0 });\n }, true),\n widthInput,\n ));\n return box;\n}\n\n/** What the Coordinates tab reads and changes. */\nexport interface CoordinatesTabActions {\n /** An anchor's time as the date and time fields show it (the chart's zone), and back. */\n toWallTime(time: number): { date: string; time: string };\n fromWallTime(date: string, time: string): number | null;\n /** A price on the market's grid. */\n roundPrice?(price: number): number;\n /** The market's smallest price step, for the price fields' arrows. */\n priceStep?(): number;\n move(index: number, patch: Partial<AnchorPoint>): void;\n}\n\n/** The Coordinates tab: a row per point, its price, date and time. */\nexport function renderCoordinatesTab(body: HTMLElement, anchors: readonly AnchorPoint[], actions: CoordinatesTabActions, t: Translator): void {\n const block = section();\n anchors.forEach((anchor, index) => {\n const point = fill(t('drawingSettings.point'), { n: index + 1 });\n const wall = actions.toWallTime(anchor.time);\n const date = document.createElement('input');\n date.type = 'date';\n date.className = 'tcw-indi-input';\n date.value = wall.date;\n const time = document.createElement('input');\n time.type = 'time';\n time.className = 'tcw-indi-input';\n time.value = wall.time;\n const onTime = () => {\n const at = actions.fromWallTime(date.value, time.value);\n if (at !== null) actions.move(index, { time: at });\n };\n date.addEventListener('change', onTime);\n time.addEventListener('change', onTime);\n const price = priceInput(anchor.price, actions, (p) => actions.move(index, { price: p }));\n const row = controlsRow(point,\n named(price, `${point}: ${t('drawingSettings.price')}`),\n named(date, `${point}: ${t('drawingSettings.date')}`),\n named(time, `${point}: ${t('drawingSettings.time')}`));\n row.classList.add('tcw-draw-point');\n block.appendChild(row);\n });\n body.appendChild(block);\n}\n\n/**\n * A price field on the market's grid. It shows the price rounded, and leaves\n * the point where it is until the field is edited.\n */\nfunction priceInput(price: number, actions: CoordinatesTabActions, onChange: (price: number) => void): HTMLInputElement {\n const round = actions.roundPrice ?? ((p: number) => p);\n const step = actions.priceStep?.();\n const input = numberInput(round(price), { step: step !== undefined && step > 0 ? step : 'any' }, (typed) => {\n const onGrid = round(typed);\n input.value = String(onGrid);\n onChange(onGrid);\n });\n return input;\n}\n","import type {\n AnchorPoint,\n DrawingOptionDefs,\n DrawingOptions,\n DrawingStyle,\n DrawingToolType,\n IndicatorIntervals,\n} from '@tradecanvas/commons';\nimport { sanitizeDrawingOptions } from '@tradecanvas/commons';\nimport { createIcon } from './icons.js';\nimport { keepTabInside } from './focusTrap.js';\nimport { EN_TRANSLATOR, fill, type Translator } from './i18n.js';\nimport { WidgetContextMenu, type ContextMenuEntry } from './WidgetContextMenu.js';\nimport type { DrawingStyleTemplate } from './DrawingTemplateStore.js';\nimport { renderCoordinatesTab, renderStyleTab, renderTextTab, type TextLayout } from './drawingSettingsTabs.js';\nimport { renderVisibilityTab } from './indicatorSettingsTabs.js';\n\n/** The drawing a settings dialog edits. */\nexport interface DrawingSettingsTarget {\n id: string;\n type: DrawingToolType;\n /** The tool's name in the widget's language. */\n name: string;\n style: DrawingStyle;\n /** Every option, defaults filled in. */\n options: DrawingOptions;\n defs: DrawingOptionDefs;\n anchors: AnchorPoint[];\n /** Whether the tool fills an area and draws text (the Fill row, the Text tab). */\n fill: boolean;\n text: boolean;\n /** How the tool lays its text out in a box (the Text tab's alignment, background, border and wrap rows); unset: font rows only. */\n textLayout?: TextLayout;\n /** The colour the tool writes in without one of its own, when it isn't the line's. */\n textColor?: string;\n /** It writes its text along a line or in a box: the Text tab offers where (`textAlign`, `textVAlign`). */\n textPlace?: boolean;\n /** False for a drawing kept to the screen: its points are places on the plot, not times and prices to edit. */\n coordinates?: boolean;\n /** The intervals it shows on; unset or null: all of them. */\n intervals?: IndicatorIntervals | null;\n}\n\nexport interface DrawingSettingsPatch {\n anchors?: AnchorPoint[];\n style?: Partial<DrawingStyle>;\n options?: DrawingOptions;\n /** Null: every interval. */\n intervals?: IndicatorIntervals | null;\n}\n\n/** A drawing's look as a template keeps it: its style, and its tool's options. */\nexport interface DrawingTemplateLook {\n type: DrawingToolType;\n style: Partial<DrawingStyle>;\n options: DrawingOptions;\n}\n\nexport interface DrawingSettingsCallbacks {\n /** The dialog opened on a drawing: edits until `onEnd` are one undo step. */\n onBegin: (id: string) => void;\n /** An edit, shown on the chart at once. */\n onChange: (id: string, patch: DrawingSettingsPatch) => void;\n /** OK keeps the edits; Cancel, Escape or the close button put the drawing back. */\n onEnd: (id: string, cancel: boolean) => void;\n /** An anchor's time as the date and time fields show it (the chart's zone), and back. */\n toWallTime: (time: number) => { date: string; time: string };\n fromWallTime: (date: string, time: string) => number | null;\n /** A price on the market's grid; the Coordinates tab shows and takes prices on it. */\n roundPrice?: (price: number) => number;\n /** The market's smallest price step, for the price fields' arrows. */\n priceStep?: () => number;\n /** Make these the options new drawings of the tool start with. */\n onSaveDefault?: (type: DrawingToolType, options: DrawingOptions) => void;\n /** Saved templates: listed and deleted in the Template menu, and \"Save as template…\" (which asks for a name). */\n templates?: {\n list: (type: DrawingToolType) => DrawingStyleTemplate[];\n save: (look: DrawingTemplateLook) => void;\n remove: (name: string, type?: DrawingToolType) => void;\n };\n}\n\ntype Tab = 'style' | 'text' | 'coordinates' | 'visibility';\n\n/** Most points the Coordinates tab lists. */\nconst MAX_COORDINATE_ROWS = 12;\n/** A saved template's entry in the Template menu, by its place in the list. */\nconst TEMPLATE_ID = 't:';\n\nlet nextDialogId = 1;\n\n/**\n * A drawing's settings, in tabs: Style (the line, its ends, the fill, the\n * tool's own switches and levels), Text, Coordinates (its points by price,\n * date and time) and Visibility (the intervals it shows on). Edits show on\n * the chart at once; OK keeps them as one undo step, Cancel puts it back.\n * The Template menu applies, saves and deletes templates, keeps the options\n * as the tool's default, or resets them.\n */\nexport class WidgetDrawingSettings {\n private backdrop: HTMLDivElement;\n private modal: HTMLDivElement;\n private titleEl: HTMLHeadingElement;\n private tabsEl: HTMLDivElement;\n private bodyEl: HTMLDivElement;\n private templateBtn: HTMLButtonElement;\n private menu: WidgetContextMenu | null = null;\n private tabButtons: HTMLButtonElement[] = [];\n private target: DrawingSettingsTarget | null = null;\n private style!: DrawingStyle;\n private options: DrawingOptions = {};\n private anchors: AnchorPoint[] = [];\n private intervals: IndicatorIntervals | null = null;\n private tab: Tab = 'style';\n private returnFocus: HTMLElement | null = null;\n private readonly uid = nextDialogId++;\n\n constructor(\n host: HTMLElement,\n private readonly callbacks: DrawingSettingsCallbacks,\n private readonly t: Translator = EN_TRANSLATOR,\n ) {\n this.backdrop = document.createElement('div');\n this.backdrop.className = 'tcw-modal-backdrop';\n this.backdrop.hidden = true;\n // A press that starts in the dialog (selecting text, say) and ends on the\n // backdrop doesn't close it.\n let pressedBackdrop = false;\n this.backdrop.addEventListener('pointerdown', (e) => {\n pressedBackdrop = e.target === this.backdrop;\n });\n this.backdrop.addEventListener('click', (e) => {\n if (e.target === this.backdrop && pressedBackdrop) this.close(true);\n pressedBackdrop = false;\n });\n\n this.modal = document.createElement('div');\n this.modal.className = 'tcw-modal tcw-modal-narrow tcw-drawing-settings';\n this.modal.setAttribute('role', 'dialog');\n this.modal.setAttribute('aria-modal', 'true');\n this.modal.setAttribute('aria-labelledby', `tcw-draw-title-${this.uid}`);\n this.modal.tabIndex = -1;\n this.modal.addEventListener('keydown', (e) => this.onKeyDown(e));\n\n const header = document.createElement('div');\n header.className = 'tcw-modal-header';\n this.titleEl = document.createElement('h3');\n this.titleEl.id = `tcw-draw-title-${this.uid}`;\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.close(true));\n header.append(this.titleEl, closeBtn);\n\n this.tabsEl = document.createElement('div');\n this.tabsEl.className = 'tcw-modal-tabs';\n this.tabsEl.setAttribute('role', 'tablist');\n this.tabsEl.addEventListener('keydown', (e) => this.onTabKey(e));\n\n this.bodyEl = document.createElement('div');\n this.bodyEl.className = 'tcw-modal-body';\n this.bodyEl.id = `tcw-draw-panel-${this.uid}`;\n this.bodyEl.setAttribute('role', 'tabpanel');\n\n this.templateBtn = this.footerButton('template', 'tcw-footer-menu', () => this.openTemplates());\n this.modal.append(header, this.tabsEl, this.bodyEl, this.buildFooter());\n this.backdrop.appendChild(this.modal);\n host.appendChild(this.backdrop);\n }\n\n /** Template on the left; Cancel and OK on the right. */\n private buildFooter(): HTMLDivElement {\n this.templateBtn.setAttribute('aria-haspopup', 'menu');\n this.templateBtn.setAttribute('aria-expanded', 'false');\n this.templateBtn.innerHTML = `<span></span>${createIcon('chevronDown', 12)}`;\n this.templateBtn.querySelector('span')!.textContent = this.t('settings.template');\n const end = document.createElement('div');\n end.className = 'tcw-footer-end';\n end.append(\n this.footerButton('cancel', 'tcw-footer-cancel', () => this.close(true), this.t('common.cancel')),\n this.footerButton('ok', 'tcw-done-btn', () => this.close(false), this.t('drawingSettings.ok')),\n );\n const footer = document.createElement('div');\n footer.className = 'tcw-modal-footer';\n footer.append(this.templateBtn, end);\n return footer;\n }\n\n /**\n * Open on `target`. With `tab: 'text'` it opens on the Text tab (a tool\n * that writes), the text selected so typing replaces it.\n */\n open(target: DrawingSettingsTarget, how: { tab?: 'text' } = {}): void {\n if (this.target) this.close(false);\n this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n this.target = target;\n this.style = { ...target.style };\n this.options = structuredClone(target.options);\n this.anchors = target.anchors.map((a) => ({ ...a }));\n this.intervals = target.intervals ?? null;\n this.titleEl.textContent = target.name;\n this.tab = how.tab === 'text' && target.text ? 'text' : 'style';\n this.callbacks.onBegin(target.id);\n try {\n this.renderTabs();\n this.renderBody();\n } catch (err) {\n // A drawing the dialog can't show: end the edit it began.\n this.target = null;\n this.callbacks.onEnd(target.id, true);\n throw err;\n }\n this.backdrop.hidden = false;\n const text = this.tab === 'text' ? this.bodyEl.querySelector<HTMLTextAreaElement>('textarea') : null;\n if (text) {\n text.focus();\n text.select();\n } else {\n (this.tabButtons[0] ?? this.modal).focus();\n }\n }\n\n /** Close the dialog, keeping the edits or (with `cancel`) putting the drawing back. */\n close(cancel: boolean): void {\n const target = this.target;\n if (!target) return;\n // A value typed but not yet committed still applies on OK.\n const active = document.activeElement;\n if (!cancel && (active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement) && this.modal.contains(active)) {\n active.dispatchEvent(new Event('change'));\n }\n this.target = null;\n this.menu?.close();\n this.backdrop.hidden = true;\n this.callbacks.onEnd(target.id, cancel);\n if (this.returnFocus?.isConnected) this.returnFocus.focus();\n this.returnFocus = null;\n }\n\n isOpen(): boolean {\n return this.target !== null;\n }\n\n /** The drawing being edited, if any. */\n editing(): string | null {\n return this.target?.id ?? null;\n }\n\n destroy(): void {\n this.close(true);\n this.menu?.destroy();\n this.backdrop.remove();\n }\n\n // --- Tabs ---\n\n private tabs(): Tab[] {\n const target = this.target;\n if (!target) return [];\n return [\n 'style',\n ...(target.text ? ['text' as const] : []),\n // A freehand stroke has hundreds of points: no table of them.\n ...(target.coordinates !== false && target.anchors.length <= MAX_COORDINATE_ROWS ? ['coordinates' as const] : []),\n 'visibility',\n ];\n }\n\n private renderTabs(): void {\n this.tabButtons = this.tabs().map((tab) => {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'tcw-modal-tab';\n btn.id = `tcw-draw-tab-${this.uid}-${tab}`;\n btn.setAttribute('role', 'tab');\n btn.setAttribute('aria-controls', this.bodyEl.id);\n btn.dataset.tab = tab;\n btn.textContent = this.t(`drawingSettings.tab.${tab}`);\n btn.addEventListener('click', () => this.selectTab(tab));\n return btn;\n });\n this.tabsEl.replaceChildren(...this.tabButtons);\n this.markTabs();\n }\n\n private markTabs(): void {\n for (const btn of this.tabButtons) {\n const selected = btn.dataset.tab === this.tab;\n btn.classList.toggle('tcw-active', selected);\n btn.setAttribute('aria-selected', String(selected));\n btn.tabIndex = selected ? 0 : -1;\n if (selected) this.bodyEl.setAttribute('aria-labelledby', btn.id);\n }\n }\n\n private selectTab(tab: Tab, focus = false): void {\n this.tab = tab;\n this.markTabs();\n this.renderBody();\n if (focus) this.tabButtons.find((b) => b.dataset.tab === tab)?.focus();\n }\n\n /** Arrow keys (the other way right to left), Home and End move between tabs. */\n private onTabKey(e: KeyboardEvent): void {\n const tabs = this.tabButtons.map((b) => b.dataset.tab as Tab);\n const at = tabs.indexOf(this.tab);\n const rtl = this.modal.closest('[dir]')?.getAttribute('dir') === 'rtl';\n const [forward, back] = rtl ? ['ArrowLeft', 'ArrowRight'] : ['ArrowRight', 'ArrowLeft'];\n const next = e.key === forward ? (at + 1) % tabs.length\n : e.key === back ? (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], true);\n }\n\n /** Escape cancels; Tab stays inside the dialog. */\n private onKeyDown(e: KeyboardEvent): void {\n if (e.key === 'Escape') {\n e.preventDefault();\n e.stopPropagation();\n this.close(true);\n return;\n }\n keepTabInside(e, this.modal);\n }\n\n private renderBody(): void {\n this.bodyEl.replaceChildren();\n const target = this.target;\n if (!target) return;\n switch (this.tab) {\n case 'text':\n renderTextTab(this.bodyEl, this.style, (patch) => this.setStyle(patch), this.t, target.textLayout, target.textColor, target.textPlace);\n break;\n case 'coordinates':\n renderCoordinatesTab(this.bodyEl, this.anchors, {\n toWallTime: this.callbacks.toWallTime,\n fromWallTime: this.callbacks.fromWallTime,\n roundPrice: this.callbacks.roundPrice,\n priceStep: this.callbacks.priceStep,\n move: (index, patch) => this.setAnchor(index, patch),\n }, this.t);\n break;\n case 'visibility':\n renderVisibilityTab(this.bodyEl, this.intervals, (next) => this.setIntervals(next), this.t);\n break;\n default:\n renderStyleTab(this.bodyEl, { style: () => this.style, options: () => this.options, defs: target.defs, fill: target.fill }, {\n style: (patch) => this.setStyle(patch),\n options: (patch) => this.setOptions(patch),\n redraw: (focus = []) => {\n this.renderBody();\n for (const selector of focus) {\n const el = this.bodyEl.querySelector<HTMLElement>(selector);\n if (el) {\n el.focus();\n break;\n }\n }\n },\n }, this.t);\n }\n }\n\n // --- Edits ---\n\n private change(patch: DrawingSettingsPatch): void {\n if (this.target) this.callbacks.onChange(this.target.id, patch);\n }\n\n private setStyle(style: Partial<DrawingStyle>): void {\n if (!this.target) return;\n this.style = { ...this.style, ...style };\n this.change({ style });\n }\n\n private setOptions(options: DrawingOptions): void {\n if (!this.target) return;\n this.options = { ...this.options, ...structuredClone(options) };\n this.change({ options });\n }\n\n private setAnchor(index: number, patch: Partial<AnchorPoint>): void {\n if (!this.target) return;\n this.anchors = this.anchors.map((a, i) => (i === index ? { ...a, ...patch } : a));\n this.change({ anchors: this.anchors.map((a) => ({ ...a })) });\n }\n\n private setIntervals(intervals: IndicatorIntervals | null): void {\n if (!this.target) return;\n this.intervals = intervals;\n this.change({ intervals });\n }\n\n // --- Template ---\n\n /** The Template menu: the saved templates (each removable), Save as template, Save as default, Reset to defaults. */\n private openTemplates(): void {\n const target = this.target;\n if (!target) return;\n if (this.menu?.isOpen()) {\n this.menu.close();\n return;\n }\n const store = this.callbacks.templates;\n const saved = store?.list(target.type) ?? [];\n const entries: ContextMenuEntry[] = [\n ...saved.map((template, i): ContextMenuEntry => ({\n id: `${TEMPLATE_ID}${i}`, label: template.name, icon: 'layers', remove: fill(this.t('templates.delete'), { name: template.name }),\n })),\n ...(saved.length > 0 ? ['separator' as const] : []),\n ...(store ? [{ id: 'save', label: this.t('settings.saveTemplate'), icon: 'save' }] : []),\n ...(this.callbacks.onSaveDefault ? [{ id: 'default', label: this.t('drawingSettings.saveDefault'), icon: 'pin' }] : []),\n { id: 'reset', label: this.t('settings.resetToDefaults'), icon: 'reset' },\n ];\n const savedAt = (id: string) => saved[Number(id.slice(TEMPLATE_ID.length))];\n this.menu ??= new WidgetContextMenu(this.modal, this.t('settings.template'));\n const at = this.templateBtn.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 === 'save') store?.save({ type: target.type, style: { ...this.style }, options: structuredClone(this.options) });\n else if (id === 'default') this.callbacks.onSaveDefault?.(target.type, structuredClone(this.options));\n else if (id === 'reset') this.resetOptions();\n else if (id.startsWith(TEMPLATE_ID)) this.applyTemplate(savedAt(id));\n }, this.templateBtn, (id) => {\n const template = savedAt(id);\n if (template) store?.remove(template.name, template.type);\n });\n }\n\n private applyTemplate(template: DrawingStyleTemplate | undefined): void {\n const target = this.target;\n if (!template || !target) return;\n if (Object.keys(template.style).length > 0) this.setStyle(template.style);\n // Templates come from storage: only options the tool takes apply.\n if (template.options) this.setOptions(sanitizeDrawingOptions(target.defs, template.options));\n this.renderBody();\n }\n\n /** The tool's options back to its defaults. */\n private resetOptions(): void {\n const target = this.target;\n if (!target) return;\n const defaults: DrawingOptions = {};\n for (const [key, def] of Object.entries(target.defs)) defaults[key] = structuredClone(def.default) as DrawingOptions[string];\n this.setOptions(defaults);\n this.renderBody();\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"],"mappings":"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"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { i as e, n as t } from "./focusTrap-Br9Zfje0.js";
|
|
2
2
|
import { d as n, f as r, i, l as a, n as o, o as s, r as c, s as l, t as u } from "./settingsControls-DIjzCFHI.js";
|
|
3
|
-
import { r as d, t as f } from "./i18n-
|
|
3
|
+
import { r as d, t as f } from "./i18n-Ci4pfuXw.js";
|
|
4
4
|
import { n as p } from "./indicatorSettingsTabs-XcgMdbLp.js";
|
|
5
5
|
import { ownFillColor as m, sanitizeDrawingOptions as h } from "@tradecanvas/commons";
|
|
6
6
|
//#region src/widget/drawingSettingsTabs.ts
|
|
@@ -470,4 +470,4 @@ var K = 12, q = "t:", J = 1, Y = class {
|
|
|
470
470
|
//#endregion
|
|
471
471
|
export { Y as WidgetDrawingSettings };
|
|
472
472
|
|
|
473
|
-
//# sourceMappingURL=WidgetDrawingSettings-
|
|
473
|
+
//# sourceMappingURL=WidgetDrawingSettings-CsR3GuFG.js.map
|
package/dist/{WidgetDrawingSettings-CJsNm1Bf.js.map → WidgetDrawingSettings-CsR3GuFG.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"WidgetDrawingSettings-CJsNm1Bf.js","names":[],"sources":["../src/widget/drawingSettingsTabs.ts","../src/widget/WidgetDrawingSettings.ts"],"sourcesContent":["import type { AnchorPoint, DrawingLevel, DrawingOptionDef, DrawingOptionDefs, DrawingOptions, DrawingStyle } from '@tradecanvas/commons';\nimport { ownFillColor } from '@tradecanvas/commons';\nimport { createIcon } from './icons.js';\nimport { fill, type MessageKey, type Translator } from './i18n.js';\nimport type { TextLayout } from './drawingText.js';\nimport { checkRow, colorAlpha, colorInput, numberInput, selectInput, settingsRow, toHex, withAlpha } from './settingsControls.js';\n\nexport type { TextLayout };\n\nconst LINE_WIDTHS = [1, 2, 3, 4];\nconst LINE_STYLES: DrawingStyle['lineStyle'][] = ['solid', 'dashed', 'dotted'];\n/**\n * The sizes offered for a drawing's text. Not 12: drawings saved with the old default\n * all carry it, so the chart reads it as no size of their own and draws its default.\n */\nconst FONT_SIZES = [10, 11, 13, 14, 16, 18, 20, 24, 28, 32];\n/** The size a text tool without a layout of its own draws at (a price label, an arrow's label). */\nconst DEFAULT_FONT_SIZE = 14;\n/** The old default every drawing was saved with: the chart draws its own default for it. */\nconst LEGACY_FONT_SIZE = 12;\n/** Most levels the editor offers to add, like the chart keeps. */\nconst MAX_LEVELS = 48;\n/** A new level sits this far past the last one. */\nconst LEVEL_STEP = 0.5;\n/** The fill's opacity a drawing without one starts from. */\nconst DEFAULT_FILL_ALPHA = 0.12;\n/** Options set in the line's own row, not listed with the tool's others. */\nconst END_KEYS = ['leftEnd', 'rightEnd'] as const;\n\n/** What the Style tab shows. */\nexport interface StyleTabModel {\n /** The style and the options as they are now (a row edits what the last edit left). */\n style: () => DrawingStyle;\n options: () => DrawingOptions;\n defs: DrawingOptionDefs;\n /** Whether the tool fills an area (the Fill row). */\n fill: boolean;\n}\n\n/** What the Style tab changes. */\nexport interface StyleTabActions {\n style(patch: Partial<DrawingStyle>): void;\n options(patch: DrawingOptions): void;\n /** Draw the tab again (a level added or removed), the keyboard on the first of `focus` there is. */\n redraw(focus?: readonly string[]): void;\n}\n\n/** Told the line's new colour: what takes it while it has none of its own (the fill, a level). */\ntype ColorFollower = (color: string) => void;\n\n/** A label from the widget's strings (`drawingOption.<key>`), else the tool's own. */\nfunction optionLabel(t: Translator, key: string, fallback: string): string {\n const messageKey = `drawingOption.${key}` as MessageKey;\n const text = t(messageKey);\n return text === messageKey ? fallback : text;\n}\n\nfunction section(): HTMLDivElement {\n const el = document.createElement('div');\n el.className = 'tcw-settings-section';\n return el;\n}\n\n/** A row of several controls after a label (a `<label>` would only reach the first). */\nfunction controlsRow(label: string, ...controls: HTMLElement[]): HTMLDivElement {\n const row = document.createElement('div');\n row.className = 'tcw-settings-row';\n const text = document.createElement('span');\n text.className = 'tcw-settings-label';\n text.textContent = label;\n const box = document.createElement('span');\n box.className = 'tcw-indi-plot-controls';\n box.append(...controls);\n row.append(text, box);\n return row;\n}\n\nfunction named<T extends HTMLElement>(el: T, label: string): T {\n el.setAttribute('aria-label', label);\n return el;\n}\n\n/**\n * The Style tab: the line (colour, width, dash), its ends, the fill, then\n * the tool's own switches and choices, and its levels last.\n */\nexport function renderStyleTab(body: HTMLElement, model: StyleTabModel, actions: StyleTabActions, t: Translator): void {\n const followers: ColorFollower[] = [];\n const look = section();\n look.appendChild(lineRow(model.style(), actions, followers, t));\n // A tool's ends only when they are the choice of plain or arrow; another option of that name is listed with the rest.\n const ends: string[] = END_KEYS.filter((key) => model.defs[key]?.kind === 'choice');\n if (ends.length > 0) {\n look.appendChild(controlsRow(t('drawingSettings.lineEnds'), ...ends.map((key) => named(selectInput(\n [{ value: 'normal', label: t('drawingSettings.lineEnd.normal') }, { value: 'arrow', label: t('drawingSettings.lineEnd.arrow') }],\n String(model.options()[key] ?? 'normal'),\n (v) => actions.options({ [key]: v }),\n ), optionLabel(t, key, model.defs[key].label)))));\n }\n if (model.fill) look.appendChild(fillRow(model.style(), actions, followers, t));\n body.appendChild(look);\n\n const rest = Object.entries(model.defs).filter(([key, def]) => def.kind !== 'levels' && !ends.includes(key));\n if (rest.length > 0) {\n const own = section();\n for (const [key, def] of rest) own.appendChild(optionRow(key, def as Exclude<DrawingOptionDef, { kind: 'levels' }>, model.options(), actions, t));\n body.appendChild(own);\n }\n for (const [key, def] of Object.entries(model.defs)) {\n if (def.kind === 'levels') body.appendChild(levelsEditor(key, def, model, actions, followers, t));\n }\n}\n\nfunction lineRow(style: DrawingStyle, actions: StyleTabActions, followers: readonly ColorFollower[], t: Translator): HTMLDivElement {\n const color = named(colorInput(style.color, (v) => {\n actions.style({ color: v });\n for (const follow of followers) follow(v);\n }), t('drawingSettings.color'));\n const width = named(selectInput(\n LINE_WIDTHS.map((w) => ({ value: String(w), label: `${w} px` })),\n String(style.lineWidth),\n (v) => actions.style({ lineWidth: Number(v) }),\n ), t('drawingSettings.lineWidth'));\n const dash = named(selectInput(\n LINE_STYLES.map((s) => ({ value: s, label: t(`drawingSettings.lineStyle.${s}`) })),\n style.lineStyle,\n (v) => actions.style({ lineStyle: v as DrawingStyle['lineStyle'] }),\n ), t('drawingSettings.lineStyle'));\n return controlsRow(t('drawingSettings.line'), color, width, dash);\n}\n\nfunction fillRow(style: DrawingStyle, actions: StyleTabActions, followers: ColorFollower[], t: Translator): HTMLDivElement {\n const current = ownFillColor(style) ?? withAlpha(style.color, DEFAULT_FILL_ALPHA);\n let hex = toHex(current);\n let alpha = colorAlpha(current);\n // Without a fill of its own the drawing fills in its line's colour, until one is set here.\n let own = ownFillColor(style) !== undefined;\n const apply = () => {\n own = true;\n actions.style({ fillColor: withAlpha(hex, alpha), fillOpacity: alpha });\n };\n const color = named(colorInput(hex, (v) => {\n hex = v;\n apply();\n }), t('drawingSettings.fill'));\n followers.push((line) => {\n if (own) return;\n hex = toHex(line);\n color.value = hex;\n });\n const opacity = named(numberInput(Math.round(alpha * 100), { min: 0, max: 100, step: 5 }, (v) => {\n alpha = v / 100;\n apply();\n }), t('drawingSettings.opacity'));\n const percent = document.createElement('span');\n percent.className = 'tcw-unit';\n percent.setAttribute('aria-hidden', 'true');\n percent.textContent = '%';\n return controlsRow(t('drawingSettings.fill'), color, opacity, percent);\n}\n\nfunction optionRow(\n key: string,\n def: Exclude<DrawingOptionDef, { kind: 'levels' }>,\n options: DrawingOptions,\n actions: StyleTabActions,\n t: Translator,\n): HTMLElement {\n const label = optionLabel(t, key, def.label);\n const value = options[key];\n switch (def.kind) {\n case 'boolean':\n return checkRow(label, Boolean(value), (v) => actions.options({ [key]: v }));\n case 'number':\n return settingsRow(label, numberInput(Number(value), { min: def.min, max: def.max, step: def.step }, (v) => actions.options({ [key]: v })));\n case 'choice':\n return settingsRow(label, selectInput(\n def.choices.map((c) => ({ value: c.value, label: optionLabel(t, `${key}.${c.value}`, c.label) })),\n String(value),\n (v) => actions.options({ [key]: v }),\n ));\n case 'text': {\n const input = document.createElement('input');\n input.type = 'text';\n input.className = 'tcw-indi-input';\n input.value = String(value ?? '');\n input.addEventListener('change', () => actions.options({ [key]: input.value }));\n return settingsRow(label, input);\n }\n }\n}\n\n/** One row per level: shown or not, its ratio, its colour, remove; and a button to add one. */\nfunction levelsEditor(\n key: string,\n def: Extract<DrawingOptionDef, { kind: 'levels' }>,\n model: StyleTabModel,\n actions: StyleTabActions,\n followers: ColorFollower[],\n t: Translator,\n): HTMLElement {\n const wrap = document.createElement('div');\n wrap.className = 'tcw-settings-section tcw-levels-editor';\n const head = document.createElement('div');\n head.className = 'tcw-settings-section-title';\n head.textContent = optionLabel(t, key, def.label);\n wrap.appendChild(head);\n\n const levels = (): DrawingLevel[] => {\n const value = model.options()[key];\n return Array.isArray(value) ? (value as DrawingLevel[]) : [];\n };\n const commit = (next: DrawingLevel[]) => actions.options({ [key]: next });\n const grid = document.createElement('div');\n grid.className = 'tcw-levels-grid';\n levels().forEach((level, index) => {\n const row = document.createElement('div');\n row.className = 'tcw-level-row';\n const nth = ` ${index + 1}`; // rows share labels; the number tells them apart\n const visible = document.createElement('input');\n visible.type = 'checkbox';\n visible.checked = level.visible;\n visible.setAttribute('aria-label', t('drawingSettings.levelVisible') + nth);\n visible.addEventListener('change', () => commit(levels().map((l, i) => (i === index ? { ...l, visible: visible.checked } : l))));\n const value = named(numberInput(level.value, { step: 0.001 }, (v) => commit(levels().map((l, i) => (i === index ? { ...l, value: v } : l)))), t('drawingSettings.levelValue') + nth);\n const color = named(colorInput(level.color ?? model.style().color, (v) => commit(levels().map((l, i) => (i === index ? { ...l, color: v } : l)))), t('drawingSettings.levelColor') + nth);\n // A level without a colour of its own is drawn in the line's.\n followers.push((line) => {\n if (levels()[index]?.color === undefined) color.value = toHex(line);\n });\n const remove = document.createElement('button');\n remove.type = 'button';\n remove.className = 'tcw-level-remove';\n remove.setAttribute('aria-label', t('drawingSettings.removeLevel') + nth);\n remove.innerHTML = createIcon('x', 12);\n remove.addEventListener('click', () => {\n commit(levels().filter((_, i) => i !== index));\n // The keyboard stays where it was: on the next level's remove button, else the last one's, else Add.\n actions.redraw([\n `.tcw-level-row:nth-child(${index + 1}) .tcw-level-remove`,\n '.tcw-level-row:last-child .tcw-level-remove',\n '.tcw-level-add',\n ]);\n });\n row.append(visible, value, color, remove);\n grid.appendChild(row);\n });\n wrap.appendChild(grid);\n\n const add = document.createElement('button');\n add.type = 'button';\n add.className = 'tcw-reset-link tcw-level-add';\n add.textContent = t('drawingSettings.addLevel');\n add.disabled = levels().length >= MAX_LEVELS;\n add.addEventListener('click', () => {\n const last = levels().at(-1)?.value ?? 0;\n commit([...levels(), { value: Math.round((last + LEVEL_STEP) * 1000) / 1000, visible: true }]);\n actions.redraw(['.tcw-level-row:last-child input[type=\"number\"]']);\n });\n wrap.appendChild(add);\n return wrap;\n}\n\n/** The width a text wraps at when wrapping is turned on and it has none of its own. */\nconst DEFAULT_WRAP = 240;\nconst MIN_WRAP = 40;\nconst MAX_WRAP = 4000;\nconst WRAP_STEP = 10;\nconst ALIGNS = ['left', 'center', 'right'] as const;\nconst VALIGNS = ['top', 'middle', 'bottom'] as const;\n\n/**\n * A box ticked or not inside a row of controls, its name written after it\n * unless the row already says it (`said`): a screen reader hears it either way.\n */\nfunction inlineCheck(label: string, value: boolean, onChange: (value: boolean) => void, said = false): HTMLLabelElement {\n const wrap = document.createElement('label');\n wrap.className = 'tcw-inline-check';\n const box = document.createElement('input');\n box.type = 'checkbox';\n box.checked = value;\n box.setAttribute('aria-label', label);\n box.addEventListener('change', () => onChange(box.checked));\n wrap.append(box);\n if (!said) {\n const text = document.createElement('span');\n text.textContent = label;\n wrap.append(text);\n }\n return wrap;\n}\n\n/**\n * The Text tab: what the drawing writes, its size, bold and italics, and its\n * colour; for a text box (`layout`), its alignment, background, border and\n * the width it wraps at; for a line's or a box's text (`place`), where it sits.\n */\nexport function renderTextTab(\n body: HTMLElement,\n style: DrawingStyle,\n onStyle: (patch: Partial<DrawingStyle>) => void,\n t: Translator,\n layout?: TextLayout,\n textColor?: string,\n place = false,\n): void {\n const block = section();\n const text = document.createElement('textarea');\n text.className = 'tcw-indi-input tcw-drawing-text';\n text.rows = 3;\n text.value = style.text ?? '';\n text.addEventListener('input', () => onStyle({ text: text.value }));\n const textRow = settingsRow(t('drawingSettings.text'), text);\n textRow.classList.add('tcw-text-row');\n block.appendChild(textRow);\n const size = named(selectInput(\n FONT_SIZES.map((s) => ({ value: String(s), label: `${s} px` })),\n String((style.fontSize !== LEGACY_FONT_SIZE ? style.fontSize : undefined) ?? layout?.fontSize ?? DEFAULT_FONT_SIZE),\n (v) => onStyle({ fontSize: Number(v) }),\n ), t('drawingSettings.fontSize'));\n block.appendChild(controlsRow(\n t('drawingSettings.fontSize'),\n size,\n inlineCheck(t('drawingSettings.bold'), style.bold === true, (on) => onStyle({ bold: on })),\n inlineCheck(t('drawingSettings.italic'), style.italic === true, (on) => onStyle({ italic: on })),\n ));\n block.appendChild(controlsRow(t('drawingSettings.textColor'), named(\n colorInput(style.textColor ?? textColor ?? style.color, (v) => onStyle({ textColor: v })),\n t('drawingSettings.textColor'),\n )));\n body.appendChild(block);\n if (layout) body.appendChild(textBoxSection(style, onStyle, t, layout));\n if (place) body.appendChild(textPlaceSection(style, onStyle, t));\n}\n\n/** Where a line's or a box's text sits: at an end or the middle, and above, on or under (at the top, middle or bottom). */\nfunction textPlaceSection(style: DrawingStyle, onStyle: (patch: Partial<DrawingStyle>) => void, t: Translator): HTMLElement {\n const place = section();\n place.appendChild(controlsRow(t('drawingSettings.align'), named(selectInput(\n ALIGNS.map((a) => ({ value: a, label: t(`drawingSettings.align.${a}`) })),\n style.textAlign ?? 'center',\n (v) => onStyle({ textAlign: v as DrawingStyle['textAlign'] }),\n ), t('drawingSettings.align'))));\n place.appendChild(controlsRow(t('drawingSettings.vAlign'), named(selectInput(\n VALIGNS.map((a) => ({ value: a, label: t(`drawingSettings.vAlign.${a}`) })),\n style.textVAlign ?? 'top',\n (v) => onStyle({ textVAlign: v as DrawingStyle['textVAlign'] }),\n ), t('drawingSettings.vAlign'))));\n return place;\n}\n\n/** A text box's rows: alignment, background, border, and the width it wraps at. */\nfunction textBoxSection(style: DrawingStyle, onStyle: (patch: Partial<DrawingStyle>) => void, t: Translator, layout: TextLayout): HTMLElement {\n const box = section();\n box.appendChild(controlsRow(t('drawingSettings.align'), named(selectInput(\n ALIGNS.map((a) => ({ value: a, label: t(`drawingSettings.align.${a}`) })),\n style.textAlign ?? 'left',\n (v) => onStyle({ textAlign: v as DrawingStyle['textAlign'] }),\n ), t('drawingSettings.align'))));\n\n const background = ownFillColor(style) ?? withAlpha(style.color, DEFAULT_FILL_ALPHA);\n box.appendChild(controlsRow(\n t('drawingSettings.background'),\n inlineCheck(t('drawingSettings.background'), style.textBackground ?? layout.box, (on) => onStyle({ textBackground: on }), true),\n named(colorInput(background, (v) => onStyle({ fillColor: withAlpha(v, colorAlpha(background)) })), t('drawingSettings.backgroundColor')),\n ));\n box.appendChild(controlsRow(\n t('drawingSettings.border'),\n inlineCheck(t('drawingSettings.border'), style.textBorder ?? layout.border, (on) => onStyle({ textBorder: on }), true),\n named(colorInput(style.borderColor ?? style.color, (v) => onStyle({ borderColor: v })), t('drawingSettings.borderColor')),\n ));\n\n // The width shows what wrapping on would use: the text's own, else the tool's, else a default.\n const own = style.textWrap ?? layout.wrap;\n let width = own > 0 ? own : layout.wrap > 0 ? layout.wrap : DEFAULT_WRAP;\n let wrapping = own > 0;\n const widthInput = named(numberInput(width, { min: MIN_WRAP, max: MAX_WRAP, step: WRAP_STEP }, (v) => {\n width = v;\n if (wrapping) onStyle({ textWrap: v });\n }), t('drawingSettings.wrapWidth'));\n // A width means something only while the text wraps.\n widthInput.disabled = !wrapping;\n box.appendChild(controlsRow(\n t('drawingSettings.wrap'),\n inlineCheck(t('drawingSettings.wrap'), wrapping, (on) => {\n wrapping = on;\n widthInput.disabled = !on;\n onStyle({ textWrap: on ? width : 0 });\n }, true),\n widthInput,\n ));\n return box;\n}\n\n/** What the Coordinates tab reads and changes. */\nexport interface CoordinatesTabActions {\n /** An anchor's time as the date and time fields show it (the chart's zone), and back. */\n toWallTime(time: number): { date: string; time: string };\n fromWallTime(date: string, time: string): number | null;\n /** A price on the market's grid. */\n roundPrice?(price: number): number;\n /** The market's smallest price step, for the price fields' arrows. */\n priceStep?(): number;\n move(index: number, patch: Partial<AnchorPoint>): void;\n}\n\n/** The Coordinates tab: a row per point, its price, date and time. */\nexport function renderCoordinatesTab(body: HTMLElement, anchors: readonly AnchorPoint[], actions: CoordinatesTabActions, t: Translator): void {\n const block = section();\n anchors.forEach((anchor, index) => {\n const point = fill(t('drawingSettings.point'), { n: index + 1 });\n const wall = actions.toWallTime(anchor.time);\n const date = document.createElement('input');\n date.type = 'date';\n date.className = 'tcw-indi-input';\n date.value = wall.date;\n const time = document.createElement('input');\n time.type = 'time';\n time.className = 'tcw-indi-input';\n time.value = wall.time;\n const onTime = () => {\n const at = actions.fromWallTime(date.value, time.value);\n if (at !== null) actions.move(index, { time: at });\n };\n date.addEventListener('change', onTime);\n time.addEventListener('change', onTime);\n const price = priceInput(anchor.price, actions, (p) => actions.move(index, { price: p }));\n const row = controlsRow(point,\n named(price, `${point}: ${t('drawingSettings.price')}`),\n named(date, `${point}: ${t('drawingSettings.date')}`),\n named(time, `${point}: ${t('drawingSettings.time')}`));\n row.classList.add('tcw-draw-point');\n block.appendChild(row);\n });\n body.appendChild(block);\n}\n\n/**\n * A price field on the market's grid. It shows the price rounded, and leaves\n * the point where it is until the field is edited.\n */\nfunction priceInput(price: number, actions: CoordinatesTabActions, onChange: (price: number) => void): HTMLInputElement {\n const round = actions.roundPrice ?? ((p: number) => p);\n const step = actions.priceStep?.();\n const input = numberInput(round(price), { step: step !== undefined && step > 0 ? step : 'any' }, (typed) => {\n const onGrid = round(typed);\n input.value = String(onGrid);\n onChange(onGrid);\n });\n return input;\n}\n","import type {\n AnchorPoint,\n DrawingOptionDefs,\n DrawingOptions,\n DrawingStyle,\n DrawingToolType,\n IndicatorIntervals,\n} from '@tradecanvas/commons';\nimport { sanitizeDrawingOptions } from '@tradecanvas/commons';\nimport { createIcon } from './icons.js';\nimport { keepTabInside } from './focusTrap.js';\nimport { EN_TRANSLATOR, fill, type Translator } from './i18n.js';\nimport { WidgetContextMenu, type ContextMenuEntry } from './WidgetContextMenu.js';\nimport type { DrawingStyleTemplate } from './DrawingTemplateStore.js';\nimport { renderCoordinatesTab, renderStyleTab, renderTextTab, type TextLayout } from './drawingSettingsTabs.js';\nimport { renderVisibilityTab } from './indicatorSettingsTabs.js';\n\n/** The drawing a settings dialog edits. */\nexport interface DrawingSettingsTarget {\n id: string;\n type: DrawingToolType;\n /** The tool's name in the widget's language. */\n name: string;\n style: DrawingStyle;\n /** Every option, defaults filled in. */\n options: DrawingOptions;\n defs: DrawingOptionDefs;\n anchors: AnchorPoint[];\n /** Whether the tool fills an area and draws text (the Fill row, the Text tab). */\n fill: boolean;\n text: boolean;\n /** How the tool lays its text out in a box (the Text tab's alignment, background, border and wrap rows); unset: font rows only. */\n textLayout?: TextLayout;\n /** The colour the tool writes in without one of its own, when it isn't the line's. */\n textColor?: string;\n /** It writes its text along a line or in a box: the Text tab offers where (`textAlign`, `textVAlign`). */\n textPlace?: boolean;\n /** False for a drawing kept to the screen: its points are places on the plot, not times and prices to edit. */\n coordinates?: boolean;\n /** The intervals it shows on; unset or null: all of them. */\n intervals?: IndicatorIntervals | null;\n}\n\nexport interface DrawingSettingsPatch {\n anchors?: AnchorPoint[];\n style?: Partial<DrawingStyle>;\n options?: DrawingOptions;\n /** Null: every interval. */\n intervals?: IndicatorIntervals | null;\n}\n\n/** A drawing's look as a template keeps it: its style, and its tool's options. */\nexport interface DrawingTemplateLook {\n type: DrawingToolType;\n style: Partial<DrawingStyle>;\n options: DrawingOptions;\n}\n\nexport interface DrawingSettingsCallbacks {\n /** The dialog opened on a drawing: edits until `onEnd` are one undo step. */\n onBegin: (id: string) => void;\n /** An edit, shown on the chart at once. */\n onChange: (id: string, patch: DrawingSettingsPatch) => void;\n /** OK keeps the edits; Cancel, Escape or the close button put the drawing back. */\n onEnd: (id: string, cancel: boolean) => void;\n /** An anchor's time as the date and time fields show it (the chart's zone), and back. */\n toWallTime: (time: number) => { date: string; time: string };\n fromWallTime: (date: string, time: string) => number | null;\n /** A price on the market's grid; the Coordinates tab shows and takes prices on it. */\n roundPrice?: (price: number) => number;\n /** The market's smallest price step, for the price fields' arrows. */\n priceStep?: () => number;\n /** Make these the options new drawings of the tool start with. */\n onSaveDefault?: (type: DrawingToolType, options: DrawingOptions) => void;\n /** Saved templates: listed and deleted in the Template menu, and \"Save as template…\" (which asks for a name). */\n templates?: {\n list: (type: DrawingToolType) => DrawingStyleTemplate[];\n save: (look: DrawingTemplateLook) => void;\n remove: (name: string, type?: DrawingToolType) => void;\n };\n}\n\ntype Tab = 'style' | 'text' | 'coordinates' | 'visibility';\n\n/** Most points the Coordinates tab lists. */\nconst MAX_COORDINATE_ROWS = 12;\n/** A saved template's entry in the Template menu, by its place in the list. */\nconst TEMPLATE_ID = 't:';\n\nlet nextDialogId = 1;\n\n/**\n * A drawing's settings, in tabs: Style (the line, its ends, the fill, the\n * tool's own switches and levels), Text, Coordinates (its points by price,\n * date and time) and Visibility (the intervals it shows on). Edits show on\n * the chart at once; OK keeps them as one undo step, Cancel puts it back.\n * The Template menu applies, saves and deletes templates, keeps the options\n * as the tool's default, or resets them.\n */\nexport class WidgetDrawingSettings {\n private backdrop: HTMLDivElement;\n private modal: HTMLDivElement;\n private titleEl: HTMLHeadingElement;\n private tabsEl: HTMLDivElement;\n private bodyEl: HTMLDivElement;\n private templateBtn: HTMLButtonElement;\n private menu: WidgetContextMenu | null = null;\n private tabButtons: HTMLButtonElement[] = [];\n private target: DrawingSettingsTarget | null = null;\n private style!: DrawingStyle;\n private options: DrawingOptions = {};\n private anchors: AnchorPoint[] = [];\n private intervals: IndicatorIntervals | null = null;\n private tab: Tab = 'style';\n private returnFocus: HTMLElement | null = null;\n private readonly uid = nextDialogId++;\n\n constructor(\n host: HTMLElement,\n private readonly callbacks: DrawingSettingsCallbacks,\n private readonly t: Translator = EN_TRANSLATOR,\n ) {\n this.backdrop = document.createElement('div');\n this.backdrop.className = 'tcw-modal-backdrop';\n this.backdrop.hidden = true;\n // A press that starts in the dialog (selecting text, say) and ends on the\n // backdrop doesn't close it.\n let pressedBackdrop = false;\n this.backdrop.addEventListener('pointerdown', (e) => {\n pressedBackdrop = e.target === this.backdrop;\n });\n this.backdrop.addEventListener('click', (e) => {\n if (e.target === this.backdrop && pressedBackdrop) this.close(true);\n pressedBackdrop = false;\n });\n\n this.modal = document.createElement('div');\n this.modal.className = 'tcw-modal tcw-modal-narrow tcw-drawing-settings';\n this.modal.setAttribute('role', 'dialog');\n this.modal.setAttribute('aria-modal', 'true');\n this.modal.setAttribute('aria-labelledby', `tcw-draw-title-${this.uid}`);\n this.modal.tabIndex = -1;\n this.modal.addEventListener('keydown', (e) => this.onKeyDown(e));\n\n const header = document.createElement('div');\n header.className = 'tcw-modal-header';\n this.titleEl = document.createElement('h3');\n this.titleEl.id = `tcw-draw-title-${this.uid}`;\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.close(true));\n header.append(this.titleEl, closeBtn);\n\n this.tabsEl = document.createElement('div');\n this.tabsEl.className = 'tcw-modal-tabs';\n this.tabsEl.setAttribute('role', 'tablist');\n this.tabsEl.addEventListener('keydown', (e) => this.onTabKey(e));\n\n this.bodyEl = document.createElement('div');\n this.bodyEl.className = 'tcw-modal-body';\n this.bodyEl.id = `tcw-draw-panel-${this.uid}`;\n this.bodyEl.setAttribute('role', 'tabpanel');\n\n this.templateBtn = this.footerButton('template', 'tcw-footer-menu', () => this.openTemplates());\n this.modal.append(header, this.tabsEl, this.bodyEl, this.buildFooter());\n this.backdrop.appendChild(this.modal);\n host.appendChild(this.backdrop);\n }\n\n /** Template on the left; Cancel and OK on the right. */\n private buildFooter(): HTMLDivElement {\n this.templateBtn.setAttribute('aria-haspopup', 'menu');\n this.templateBtn.setAttribute('aria-expanded', 'false');\n this.templateBtn.innerHTML = `<span></span>${createIcon('chevronDown', 12)}`;\n this.templateBtn.querySelector('span')!.textContent = this.t('settings.template');\n const end = document.createElement('div');\n end.className = 'tcw-footer-end';\n end.append(\n this.footerButton('cancel', 'tcw-footer-cancel', () => this.close(true), this.t('common.cancel')),\n this.footerButton('ok', 'tcw-done-btn', () => this.close(false), this.t('drawingSettings.ok')),\n );\n const footer = document.createElement('div');\n footer.className = 'tcw-modal-footer';\n footer.append(this.templateBtn, end);\n return footer;\n }\n\n /**\n * Open on `target`. With `tab: 'text'` it opens on the Text tab (a tool\n * that writes), the text selected so typing replaces it.\n */\n open(target: DrawingSettingsTarget, how: { tab?: 'text' } = {}): void {\n if (this.target) this.close(false);\n this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n this.target = target;\n this.style = { ...target.style };\n this.options = structuredClone(target.options);\n this.anchors = target.anchors.map((a) => ({ ...a }));\n this.intervals = target.intervals ?? null;\n this.titleEl.textContent = target.name;\n this.tab = how.tab === 'text' && target.text ? 'text' : 'style';\n this.callbacks.onBegin(target.id);\n try {\n this.renderTabs();\n this.renderBody();\n } catch (err) {\n // A drawing the dialog can't show: end the edit it began.\n this.target = null;\n this.callbacks.onEnd(target.id, true);\n throw err;\n }\n this.backdrop.hidden = false;\n const text = this.tab === 'text' ? this.bodyEl.querySelector<HTMLTextAreaElement>('textarea') : null;\n if (text) {\n text.focus();\n text.select();\n } else {\n (this.tabButtons[0] ?? this.modal).focus();\n }\n }\n\n /** Close the dialog, keeping the edits or (with `cancel`) putting the drawing back. */\n close(cancel: boolean): void {\n const target = this.target;\n if (!target) return;\n // A value typed but not yet committed still applies on OK.\n const active = document.activeElement;\n if (!cancel && (active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement) && this.modal.contains(active)) {\n active.dispatchEvent(new Event('change'));\n }\n this.target = null;\n this.menu?.close();\n this.backdrop.hidden = true;\n this.callbacks.onEnd(target.id, cancel);\n if (this.returnFocus?.isConnected) this.returnFocus.focus();\n this.returnFocus = null;\n }\n\n isOpen(): boolean {\n return this.target !== null;\n }\n\n /** The drawing being edited, if any. */\n editing(): string | null {\n return this.target?.id ?? null;\n }\n\n destroy(): void {\n this.close(true);\n this.menu?.destroy();\n this.backdrop.remove();\n }\n\n // --- Tabs ---\n\n private tabs(): Tab[] {\n const target = this.target;\n if (!target) return [];\n return [\n 'style',\n ...(target.text ? ['text' as const] : []),\n // A freehand stroke has hundreds of points: no table of them.\n ...(target.coordinates !== false && target.anchors.length <= MAX_COORDINATE_ROWS ? ['coordinates' as const] : []),\n 'visibility',\n ];\n }\n\n private renderTabs(): void {\n this.tabButtons = this.tabs().map((tab) => {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'tcw-modal-tab';\n btn.id = `tcw-draw-tab-${this.uid}-${tab}`;\n btn.setAttribute('role', 'tab');\n btn.setAttribute('aria-controls', this.bodyEl.id);\n btn.dataset.tab = tab;\n btn.textContent = this.t(`drawingSettings.tab.${tab}`);\n btn.addEventListener('click', () => this.selectTab(tab));\n return btn;\n });\n this.tabsEl.replaceChildren(...this.tabButtons);\n this.markTabs();\n }\n\n private markTabs(): void {\n for (const btn of this.tabButtons) {\n const selected = btn.dataset.tab === this.tab;\n btn.classList.toggle('tcw-active', selected);\n btn.setAttribute('aria-selected', String(selected));\n btn.tabIndex = selected ? 0 : -1;\n if (selected) this.bodyEl.setAttribute('aria-labelledby', btn.id);\n }\n }\n\n private selectTab(tab: Tab, focus = false): void {\n this.tab = tab;\n this.markTabs();\n this.renderBody();\n if (focus) this.tabButtons.find((b) => b.dataset.tab === tab)?.focus();\n }\n\n /** Arrow keys (the other way right to left), Home and End move between tabs. */\n private onTabKey(e: KeyboardEvent): void {\n const tabs = this.tabButtons.map((b) => b.dataset.tab as Tab);\n const at = tabs.indexOf(this.tab);\n const rtl = this.modal.closest('[dir]')?.getAttribute('dir') === 'rtl';\n const [forward, back] = rtl ? ['ArrowLeft', 'ArrowRight'] : ['ArrowRight', 'ArrowLeft'];\n const next = e.key === forward ? (at + 1) % tabs.length\n : e.key === back ? (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], true);\n }\n\n /** Escape cancels; Tab stays inside the dialog. */\n private onKeyDown(e: KeyboardEvent): void {\n if (e.key === 'Escape') {\n e.preventDefault();\n e.stopPropagation();\n this.close(true);\n return;\n }\n keepTabInside(e, this.modal);\n }\n\n private renderBody(): void {\n this.bodyEl.replaceChildren();\n const target = this.target;\n if (!target) return;\n switch (this.tab) {\n case 'text':\n renderTextTab(this.bodyEl, this.style, (patch) => this.setStyle(patch), this.t, target.textLayout, target.textColor, target.textPlace);\n break;\n case 'coordinates':\n renderCoordinatesTab(this.bodyEl, this.anchors, {\n toWallTime: this.callbacks.toWallTime,\n fromWallTime: this.callbacks.fromWallTime,\n roundPrice: this.callbacks.roundPrice,\n priceStep: this.callbacks.priceStep,\n move: (index, patch) => this.setAnchor(index, patch),\n }, this.t);\n break;\n case 'visibility':\n renderVisibilityTab(this.bodyEl, this.intervals, (next) => this.setIntervals(next), this.t);\n break;\n default:\n renderStyleTab(this.bodyEl, { style: () => this.style, options: () => this.options, defs: target.defs, fill: target.fill }, {\n style: (patch) => this.setStyle(patch),\n options: (patch) => this.setOptions(patch),\n redraw: (focus = []) => {\n this.renderBody();\n for (const selector of focus) {\n const el = this.bodyEl.querySelector<HTMLElement>(selector);\n if (el) {\n el.focus();\n break;\n }\n }\n },\n }, this.t);\n }\n }\n\n // --- Edits ---\n\n private change(patch: DrawingSettingsPatch): void {\n if (this.target) this.callbacks.onChange(this.target.id, patch);\n }\n\n private setStyle(style: Partial<DrawingStyle>): void {\n if (!this.target) return;\n this.style = { ...this.style, ...style };\n this.change({ style });\n }\n\n private setOptions(options: DrawingOptions): void {\n if (!this.target) return;\n this.options = { ...this.options, ...structuredClone(options) };\n this.change({ options });\n }\n\n private setAnchor(index: number, patch: Partial<AnchorPoint>): void {\n if (!this.target) return;\n this.anchors = this.anchors.map((a, i) => (i === index ? { ...a, ...patch } : a));\n this.change({ anchors: this.anchors.map((a) => ({ ...a })) });\n }\n\n private setIntervals(intervals: IndicatorIntervals | null): void {\n if (!this.target) return;\n this.intervals = intervals;\n this.change({ intervals });\n }\n\n // --- Template ---\n\n /** The Template menu: the saved templates (each removable), Save as template, Save as default, Reset to defaults. */\n private openTemplates(): void {\n const target = this.target;\n if (!target) return;\n if (this.menu?.isOpen()) {\n this.menu.close();\n return;\n }\n const store = this.callbacks.templates;\n const saved = store?.list(target.type) ?? [];\n const entries: ContextMenuEntry[] = [\n ...saved.map((template, i): ContextMenuEntry => ({\n id: `${TEMPLATE_ID}${i}`, label: template.name, icon: 'layers', remove: fill(this.t('templates.delete'), { name: template.name }),\n })),\n ...(saved.length > 0 ? ['separator' as const] : []),\n ...(store ? [{ id: 'save', label: this.t('settings.saveTemplate'), icon: 'save' }] : []),\n ...(this.callbacks.onSaveDefault ? [{ id: 'default', label: this.t('drawingSettings.saveDefault'), icon: 'pin' }] : []),\n { id: 'reset', label: this.t('settings.resetToDefaults'), icon: 'reset' },\n ];\n const savedAt = (id: string) => saved[Number(id.slice(TEMPLATE_ID.length))];\n this.menu ??= new WidgetContextMenu(this.modal, this.t('settings.template'));\n const at = this.templateBtn.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 === 'save') store?.save({ type: target.type, style: { ...this.style }, options: structuredClone(this.options) });\n else if (id === 'default') this.callbacks.onSaveDefault?.(target.type, structuredClone(this.options));\n else if (id === 'reset') this.resetOptions();\n else if (id.startsWith(TEMPLATE_ID)) this.applyTemplate(savedAt(id));\n }, this.templateBtn, (id) => {\n const template = savedAt(id);\n if (template) store?.remove(template.name, template.type);\n });\n }\n\n private applyTemplate(template: DrawingStyleTemplate | undefined): void {\n const target = this.target;\n if (!template || !target) return;\n if (Object.keys(template.style).length > 0) this.setStyle(template.style);\n // Templates come from storage: only options the tool takes apply.\n if (template.options) this.setOptions(sanitizeDrawingOptions(target.defs, template.options));\n this.renderBody();\n }\n\n /** The tool's options back to its defaults. */\n private resetOptions(): void {\n const target = this.target;\n if (!target) return;\n const defaults: DrawingOptions = {};\n for (const [key, def] of Object.entries(target.defs)) defaults[key] = structuredClone(def.default) as DrawingOptions[string];\n this.setOptions(defaults);\n this.renderBody();\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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"WidgetDrawingSettings-CsR3GuFG.js","names":[],"sources":["../src/widget/drawingSettingsTabs.ts","../src/widget/WidgetDrawingSettings.ts"],"sourcesContent":["import type { AnchorPoint, DrawingLevel, DrawingOptionDef, DrawingOptionDefs, DrawingOptions, DrawingStyle } from '@tradecanvas/commons';\nimport { ownFillColor } from '@tradecanvas/commons';\nimport { createIcon } from './icons.js';\nimport { fill, type MessageKey, type Translator } from './i18n.js';\nimport type { TextLayout } from './drawingText.js';\nimport { checkRow, colorAlpha, colorInput, numberInput, selectInput, settingsRow, toHex, withAlpha } from './settingsControls.js';\n\nexport type { TextLayout };\n\nconst LINE_WIDTHS = [1, 2, 3, 4];\nconst LINE_STYLES: DrawingStyle['lineStyle'][] = ['solid', 'dashed', 'dotted'];\n/**\n * The sizes offered for a drawing's text. Not 12: drawings saved with the old default\n * all carry it, so the chart reads it as no size of their own and draws its default.\n */\nconst FONT_SIZES = [10, 11, 13, 14, 16, 18, 20, 24, 28, 32];\n/** The size a text tool without a layout of its own draws at (a price label, an arrow's label). */\nconst DEFAULT_FONT_SIZE = 14;\n/** The old default every drawing was saved with: the chart draws its own default for it. */\nconst LEGACY_FONT_SIZE = 12;\n/** Most levels the editor offers to add, like the chart keeps. */\nconst MAX_LEVELS = 48;\n/** A new level sits this far past the last one. */\nconst LEVEL_STEP = 0.5;\n/** The fill's opacity a drawing without one starts from. */\nconst DEFAULT_FILL_ALPHA = 0.12;\n/** Options set in the line's own row, not listed with the tool's others. */\nconst END_KEYS = ['leftEnd', 'rightEnd'] as const;\n\n/** What the Style tab shows. */\nexport interface StyleTabModel {\n /** The style and the options as they are now (a row edits what the last edit left). */\n style: () => DrawingStyle;\n options: () => DrawingOptions;\n defs: DrawingOptionDefs;\n /** Whether the tool fills an area (the Fill row). */\n fill: boolean;\n}\n\n/** What the Style tab changes. */\nexport interface StyleTabActions {\n style(patch: Partial<DrawingStyle>): void;\n options(patch: DrawingOptions): void;\n /** Draw the tab again (a level added or removed), the keyboard on the first of `focus` there is. */\n redraw(focus?: readonly string[]): void;\n}\n\n/** Told the line's new colour: what takes it while it has none of its own (the fill, a level). */\ntype ColorFollower = (color: string) => void;\n\n/** A label from the widget's strings (`drawingOption.<key>`), else the tool's own. */\nfunction optionLabel(t: Translator, key: string, fallback: string): string {\n const messageKey = `drawingOption.${key}` as MessageKey;\n const text = t(messageKey);\n return text === messageKey ? fallback : text;\n}\n\nfunction section(): HTMLDivElement {\n const el = document.createElement('div');\n el.className = 'tcw-settings-section';\n return el;\n}\n\n/** A row of several controls after a label (a `<label>` would only reach the first). */\nfunction controlsRow(label: string, ...controls: HTMLElement[]): HTMLDivElement {\n const row = document.createElement('div');\n row.className = 'tcw-settings-row';\n const text = document.createElement('span');\n text.className = 'tcw-settings-label';\n text.textContent = label;\n const box = document.createElement('span');\n box.className = 'tcw-indi-plot-controls';\n box.append(...controls);\n row.append(text, box);\n return row;\n}\n\nfunction named<T extends HTMLElement>(el: T, label: string): T {\n el.setAttribute('aria-label', label);\n return el;\n}\n\n/**\n * The Style tab: the line (colour, width, dash), its ends, the fill, then\n * the tool's own switches and choices, and its levels last.\n */\nexport function renderStyleTab(body: HTMLElement, model: StyleTabModel, actions: StyleTabActions, t: Translator): void {\n const followers: ColorFollower[] = [];\n const look = section();\n look.appendChild(lineRow(model.style(), actions, followers, t));\n // A tool's ends only when they are the choice of plain or arrow; another option of that name is listed with the rest.\n const ends: string[] = END_KEYS.filter((key) => model.defs[key]?.kind === 'choice');\n if (ends.length > 0) {\n look.appendChild(controlsRow(t('drawingSettings.lineEnds'), ...ends.map((key) => named(selectInput(\n [{ value: 'normal', label: t('drawingSettings.lineEnd.normal') }, { value: 'arrow', label: t('drawingSettings.lineEnd.arrow') }],\n String(model.options()[key] ?? 'normal'),\n (v) => actions.options({ [key]: v }),\n ), optionLabel(t, key, model.defs[key].label)))));\n }\n if (model.fill) look.appendChild(fillRow(model.style(), actions, followers, t));\n body.appendChild(look);\n\n const rest = Object.entries(model.defs).filter(([key, def]) => def.kind !== 'levels' && !ends.includes(key));\n if (rest.length > 0) {\n const own = section();\n for (const [key, def] of rest) own.appendChild(optionRow(key, def as Exclude<DrawingOptionDef, { kind: 'levels' }>, model.options(), actions, t));\n body.appendChild(own);\n }\n for (const [key, def] of Object.entries(model.defs)) {\n if (def.kind === 'levels') body.appendChild(levelsEditor(key, def, model, actions, followers, t));\n }\n}\n\nfunction lineRow(style: DrawingStyle, actions: StyleTabActions, followers: readonly ColorFollower[], t: Translator): HTMLDivElement {\n const color = named(colorInput(style.color, (v) => {\n actions.style({ color: v });\n for (const follow of followers) follow(v);\n }), t('drawingSettings.color'));\n const width = named(selectInput(\n LINE_WIDTHS.map((w) => ({ value: String(w), label: `${w} px` })),\n String(style.lineWidth),\n (v) => actions.style({ lineWidth: Number(v) }),\n ), t('drawingSettings.lineWidth'));\n const dash = named(selectInput(\n LINE_STYLES.map((s) => ({ value: s, label: t(`drawingSettings.lineStyle.${s}`) })),\n style.lineStyle,\n (v) => actions.style({ lineStyle: v as DrawingStyle['lineStyle'] }),\n ), t('drawingSettings.lineStyle'));\n return controlsRow(t('drawingSettings.line'), color, width, dash);\n}\n\nfunction fillRow(style: DrawingStyle, actions: StyleTabActions, followers: ColorFollower[], t: Translator): HTMLDivElement {\n const current = ownFillColor(style) ?? withAlpha(style.color, DEFAULT_FILL_ALPHA);\n let hex = toHex(current);\n let alpha = colorAlpha(current);\n // Without a fill of its own the drawing fills in its line's colour, until one is set here.\n let own = ownFillColor(style) !== undefined;\n const apply = () => {\n own = true;\n actions.style({ fillColor: withAlpha(hex, alpha), fillOpacity: alpha });\n };\n const color = named(colorInput(hex, (v) => {\n hex = v;\n apply();\n }), t('drawingSettings.fill'));\n followers.push((line) => {\n if (own) return;\n hex = toHex(line);\n color.value = hex;\n });\n const opacity = named(numberInput(Math.round(alpha * 100), { min: 0, max: 100, step: 5 }, (v) => {\n alpha = v / 100;\n apply();\n }), t('drawingSettings.opacity'));\n const percent = document.createElement('span');\n percent.className = 'tcw-unit';\n percent.setAttribute('aria-hidden', 'true');\n percent.textContent = '%';\n return controlsRow(t('drawingSettings.fill'), color, opacity, percent);\n}\n\nfunction optionRow(\n key: string,\n def: Exclude<DrawingOptionDef, { kind: 'levels' }>,\n options: DrawingOptions,\n actions: StyleTabActions,\n t: Translator,\n): HTMLElement {\n const label = optionLabel(t, key, def.label);\n const value = options[key];\n switch (def.kind) {\n case 'boolean':\n return checkRow(label, Boolean(value), (v) => actions.options({ [key]: v }));\n case 'number':\n return settingsRow(label, numberInput(Number(value), { min: def.min, max: def.max, step: def.step }, (v) => actions.options({ [key]: v })));\n case 'choice':\n return settingsRow(label, selectInput(\n def.choices.map((c) => ({ value: c.value, label: optionLabel(t, `${key}.${c.value}`, c.label) })),\n String(value),\n (v) => actions.options({ [key]: v }),\n ));\n case 'text': {\n const input = document.createElement('input');\n input.type = 'text';\n input.className = 'tcw-indi-input';\n input.value = String(value ?? '');\n input.addEventListener('change', () => actions.options({ [key]: input.value }));\n return settingsRow(label, input);\n }\n }\n}\n\n/** One row per level: shown or not, its ratio, its colour, remove; and a button to add one. */\nfunction levelsEditor(\n key: string,\n def: Extract<DrawingOptionDef, { kind: 'levels' }>,\n model: StyleTabModel,\n actions: StyleTabActions,\n followers: ColorFollower[],\n t: Translator,\n): HTMLElement {\n const wrap = document.createElement('div');\n wrap.className = 'tcw-settings-section tcw-levels-editor';\n const head = document.createElement('div');\n head.className = 'tcw-settings-section-title';\n head.textContent = optionLabel(t, key, def.label);\n wrap.appendChild(head);\n\n const levels = (): DrawingLevel[] => {\n const value = model.options()[key];\n return Array.isArray(value) ? (value as DrawingLevel[]) : [];\n };\n const commit = (next: DrawingLevel[]) => actions.options({ [key]: next });\n const grid = document.createElement('div');\n grid.className = 'tcw-levels-grid';\n levels().forEach((level, index) => {\n const row = document.createElement('div');\n row.className = 'tcw-level-row';\n const nth = ` ${index + 1}`; // rows share labels; the number tells them apart\n const visible = document.createElement('input');\n visible.type = 'checkbox';\n visible.checked = level.visible;\n visible.setAttribute('aria-label', t('drawingSettings.levelVisible') + nth);\n visible.addEventListener('change', () => commit(levels().map((l, i) => (i === index ? { ...l, visible: visible.checked } : l))));\n const value = named(numberInput(level.value, { step: 0.001 }, (v) => commit(levels().map((l, i) => (i === index ? { ...l, value: v } : l)))), t('drawingSettings.levelValue') + nth);\n const color = named(colorInput(level.color ?? model.style().color, (v) => commit(levels().map((l, i) => (i === index ? { ...l, color: v } : l)))), t('drawingSettings.levelColor') + nth);\n // A level without a colour of its own is drawn in the line's.\n followers.push((line) => {\n if (levels()[index]?.color === undefined) color.value = toHex(line);\n });\n const remove = document.createElement('button');\n remove.type = 'button';\n remove.className = 'tcw-level-remove';\n remove.setAttribute('aria-label', t('drawingSettings.removeLevel') + nth);\n remove.innerHTML = createIcon('x', 12);\n remove.addEventListener('click', () => {\n commit(levels().filter((_, i) => i !== index));\n // The keyboard stays where it was: on the next level's remove button, else the last one's, else Add.\n actions.redraw([\n `.tcw-level-row:nth-child(${index + 1}) .tcw-level-remove`,\n '.tcw-level-row:last-child .tcw-level-remove',\n '.tcw-level-add',\n ]);\n });\n row.append(visible, value, color, remove);\n grid.appendChild(row);\n });\n wrap.appendChild(grid);\n\n const add = document.createElement('button');\n add.type = 'button';\n add.className = 'tcw-reset-link tcw-level-add';\n add.textContent = t('drawingSettings.addLevel');\n add.disabled = levels().length >= MAX_LEVELS;\n add.addEventListener('click', () => {\n const last = levels().at(-1)?.value ?? 0;\n commit([...levels(), { value: Math.round((last + LEVEL_STEP) * 1000) / 1000, visible: true }]);\n actions.redraw(['.tcw-level-row:last-child input[type=\"number\"]']);\n });\n wrap.appendChild(add);\n return wrap;\n}\n\n/** The width a text wraps at when wrapping is turned on and it has none of its own. */\nconst DEFAULT_WRAP = 240;\nconst MIN_WRAP = 40;\nconst MAX_WRAP = 4000;\nconst WRAP_STEP = 10;\nconst ALIGNS = ['left', 'center', 'right'] as const;\nconst VALIGNS = ['top', 'middle', 'bottom'] as const;\n\n/**\n * A box ticked or not inside a row of controls, its name written after it\n * unless the row already says it (`said`): a screen reader hears it either way.\n */\nfunction inlineCheck(label: string, value: boolean, onChange: (value: boolean) => void, said = false): HTMLLabelElement {\n const wrap = document.createElement('label');\n wrap.className = 'tcw-inline-check';\n const box = document.createElement('input');\n box.type = 'checkbox';\n box.checked = value;\n box.setAttribute('aria-label', label);\n box.addEventListener('change', () => onChange(box.checked));\n wrap.append(box);\n if (!said) {\n const text = document.createElement('span');\n text.textContent = label;\n wrap.append(text);\n }\n return wrap;\n}\n\n/**\n * The Text tab: what the drawing writes, its size, bold and italics, and its\n * colour; for a text box (`layout`), its alignment, background, border and\n * the width it wraps at; for a line's or a box's text (`place`), where it sits.\n */\nexport function renderTextTab(\n body: HTMLElement,\n style: DrawingStyle,\n onStyle: (patch: Partial<DrawingStyle>) => void,\n t: Translator,\n layout?: TextLayout,\n textColor?: string,\n place = false,\n): void {\n const block = section();\n const text = document.createElement('textarea');\n text.className = 'tcw-indi-input tcw-drawing-text';\n text.rows = 3;\n text.value = style.text ?? '';\n text.addEventListener('input', () => onStyle({ text: text.value }));\n const textRow = settingsRow(t('drawingSettings.text'), text);\n textRow.classList.add('tcw-text-row');\n block.appendChild(textRow);\n const size = named(selectInput(\n FONT_SIZES.map((s) => ({ value: String(s), label: `${s} px` })),\n String((style.fontSize !== LEGACY_FONT_SIZE ? style.fontSize : undefined) ?? layout?.fontSize ?? DEFAULT_FONT_SIZE),\n (v) => onStyle({ fontSize: Number(v) }),\n ), t('drawingSettings.fontSize'));\n block.appendChild(controlsRow(\n t('drawingSettings.fontSize'),\n size,\n inlineCheck(t('drawingSettings.bold'), style.bold === true, (on) => onStyle({ bold: on })),\n inlineCheck(t('drawingSettings.italic'), style.italic === true, (on) => onStyle({ italic: on })),\n ));\n block.appendChild(controlsRow(t('drawingSettings.textColor'), named(\n colorInput(style.textColor ?? textColor ?? style.color, (v) => onStyle({ textColor: v })),\n t('drawingSettings.textColor'),\n )));\n body.appendChild(block);\n if (layout) body.appendChild(textBoxSection(style, onStyle, t, layout));\n if (place) body.appendChild(textPlaceSection(style, onStyle, t));\n}\n\n/** Where a line's or a box's text sits: at an end or the middle, and above, on or under (at the top, middle or bottom). */\nfunction textPlaceSection(style: DrawingStyle, onStyle: (patch: Partial<DrawingStyle>) => void, t: Translator): HTMLElement {\n const place = section();\n place.appendChild(controlsRow(t('drawingSettings.align'), named(selectInput(\n ALIGNS.map((a) => ({ value: a, label: t(`drawingSettings.align.${a}`) })),\n style.textAlign ?? 'center',\n (v) => onStyle({ textAlign: v as DrawingStyle['textAlign'] }),\n ), t('drawingSettings.align'))));\n place.appendChild(controlsRow(t('drawingSettings.vAlign'), named(selectInput(\n VALIGNS.map((a) => ({ value: a, label: t(`drawingSettings.vAlign.${a}`) })),\n style.textVAlign ?? 'top',\n (v) => onStyle({ textVAlign: v as DrawingStyle['textVAlign'] }),\n ), t('drawingSettings.vAlign'))));\n return place;\n}\n\n/** A text box's rows: alignment, background, border, and the width it wraps at. */\nfunction textBoxSection(style: DrawingStyle, onStyle: (patch: Partial<DrawingStyle>) => void, t: Translator, layout: TextLayout): HTMLElement {\n const box = section();\n box.appendChild(controlsRow(t('drawingSettings.align'), named(selectInput(\n ALIGNS.map((a) => ({ value: a, label: t(`drawingSettings.align.${a}`) })),\n style.textAlign ?? 'left',\n (v) => onStyle({ textAlign: v as DrawingStyle['textAlign'] }),\n ), t('drawingSettings.align'))));\n\n const background = ownFillColor(style) ?? withAlpha(style.color, DEFAULT_FILL_ALPHA);\n box.appendChild(controlsRow(\n t('drawingSettings.background'),\n inlineCheck(t('drawingSettings.background'), style.textBackground ?? layout.box, (on) => onStyle({ textBackground: on }), true),\n named(colorInput(background, (v) => onStyle({ fillColor: withAlpha(v, colorAlpha(background)) })), t('drawingSettings.backgroundColor')),\n ));\n box.appendChild(controlsRow(\n t('drawingSettings.border'),\n inlineCheck(t('drawingSettings.border'), style.textBorder ?? layout.border, (on) => onStyle({ textBorder: on }), true),\n named(colorInput(style.borderColor ?? style.color, (v) => onStyle({ borderColor: v })), t('drawingSettings.borderColor')),\n ));\n\n // The width shows what wrapping on would use: the text's own, else the tool's, else a default.\n const own = style.textWrap ?? layout.wrap;\n let width = own > 0 ? own : layout.wrap > 0 ? layout.wrap : DEFAULT_WRAP;\n let wrapping = own > 0;\n const widthInput = named(numberInput(width, { min: MIN_WRAP, max: MAX_WRAP, step: WRAP_STEP }, (v) => {\n width = v;\n if (wrapping) onStyle({ textWrap: v });\n }), t('drawingSettings.wrapWidth'));\n // A width means something only while the text wraps.\n widthInput.disabled = !wrapping;\n box.appendChild(controlsRow(\n t('drawingSettings.wrap'),\n inlineCheck(t('drawingSettings.wrap'), wrapping, (on) => {\n wrapping = on;\n widthInput.disabled = !on;\n onStyle({ textWrap: on ? width : 0 });\n }, true),\n widthInput,\n ));\n return box;\n}\n\n/** What the Coordinates tab reads and changes. */\nexport interface CoordinatesTabActions {\n /** An anchor's time as the date and time fields show it (the chart's zone), and back. */\n toWallTime(time: number): { date: string; time: string };\n fromWallTime(date: string, time: string): number | null;\n /** A price on the market's grid. */\n roundPrice?(price: number): number;\n /** The market's smallest price step, for the price fields' arrows. */\n priceStep?(): number;\n move(index: number, patch: Partial<AnchorPoint>): void;\n}\n\n/** The Coordinates tab: a row per point, its price, date and time. */\nexport function renderCoordinatesTab(body: HTMLElement, anchors: readonly AnchorPoint[], actions: CoordinatesTabActions, t: Translator): void {\n const block = section();\n anchors.forEach((anchor, index) => {\n const point = fill(t('drawingSettings.point'), { n: index + 1 });\n const wall = actions.toWallTime(anchor.time);\n const date = document.createElement('input');\n date.type = 'date';\n date.className = 'tcw-indi-input';\n date.value = wall.date;\n const time = document.createElement('input');\n time.type = 'time';\n time.className = 'tcw-indi-input';\n time.value = wall.time;\n const onTime = () => {\n const at = actions.fromWallTime(date.value, time.value);\n if (at !== null) actions.move(index, { time: at });\n };\n date.addEventListener('change', onTime);\n time.addEventListener('change', onTime);\n const price = priceInput(anchor.price, actions, (p) => actions.move(index, { price: p }));\n const row = controlsRow(point,\n named(price, `${point}: ${t('drawingSettings.price')}`),\n named(date, `${point}: ${t('drawingSettings.date')}`),\n named(time, `${point}: ${t('drawingSettings.time')}`));\n row.classList.add('tcw-draw-point');\n block.appendChild(row);\n });\n body.appendChild(block);\n}\n\n/**\n * A price field on the market's grid. It shows the price rounded, and leaves\n * the point where it is until the field is edited.\n */\nfunction priceInput(price: number, actions: CoordinatesTabActions, onChange: (price: number) => void): HTMLInputElement {\n const round = actions.roundPrice ?? ((p: number) => p);\n const step = actions.priceStep?.();\n const input = numberInput(round(price), { step: step !== undefined && step > 0 ? step : 'any' }, (typed) => {\n const onGrid = round(typed);\n input.value = String(onGrid);\n onChange(onGrid);\n });\n return input;\n}\n","import type {\n AnchorPoint,\n DrawingOptionDefs,\n DrawingOptions,\n DrawingStyle,\n DrawingToolType,\n IndicatorIntervals,\n} from '@tradecanvas/commons';\nimport { sanitizeDrawingOptions } from '@tradecanvas/commons';\nimport { createIcon } from './icons.js';\nimport { keepTabInside } from './focusTrap.js';\nimport { EN_TRANSLATOR, fill, type Translator } from './i18n.js';\nimport { WidgetContextMenu, type ContextMenuEntry } from './WidgetContextMenu.js';\nimport type { DrawingStyleTemplate } from './DrawingTemplateStore.js';\nimport { renderCoordinatesTab, renderStyleTab, renderTextTab, type TextLayout } from './drawingSettingsTabs.js';\nimport { renderVisibilityTab } from './indicatorSettingsTabs.js';\n\n/** The drawing a settings dialog edits. */\nexport interface DrawingSettingsTarget {\n id: string;\n type: DrawingToolType;\n /** The tool's name in the widget's language. */\n name: string;\n style: DrawingStyle;\n /** Every option, defaults filled in. */\n options: DrawingOptions;\n defs: DrawingOptionDefs;\n anchors: AnchorPoint[];\n /** Whether the tool fills an area and draws text (the Fill row, the Text tab). */\n fill: boolean;\n text: boolean;\n /** How the tool lays its text out in a box (the Text tab's alignment, background, border and wrap rows); unset: font rows only. */\n textLayout?: TextLayout;\n /** The colour the tool writes in without one of its own, when it isn't the line's. */\n textColor?: string;\n /** It writes its text along a line or in a box: the Text tab offers where (`textAlign`, `textVAlign`). */\n textPlace?: boolean;\n /** False for a drawing kept to the screen: its points are places on the plot, not times and prices to edit. */\n coordinates?: boolean;\n /** The intervals it shows on; unset or null: all of them. */\n intervals?: IndicatorIntervals | null;\n}\n\nexport interface DrawingSettingsPatch {\n anchors?: AnchorPoint[];\n style?: Partial<DrawingStyle>;\n options?: DrawingOptions;\n /** Null: every interval. */\n intervals?: IndicatorIntervals | null;\n}\n\n/** A drawing's look as a template keeps it: its style, and its tool's options. */\nexport interface DrawingTemplateLook {\n type: DrawingToolType;\n style: Partial<DrawingStyle>;\n options: DrawingOptions;\n}\n\nexport interface DrawingSettingsCallbacks {\n /** The dialog opened on a drawing: edits until `onEnd` are one undo step. */\n onBegin: (id: string) => void;\n /** An edit, shown on the chart at once. */\n onChange: (id: string, patch: DrawingSettingsPatch) => void;\n /** OK keeps the edits; Cancel, Escape or the close button put the drawing back. */\n onEnd: (id: string, cancel: boolean) => void;\n /** An anchor's time as the date and time fields show it (the chart's zone), and back. */\n toWallTime: (time: number) => { date: string; time: string };\n fromWallTime: (date: string, time: string) => number | null;\n /** A price on the market's grid; the Coordinates tab shows and takes prices on it. */\n roundPrice?: (price: number) => number;\n /** The market's smallest price step, for the price fields' arrows. */\n priceStep?: () => number;\n /** Make these the options new drawings of the tool start with. */\n onSaveDefault?: (type: DrawingToolType, options: DrawingOptions) => void;\n /** Saved templates: listed and deleted in the Template menu, and \"Save as template…\" (which asks for a name). */\n templates?: {\n list: (type: DrawingToolType) => DrawingStyleTemplate[];\n save: (look: DrawingTemplateLook) => void;\n remove: (name: string, type?: DrawingToolType) => void;\n };\n}\n\ntype Tab = 'style' | 'text' | 'coordinates' | 'visibility';\n\n/** Most points the Coordinates tab lists. */\nconst MAX_COORDINATE_ROWS = 12;\n/** A saved template's entry in the Template menu, by its place in the list. */\nconst TEMPLATE_ID = 't:';\n\nlet nextDialogId = 1;\n\n/**\n * A drawing's settings, in tabs: Style (the line, its ends, the fill, the\n * tool's own switches and levels), Text, Coordinates (its points by price,\n * date and time) and Visibility (the intervals it shows on). Edits show on\n * the chart at once; OK keeps them as one undo step, Cancel puts it back.\n * The Template menu applies, saves and deletes templates, keeps the options\n * as the tool's default, or resets them.\n */\nexport class WidgetDrawingSettings {\n private backdrop: HTMLDivElement;\n private modal: HTMLDivElement;\n private titleEl: HTMLHeadingElement;\n private tabsEl: HTMLDivElement;\n private bodyEl: HTMLDivElement;\n private templateBtn: HTMLButtonElement;\n private menu: WidgetContextMenu | null = null;\n private tabButtons: HTMLButtonElement[] = [];\n private target: DrawingSettingsTarget | null = null;\n private style!: DrawingStyle;\n private options: DrawingOptions = {};\n private anchors: AnchorPoint[] = [];\n private intervals: IndicatorIntervals | null = null;\n private tab: Tab = 'style';\n private returnFocus: HTMLElement | null = null;\n private readonly uid = nextDialogId++;\n\n constructor(\n host: HTMLElement,\n private readonly callbacks: DrawingSettingsCallbacks,\n private readonly t: Translator = EN_TRANSLATOR,\n ) {\n this.backdrop = document.createElement('div');\n this.backdrop.className = 'tcw-modal-backdrop';\n this.backdrop.hidden = true;\n // A press that starts in the dialog (selecting text, say) and ends on the\n // backdrop doesn't close it.\n let pressedBackdrop = false;\n this.backdrop.addEventListener('pointerdown', (e) => {\n pressedBackdrop = e.target === this.backdrop;\n });\n this.backdrop.addEventListener('click', (e) => {\n if (e.target === this.backdrop && pressedBackdrop) this.close(true);\n pressedBackdrop = false;\n });\n\n this.modal = document.createElement('div');\n this.modal.className = 'tcw-modal tcw-modal-narrow tcw-drawing-settings';\n this.modal.setAttribute('role', 'dialog');\n this.modal.setAttribute('aria-modal', 'true');\n this.modal.setAttribute('aria-labelledby', `tcw-draw-title-${this.uid}`);\n this.modal.tabIndex = -1;\n this.modal.addEventListener('keydown', (e) => this.onKeyDown(e));\n\n const header = document.createElement('div');\n header.className = 'tcw-modal-header';\n this.titleEl = document.createElement('h3');\n this.titleEl.id = `tcw-draw-title-${this.uid}`;\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.close(true));\n header.append(this.titleEl, closeBtn);\n\n this.tabsEl = document.createElement('div');\n this.tabsEl.className = 'tcw-modal-tabs';\n this.tabsEl.setAttribute('role', 'tablist');\n this.tabsEl.addEventListener('keydown', (e) => this.onTabKey(e));\n\n this.bodyEl = document.createElement('div');\n this.bodyEl.className = 'tcw-modal-body';\n this.bodyEl.id = `tcw-draw-panel-${this.uid}`;\n this.bodyEl.setAttribute('role', 'tabpanel');\n\n this.templateBtn = this.footerButton('template', 'tcw-footer-menu', () => this.openTemplates());\n this.modal.append(header, this.tabsEl, this.bodyEl, this.buildFooter());\n this.backdrop.appendChild(this.modal);\n host.appendChild(this.backdrop);\n }\n\n /** Template on the left; Cancel and OK on the right. */\n private buildFooter(): HTMLDivElement {\n this.templateBtn.setAttribute('aria-haspopup', 'menu');\n this.templateBtn.setAttribute('aria-expanded', 'false');\n this.templateBtn.innerHTML = `<span></span>${createIcon('chevronDown', 12)}`;\n this.templateBtn.querySelector('span')!.textContent = this.t('settings.template');\n const end = document.createElement('div');\n end.className = 'tcw-footer-end';\n end.append(\n this.footerButton('cancel', 'tcw-footer-cancel', () => this.close(true), this.t('common.cancel')),\n this.footerButton('ok', 'tcw-done-btn', () => this.close(false), this.t('drawingSettings.ok')),\n );\n const footer = document.createElement('div');\n footer.className = 'tcw-modal-footer';\n footer.append(this.templateBtn, end);\n return footer;\n }\n\n /**\n * Open on `target`. With `tab: 'text'` it opens on the Text tab (a tool\n * that writes), the text selected so typing replaces it.\n */\n open(target: DrawingSettingsTarget, how: { tab?: 'text' } = {}): void {\n if (this.target) this.close(false);\n this.returnFocus = document.activeElement instanceof HTMLElement ? document.activeElement : null;\n this.target = target;\n this.style = { ...target.style };\n this.options = structuredClone(target.options);\n this.anchors = target.anchors.map((a) => ({ ...a }));\n this.intervals = target.intervals ?? null;\n this.titleEl.textContent = target.name;\n this.tab = how.tab === 'text' && target.text ? 'text' : 'style';\n this.callbacks.onBegin(target.id);\n try {\n this.renderTabs();\n this.renderBody();\n } catch (err) {\n // A drawing the dialog can't show: end the edit it began.\n this.target = null;\n this.callbacks.onEnd(target.id, true);\n throw err;\n }\n this.backdrop.hidden = false;\n const text = this.tab === 'text' ? this.bodyEl.querySelector<HTMLTextAreaElement>('textarea') : null;\n if (text) {\n text.focus();\n text.select();\n } else {\n (this.tabButtons[0] ?? this.modal).focus();\n }\n }\n\n /** Close the dialog, keeping the edits or (with `cancel`) putting the drawing back. */\n close(cancel: boolean): void {\n const target = this.target;\n if (!target) return;\n // A value typed but not yet committed still applies on OK.\n const active = document.activeElement;\n if (!cancel && (active instanceof HTMLInputElement || active instanceof HTMLTextAreaElement) && this.modal.contains(active)) {\n active.dispatchEvent(new Event('change'));\n }\n this.target = null;\n this.menu?.close();\n this.backdrop.hidden = true;\n this.callbacks.onEnd(target.id, cancel);\n if (this.returnFocus?.isConnected) this.returnFocus.focus();\n this.returnFocus = null;\n }\n\n isOpen(): boolean {\n return this.target !== null;\n }\n\n /** The drawing being edited, if any. */\n editing(): string | null {\n return this.target?.id ?? null;\n }\n\n destroy(): void {\n this.close(true);\n this.menu?.destroy();\n this.backdrop.remove();\n }\n\n // --- Tabs ---\n\n private tabs(): Tab[] {\n const target = this.target;\n if (!target) return [];\n return [\n 'style',\n ...(target.text ? ['text' as const] : []),\n // A freehand stroke has hundreds of points: no table of them.\n ...(target.coordinates !== false && target.anchors.length <= MAX_COORDINATE_ROWS ? ['coordinates' as const] : []),\n 'visibility',\n ];\n }\n\n private renderTabs(): void {\n this.tabButtons = this.tabs().map((tab) => {\n const btn = document.createElement('button');\n btn.type = 'button';\n btn.className = 'tcw-modal-tab';\n btn.id = `tcw-draw-tab-${this.uid}-${tab}`;\n btn.setAttribute('role', 'tab');\n btn.setAttribute('aria-controls', this.bodyEl.id);\n btn.dataset.tab = tab;\n btn.textContent = this.t(`drawingSettings.tab.${tab}`);\n btn.addEventListener('click', () => this.selectTab(tab));\n return btn;\n });\n this.tabsEl.replaceChildren(...this.tabButtons);\n this.markTabs();\n }\n\n private markTabs(): void {\n for (const btn of this.tabButtons) {\n const selected = btn.dataset.tab === this.tab;\n btn.classList.toggle('tcw-active', selected);\n btn.setAttribute('aria-selected', String(selected));\n btn.tabIndex = selected ? 0 : -1;\n if (selected) this.bodyEl.setAttribute('aria-labelledby', btn.id);\n }\n }\n\n private selectTab(tab: Tab, focus = false): void {\n this.tab = tab;\n this.markTabs();\n this.renderBody();\n if (focus) this.tabButtons.find((b) => b.dataset.tab === tab)?.focus();\n }\n\n /** Arrow keys (the other way right to left), Home and End move between tabs. */\n private onTabKey(e: KeyboardEvent): void {\n const tabs = this.tabButtons.map((b) => b.dataset.tab as Tab);\n const at = tabs.indexOf(this.tab);\n const rtl = this.modal.closest('[dir]')?.getAttribute('dir') === 'rtl';\n const [forward, back] = rtl ? ['ArrowLeft', 'ArrowRight'] : ['ArrowRight', 'ArrowLeft'];\n const next = e.key === forward ? (at + 1) % tabs.length\n : e.key === back ? (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], true);\n }\n\n /** Escape cancels; Tab stays inside the dialog. */\n private onKeyDown(e: KeyboardEvent): void {\n if (e.key === 'Escape') {\n e.preventDefault();\n e.stopPropagation();\n this.close(true);\n return;\n }\n keepTabInside(e, this.modal);\n }\n\n private renderBody(): void {\n this.bodyEl.replaceChildren();\n const target = this.target;\n if (!target) return;\n switch (this.tab) {\n case 'text':\n renderTextTab(this.bodyEl, this.style, (patch) => this.setStyle(patch), this.t, target.textLayout, target.textColor, target.textPlace);\n break;\n case 'coordinates':\n renderCoordinatesTab(this.bodyEl, this.anchors, {\n toWallTime: this.callbacks.toWallTime,\n fromWallTime: this.callbacks.fromWallTime,\n roundPrice: this.callbacks.roundPrice,\n priceStep: this.callbacks.priceStep,\n move: (index, patch) => this.setAnchor(index, patch),\n }, this.t);\n break;\n case 'visibility':\n renderVisibilityTab(this.bodyEl, this.intervals, (next) => this.setIntervals(next), this.t);\n break;\n default:\n renderStyleTab(this.bodyEl, { style: () => this.style, options: () => this.options, defs: target.defs, fill: target.fill }, {\n style: (patch) => this.setStyle(patch),\n options: (patch) => this.setOptions(patch),\n redraw: (focus = []) => {\n this.renderBody();\n for (const selector of focus) {\n const el = this.bodyEl.querySelector<HTMLElement>(selector);\n if (el) {\n el.focus();\n break;\n }\n }\n },\n }, this.t);\n }\n }\n\n // --- Edits ---\n\n private change(patch: DrawingSettingsPatch): void {\n if (this.target) this.callbacks.onChange(this.target.id, patch);\n }\n\n private setStyle(style: Partial<DrawingStyle>): void {\n if (!this.target) return;\n this.style = { ...this.style, ...style };\n this.change({ style });\n }\n\n private setOptions(options: DrawingOptions): void {\n if (!this.target) return;\n this.options = { ...this.options, ...structuredClone(options) };\n this.change({ options });\n }\n\n private setAnchor(index: number, patch: Partial<AnchorPoint>): void {\n if (!this.target) return;\n this.anchors = this.anchors.map((a, i) => (i === index ? { ...a, ...patch } : a));\n this.change({ anchors: this.anchors.map((a) => ({ ...a })) });\n }\n\n private setIntervals(intervals: IndicatorIntervals | null): void {\n if (!this.target) return;\n this.intervals = intervals;\n this.change({ intervals });\n }\n\n // --- Template ---\n\n /** The Template menu: the saved templates (each removable), Save as template, Save as default, Reset to defaults. */\n private openTemplates(): void {\n const target = this.target;\n if (!target) return;\n if (this.menu?.isOpen()) {\n this.menu.close();\n return;\n }\n const store = this.callbacks.templates;\n const saved = store?.list(target.type) ?? [];\n const entries: ContextMenuEntry[] = [\n ...saved.map((template, i): ContextMenuEntry => ({\n id: `${TEMPLATE_ID}${i}`, label: template.name, icon: 'layers', remove: fill(this.t('templates.delete'), { name: template.name }),\n })),\n ...(saved.length > 0 ? ['separator' as const] : []),\n ...(store ? [{ id: 'save', label: this.t('settings.saveTemplate'), icon: 'save' }] : []),\n ...(this.callbacks.onSaveDefault ? [{ id: 'default', label: this.t('drawingSettings.saveDefault'), icon: 'pin' }] : []),\n { id: 'reset', label: this.t('settings.resetToDefaults'), icon: 'reset' },\n ];\n const savedAt = (id: string) => saved[Number(id.slice(TEMPLATE_ID.length))];\n this.menu ??= new WidgetContextMenu(this.modal, this.t('settings.template'));\n const at = this.templateBtn.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 === 'save') store?.save({ type: target.type, style: { ...this.style }, options: structuredClone(this.options) });\n else if (id === 'default') this.callbacks.onSaveDefault?.(target.type, structuredClone(this.options));\n else if (id === 'reset') this.resetOptions();\n else if (id.startsWith(TEMPLATE_ID)) this.applyTemplate(savedAt(id));\n }, this.templateBtn, (id) => {\n const template = savedAt(id);\n if (template) store?.remove(template.name, template.type);\n });\n }\n\n private applyTemplate(template: DrawingStyleTemplate | undefined): void {\n const target = this.target;\n if (!template || !target) return;\n if (Object.keys(template.style).length > 0) this.setStyle(template.style);\n // Templates come from storage: only options the tool takes apply.\n if (template.options) this.setOptions(sanitizeDrawingOptions(target.defs, template.options));\n this.renderBody();\n }\n\n /** The tool's options back to its defaults. */\n private resetOptions(): void {\n const target = this.target;\n if (!target) return;\n const defaults: DrawingOptions = {};\n for (const [key, def] of Object.entries(target.defs)) defaults[key] = structuredClone(def.default) as DrawingOptions[string];\n this.setOptions(defaults);\n this.renderBody();\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"],"mappings":"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"}
|