158 lines
3.9 KiB
TypeScript
158 lines
3.9 KiB
TypeScript
import { FolkShape } from './folk-shape';
|
|
|
|
export abstract class FolkInteractionHandler extends HTMLElement {
|
|
abstract readonly events: string[];
|
|
abstract handleEvent(event: Event): void;
|
|
|
|
static toolbar: FolkToolset | null = null;
|
|
|
|
protected button: HTMLButtonElement;
|
|
|
|
constructor() {
|
|
super();
|
|
this.attachShadow({ mode: 'open' });
|
|
|
|
const style = document.createElement('style');
|
|
style.textContent = `
|
|
button {
|
|
padding: 8px 16px;
|
|
border: 2px solid transparent;
|
|
cursor: pointer;
|
|
}
|
|
:host(.active) button {
|
|
background-color: #00aaff;
|
|
outline: none;
|
|
}
|
|
`;
|
|
|
|
this.button = document.createElement('button');
|
|
this.shadowRoot!.appendChild(style);
|
|
this.shadowRoot!.appendChild(this.button);
|
|
this.button.addEventListener('click', () => this.activate());
|
|
}
|
|
|
|
activate() {
|
|
console.log('activate', this);
|
|
FolkToolset.setActiveTool(this);
|
|
}
|
|
}
|
|
|
|
export class FolkShapeTool extends FolkInteractionHandler {
|
|
static tagName = 'folk-shape-tool';
|
|
readonly events = ['pointerdown'];
|
|
|
|
constructor() {
|
|
super();
|
|
this.button.textContent = 'Create Shape';
|
|
}
|
|
|
|
handleEvent(event: Event): void {
|
|
if (!(event instanceof PointerEvent)) return;
|
|
const target = event.target as HTMLElement;
|
|
if (!target || target instanceof FolkShape) return;
|
|
|
|
event.stopImmediatePropagation();
|
|
|
|
const shape = new FolkShape();
|
|
const rect = target.getBoundingClientRect();
|
|
const width = 100;
|
|
const height = 100;
|
|
shape.x = event.clientX - rect.left - width / 2;
|
|
shape.y = event.clientY - rect.top - height / 2;
|
|
shape.width = width;
|
|
shape.height = height;
|
|
|
|
target.appendChild(shape);
|
|
shape.focus();
|
|
}
|
|
|
|
static define() {
|
|
if (!customElements.get(this.tagName)) {
|
|
customElements.define(this.tagName, this);
|
|
}
|
|
}
|
|
}
|
|
|
|
export class FolkDeleteTool extends FolkInteractionHandler {
|
|
static tagName = 'folk-delete-tool';
|
|
readonly events = ['pointerdown'];
|
|
|
|
constructor() {
|
|
super();
|
|
this.button.textContent = 'Delete';
|
|
}
|
|
|
|
handleEvent(event: Event): void {
|
|
if (!(event instanceof PointerEvent)) return;
|
|
const target = event.target as HTMLElement;
|
|
if (!target || !(target instanceof FolkShape)) return;
|
|
event.stopImmediatePropagation();
|
|
target.remove();
|
|
}
|
|
|
|
static define() {
|
|
if (!customElements.get(this.tagName)) {
|
|
customElements.define(this.tagName, this);
|
|
}
|
|
}
|
|
}
|
|
|
|
export class FolkToolset extends HTMLElement {
|
|
static tagName = 'folk-toolset';
|
|
private static instance: FolkToolset | null = null;
|
|
private currentHandler: ((event: Event) => void) | null = null;
|
|
private activeTool: FolkInteractionHandler | null = null;
|
|
|
|
static setActiveTool(tool: FolkInteractionHandler) {
|
|
if (this.instance) {
|
|
this.instance.activateTool(tool);
|
|
}
|
|
}
|
|
|
|
constructor() {
|
|
super();
|
|
FolkToolset.instance = this;
|
|
}
|
|
|
|
private activateTool(tool: FolkInteractionHandler) {
|
|
// Remove active class from previous tool
|
|
if (this.activeTool) {
|
|
this.activeTool.classList.remove('active');
|
|
}
|
|
|
|
// Deactivate current handler
|
|
if (this.currentHandler) {
|
|
tool.events.forEach((event) => {
|
|
this.removeEventListener(event, this.currentHandler!, true);
|
|
});
|
|
}
|
|
|
|
// If clicking same tool, just deactivate
|
|
if (this.currentHandler === tool.handleEvent.bind(tool)) {
|
|
this.currentHandler = null;
|
|
this.activeTool = null;
|
|
return;
|
|
}
|
|
|
|
// Activate new handler
|
|
this.currentHandler = tool.handleEvent.bind(tool);
|
|
tool.events.forEach((event) => {
|
|
this.addEventListener(event, this.currentHandler!, true);
|
|
});
|
|
|
|
// Add active class to new tool
|
|
tool.classList.add('active');
|
|
this.activeTool = tool;
|
|
}
|
|
|
|
static define() {
|
|
if (!customElements.get(this.tagName)) {
|
|
customElements.define(this.tagName, this);
|
|
}
|
|
}
|
|
}
|
|
|
|
FolkShapeTool.define();
|
|
FolkDeleteTool.define();
|
|
FolkToolset.define();
|