components_speaker_context_menu.js
import { ContextMenu } from "./context_menu.js"
/**
* A context menu for speaker operations (set color, rename, remove).
*
* @example
* new SpeakerContextMenu(event.clientX, event.clientY, speaker, {
* onSetColor: () => speakersPanel.openHuePicker(speaker, swatchEl),
* onChangeName: () => speakersPanel.makeSpeakerEditable(nameSpan, speaker),
* onRemove: () => speakersPanel.deleteSpeaker(speaker.id),
* onDismiss: () => {},
* });
*/
export class SpeakerContextMenu extends ContextMenu {
/**
* @param {number} x - Preferred left position in viewport pixels.
* @param {number} y - Preferred top position in viewport pixels.
* @param {object} speaker - The speaker object being acted on.
* @param {object} options - Options and callback functions for the menu.
* @param {function(): void} options.onSetColor - Called when "Set color" is clicked.
* @param {function(): void} options.onChangeName - Called when "Change name" is clicked.
* @param {function(): void} options.onRemove - Called when "Remove speaker" is clicked.
* @param {function(): void} [options.onDismiss] - Called when the menu is dismissed via outside click.
* @param {{message: string, href: (string|undefined)}|null} [options.info] - Info widget config passed to the base ContextMenu.
*/
constructor(x, y, speaker, { onSetColor, onChangeName, onRemove, onDismiss, info = { message: 'Change the color or name of this speaker, or remove them from the project.', href: '/docs' } } = {}) {
super('Speaker', onDismiss, info);
if (speaker) {
const info = document.createElement('div');
info.className = 'ctx-info';
const pairs = [
['NAME', speaker.name],
['ID', speaker.id],
];
pairs.forEach(([k, v]) => {
const key = document.createElement('span');
key.className = 'ctx-info-key';
key.textContent = k;
const val = document.createElement('span');
val.className = 'ctx-info-val';
val.textContent = v;
info.appendChild(key);
info.appendChild(val);
});
this.root.appendChild(info);
}
const controls = document.createElement('div');
controls.className = 'ctx-controls';
if (onSetColor) {
controls.appendChild(this.makeItem(
'◐', 'Set color', null,
() => { this.close(); this._onDismiss(); onSetColor(); },
));
}
if (onChangeName) {
controls.appendChild(this.makeItem(
'✎', 'Change name', null,
() => { this.close(); this._onDismiss(); onChangeName(); },
));
}
if (onRemove) {
const item = this.makeItem(
'<span class="icon icon-close" style="width:12px;height:12px;"></span>',
'Remove speaker', null,
() => { this.close(); this._onDismiss(); onRemove(); },
);
item.classList.add('ctx-item--danger');
controls.appendChild(item);
}
this.root.appendChild(controls);
this._mount(x, y);
}
}