import * as Phaser from 'phaser'; // DOM-overlay text input. Positions a real element above the canvas // using the scene's scale so it lines up with where you'd draw it in Phaser. export class TextInput { constructor(scene, x, y, options = {}) { this.scene = scene; this.gameX = x; this.gameY = y; this.width = options.width ?? 360; this.height = options.height ?? 48; this.layer = document.getElementById('dom-layer'); const isTextarea = options.multiline === true; this.el = document.createElement(isTextarea ? 'textarea' : 'input'); if (!isTextarea) this.el.type = options.type ?? 'text'; if (options.placeholder) this.el.placeholder = options.placeholder; if (options.value !== undefined) this.el.value = options.value; if (options.maxLength) this.el.maxLength = options.maxLength; if (options.autocomplete) this.el.autocomplete = options.autocomplete; this.el.style.position = 'absolute'; this.el.style.boxSizing = 'border-box'; this.layer.appendChild(this.el); this.reposition = this.reposition.bind(this); this.scene.scale.on('resize', this.reposition); this.reposition(); this.scene.events.once(Phaser.Scenes.Events.SHUTDOWN, () => this.destroy()); this.scene.events.once(Phaser.Scenes.Events.DESTROY, () => this.destroy()); } reposition() { const cam = this.scene.cameras.main; const zoom = this.scene.scale.displayScale; // {x, y} canvas-to-css scale const canvas = this.scene.scale.canvas; const rect = canvas.getBoundingClientRect(); const cssX = rect.left + (this.gameX - this.width / 2) / zoom.x; const cssY = rect.top + (this.gameY - this.height / 2) / zoom.y; const cssW = this.width / zoom.x; const cssH = this.height / zoom.y; this.el.style.left = `${cssX}px`; this.el.style.top = `${cssY}px`; this.el.style.width = `${cssW}px`; this.el.style.height = `${cssH}px`; this.el.style.fontSize = `${20 / zoom.y}px`; // Avoid unused-variable lint complaints void cam; } get value() { return this.el.value; } set value(v) { this.el.value = v; } focus() { this.el.focus(); } on(event, handler) { this.el.addEventListener(event, handler); return this; } destroy() { this.scene.scale.off('resize', this.reposition); this.el.remove(); } }