polyv-live-cli
Version:
CLI tool for managing PolyV live streaming services.
346 lines • 10.6 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.BaseComponent = void 0;
const monitoring_1 = require("../types/monitoring");
class BaseComponent extends monitoring_1.Component {
constructor(config, eventBus) {
super(config, eventBus);
this.isDestroyed = false;
this.lastRenderTime = 0;
this.renderThrottleMs = 16;
this.focusState = {
focused: false,
focusable: true,
tabIndex: 0,
showFocusRing: true,
};
this.initializeComponent();
}
initializeComponent() {
this.state.status = 'initializing';
this.setupEventListeners();
this.createWidget();
this.state.status = 'running';
this.state.lastUpdate = new Date();
}
setupEventListeners() {
this.subscribe('terminal:resize', this.handleTerminalResize.bind(this));
this.subscribe('theme:change', this.handleThemeChange.bind(this));
this.subscribe('component:update', this.handleComponentUpdate.bind(this));
}
throttledRender() {
const now = Date.now();
if (now - this.lastRenderTime >= this.renderThrottleMs) {
this.render();
this.lastRenderTime = now;
}
}
handleTerminalResize(data) {
if (this.isDestroyed)
return;
const newSize = {
minWidth: Math.max(this.config.size.minWidth, data.width * 0.1),
minHeight: Math.max(this.config.size.minHeight, data.height * 0.1),
maxWidth: data.width,
maxHeight: data.height,
};
this.resize(newSize);
}
handleThemeChange(data) {
if (this.isDestroyed)
return;
this.applyTheme(data.theme);
this.throttledRender();
}
handleComponentUpdate(data) {
if (this.isDestroyed)
return;
if (data.source === this.state.id)
return;
this.update(data);
}
applyTheme(_theme) {
}
startRefresh(intervalMs) {
this.stopRefresh();
this.refreshInterval = setInterval(() => {
if (!this.isDestroyed) {
this.requestUpdate();
}
}, intervalMs);
}
stopRefresh() {
if (this.refreshInterval) {
clearInterval(this.refreshInterval);
this.refreshInterval = undefined;
}
}
requestUpdate() {
this.emit('component:requestUpdate', {
componentId: this.state.id,
type: this.config.type,
timestamp: new Date(),
});
}
updateState(updates) {
this.state = { ...this.state, ...updates, lastUpdate: new Date() };
}
handleError(error) {
this.state.status = 'error';
this.state.error = error;
this.emit('component:error', {
componentId: this.state.id,
type: this.config.type,
error: error.message,
timestamp: new Date(),
});
}
resize(size) {
if (this.isDestroyed || !this.widget)
return;
try {
this.widget.width = size.maxWidth || size.minWidth;
this.widget.height = size.maxHeight || size.minHeight;
this.widget.screen?.render();
}
catch (error) {
this.handleError(error instanceof Error ? error : new Error('Unknown resize error'));
}
}
show() {
if (this.widget && !this.isDestroyed) {
this.widget.show();
this.widget.screen?.render();
}
}
hide() {
if (this.widget && !this.isDestroyed) {
this.widget.hide();
this.widget.screen?.render();
}
}
destroy() {
if (this.isDestroyed)
return;
this.isDestroyed = true;
this.state.status = 'destroyed';
this.stopRefresh();
if (this.focusState.focused) {
this.blur();
}
if (this.widget) {
this.widget.destroy();
}
this.emit('component:destroyed', {
componentId: this.state.id,
type: this.config.type,
timestamp: new Date(),
});
}
getId() {
return this.state.id;
}
getType() {
return this.config.type;
}
canFocus() {
return this.focusState.focusable && !this.isDestroyed && this.widget;
}
focus() {
if (!this.canFocus())
return;
this.focusState.focused = true;
if (this.widget && this.widget.focus) {
this.widget.focus();
}
this.updateFocusVisuals();
this.emit('component:focused', {
componentId: this.state.id,
type: this.config.type,
timestamp: new Date(),
});
}
blur() {
if (!this.focusState.focused)
return;
this.focusState.focused = false;
this.updateFocusVisuals();
this.emit('component:blurred', {
componentId: this.state.id,
type: this.config.type,
timestamp: new Date(),
});
}
getFocusState() {
return { ...this.focusState };
}
handleKeyboard(event) {
switch (event.key) {
case 'enter':
this.handleEnterKey(event);
return true;
case 'escape':
this.handleEscapeKey(event);
return true;
case 'space':
this.handleSpaceKey(event);
return true;
default:
return this.handleCustomKeyboard(event);
}
}
handleMouse(event) {
if (!this.isMouseEventInBounds(event)) {
return false;
}
switch (event.action) {
case 'mousedown':
if (event.button === 'left') {
this.handleMouseClick(event);
return true;
}
else if (event.button === 'right') {
this.handleRightClick(event);
return true;
}
break;
case 'wheelup':
case 'wheeldown':
this.handleMouseWheel(event);
return true;
case 'mousemove':
this.handleMouseMove(event);
return true;
}
return false;
}
setTabIndex(index) {
this.focusState.tabIndex = index;
}
setFocusable(focusable) {
this.focusState.focusable = focusable;
if (!focusable && this.focusState.focused) {
this.blur();
}
}
setShowFocusRing(show) {
this.focusState.showFocusRing = show;
this.updateFocusVisuals();
}
updateFocusVisuals() {
if (!this.widget)
return;
if (this.focusState.focused && this.focusState.showFocusRing) {
if (this.widget.style) {
this.widget.style.border = this.widget.style.border || {};
this.widget.style.border.fg = 'cyan';
this.widget.style.border.bold = true;
}
}
else {
if (this.widget.style && this.widget.style.border) {
this.widget.style.border.fg = this.widget.style.border.fg === 'cyan' ? 'white' : this.widget.style.border.fg;
this.widget.style.border.bold = false;
}
}
this.throttledRender();
}
handleEnterKey(event) {
this.emit('component:activated', {
componentId: this.state.id,
type: this.config.type,
event,
timestamp: new Date(),
});
}
handleEscapeKey(event) {
this.emit('component:cancelled', {
componentId: this.state.id,
type: this.config.type,
event,
timestamp: new Date(),
});
}
handleSpaceKey(event) {
this.handleEnterKey(event);
}
handleCustomKeyboard(_event) {
return false;
}
handleMouseClick(event) {
this.emit('component:clicked', {
componentId: this.state.id,
type: this.config.type,
event,
timestamp: new Date(),
});
}
handleRightClick(event) {
this.emit('component:contextmenu', {
componentId: this.state.id,
type: this.config.type,
event,
timestamp: new Date(),
});
}
handleMouseWheel(event) {
this.emit('component:scroll', {
componentId: this.state.id,
type: this.config.type,
event,
direction: event.action === 'wheelup' ? 'up' : 'down',
timestamp: new Date(),
});
}
handleMouseMove(event) {
this.emit('component:hover', {
componentId: this.state.id,
type: this.config.type,
event,
timestamp: new Date(),
});
}
isMouseEventInBounds(event) {
if (!this.widget)
return false;
const bounds = this.getComponentBounds();
if (!bounds)
return false;
return event.x >= bounds.left && event.x <= bounds.right &&
event.y >= bounds.top && event.y <= bounds.bottom;
}
getComponentBounds() {
if (!this.widget)
return null;
if (typeof this.widget.aleft === 'number' && typeof this.widget.atop === 'number') {
const left = this.widget.aleft;
const top = this.widget.atop;
const width = this.widget.width || 0;
const height = this.widget.height || 0;
return {
left,
top,
right: left + width - 1,
bottom: top + height - 1,
};
}
const left = this.widget.left || 0;
const top = this.widget.top || 0;
const width = this.widget.width || 0;
const height = this.widget.height || 0;
let parentLeft = 0;
let parentTop = 0;
if (this.widget.parent) {
parentLeft = this.widget.parent.aleft || 0;
parentTop = this.widget.parent.atop || 0;
}
return {
left: parentLeft + left,
top: parentTop + top,
right: parentLeft + left + width - 1,
bottom: parentTop + top + height - 1,
};
}
}
exports.BaseComponent = BaseComponent;
//# sourceMappingURL=base.component.js.map