UNPKG

@sprucelabs/spruce-cli

Version:

Command line interface for building Spruce skills.

250 lines (211 loc) • 7.04 kB
import { AbstractEventEmitter } from '@sprucelabs/mercury-event-emitter' import { EventContract } from '@sprucelabs/mercury-types' import { Terminal } from 'terminal-kit' import { BaseWidget, UniversalWidgetOptions, WidgetFrame, WidgetFrameCalculated, WidgetPadding, } from '../types/widgets.types' export type BaseWidgetWithTermKitAddons = BaseWidget & { getTermKitElement: () => any | null } export type TkWidgetOptions = UniversalWidgetOptions & { term: Terminal parent: BaseWidgetWithTermKitAddons } export default abstract class TkBaseWidget<Contract extends EventContract = any> extends AbstractEventEmitter<Contract> implements BaseWidget<Contract> { public type = 'abstract' protected parent: BaseWidgetWithTermKitAddons | null protected term: Terminal private id: string | null private children: BaseWidget[] = [] protected shouldLockWidthWithParent = false protected shouldLockHeightWithParent = false protected shouldLockRightWithParent = false protected shouldLockBottomWithParent = false protected padding: WidgetPadding = {} private frameLockDeltas: { leftDelta: number widthDelta: number topDelta: number heightDelta: number rightDelta: number bottomDelta: number } = { leftDelta: 0, widthDelta: 0, topDelta: 0, heightDelta: 0, rightDelta: 0, bottomDelta: 0, } public constructor(options: TkWidgetOptions) { super(options.eventContract ?? { eventSignatures: {} }) this.parent = options.parent ?? null this.term = options.term this.id = options.id ?? null this.shouldLockHeightWithParent = options.shouldLockHeightWithParent ?? false this.shouldLockWidthWithParent = options.shouldLockWidthWithParent ?? false this.shouldLockRightWithParent = options.shouldLockRightWithParent ?? false this.shouldLockBottomWithParent = options.shouldLockBottomWithParent ?? false this.padding = { left: 0, top: 0, right: 0, bottom: 0, ...options.padding, } if (this.parent) { this.parent.addChild(this as TkBaseWidget) } } public getChildren(): BaseWidget[] { return this.children } public addChild(child: BaseWidget): void { this.children.push(child) } public getId(): string | null { return this.id } public getParent(): BaseWidget | null { return this.parent } public getFrame(): WidgetFrameCalculated { const element = this.getTermKitElement() if (element) { return { left: element.outputX, top: element.outputY, width: element.outputWidth, height: element.outputHeight, } } throw new Error( element ? `${this.type} does not implement getFrame()` : `${this.type} does not implement getTermKitElement()` ) } public setFrame(frame: Partial<WidgetFrame>): void { const element = this.getTermKitElement() if (element) { if (element.resize) { element.resize({ x: frame.left, y: frame.top, width: frame.width, height: frame.height, }) } else { element.outputX = frame.left ?? element.outputX element.outputY = frame.top ?? element.outputY element.outputWidth = frame.width ?? element.outputWidth element.outputHeight = frame.height ?? element.outputHeight } this.sizeLockedChildren() element.draw() return } throw new Error(`${this.type} does not implement getTermKitElement()`) } protected sizeLockedChildren() { const newFrame = this.getFrame() for (const child of this.children as TkBaseWidget[]) { child.handleParentResize(newFrame) } } public getChildById(id?: string): BaseWidget | null { for (const child of this.getChildren()) { if (child.getId() === id) { return child } } return null } public removeChild(child: BaseWidget) { this.children = this.children.filter((c) => c !== child) } protected handleParentResize(parentFrame: WidgetFrameCalculated): void { const updatedFrame = this.getFrame() let shouldSetFrame = false if (this.shouldLockHeightWithParent) { shouldSetFrame = true updatedFrame.height = parentFrame.height - this.frameLockDeltas.heightDelta } if (this.shouldLockWidthWithParent) { shouldSetFrame = true updatedFrame.width = parentFrame.width - this.frameLockDeltas.widthDelta } if (this.shouldLockRightWithParent) { shouldSetFrame = true updatedFrame.left = parentFrame.width - this.frameLockDeltas.rightDelta - updatedFrame.width } if (this.shouldLockBottomWithParent) { shouldSetFrame = true updatedFrame.top = parentFrame.height - updatedFrame.height - this.frameLockDeltas.bottomDelta } if (shouldSetFrame) { this.setFrame(updatedFrame) } } public async destroy() { this.getTermKitElement()?.destroy() this.getParent()?.removeChild(this as BaseWidget) } public getTermKitElement(): any | null { return null } protected calculateSizeLockDeltas() { const frame = this.getFrame() const parentFrame = this.getParent()?.getFrame() if (!parentFrame) { return } let leftDelta = 0 let widthDelta = 0 let topDelta = 0 let heightDelta = 0 let rightDelta = 0 let bottomDelta = 0 if (this.shouldLockWidthWithParent) { leftDelta = frame.left widthDelta = parentFrame.width - frame.width } if (this.shouldLockHeightWithParent) { topDelta = frame.top heightDelta = parentFrame.height - frame.height } if (this.shouldLockRightWithParent) { rightDelta = frame.left + frame.width - parentFrame.width } if (this.shouldLockBottomWithParent) { bottomDelta = parentFrame.height - (frame.top + frame.height) } this.frameLockDeltas = { leftDelta, widthDelta, topDelta, heightDelta, rightDelta, bottomDelta, } } }