JSFiddle - React, Tailwind, and code Playground
by Nicholas Berlette
TypeScript
export interface Position {
x: number;
y: number;
z?: number;
}
export interface Size {
width: number;
height: number;
}
export interface HistoryEntry { position: Position; size: Size }
class NWindow extends HTMLElement {
protected _isMinimized = false;
protected _isMaximized = false;
protected _isDragging = false;
protected _isResizing = false;
protected _fullscreen = false;
protected _resizable = true;
protected _zIndex = 1;
protected _position: Position = { x: 0, y: 0 };
protected _size: Size = { width: 600, height: 400 };
protected _stateHistory: HistoryEntry[] = [];
get isMinimized() {
return this._isMinimized;
}
get id() {
return this.getAttribute('id') || '';
}
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
this.render();
this.setupEventListeners();
}
updateSize() {
this.style.width = `${this._size.width}px`;
this.style.height = `${this._size.height}px`;
}
getZIndex(): number {
const z = parseInt(this.style.zIndex ?? "0");
return this._zIndex = isFinite(z) ? z : this._zIndex;
}
setZIndex(zIndex: number) {
this._zIndex = zIndex;
this.style.zIndex = zIndex.toString();
return this;
}
render() {
if (!this.shadowRoot) return;
this.shadowRoot.innerHTML = `
<style>
:host {
display: ${this._isMinimized ? 'none' : 'block'};
position: absolute;
left: ${this._position.x}px;
top: ${this._position.y}px;
width: ${this._size.width}px;
height: ${this._size.height}px;
z-index: ${this._zIndex};
background: white;
border-radius: 8px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
overflow: hidden;
}
.title-bar {
display: flex;
justify-content: space-between;
align-items: center;
padding: 8px;
background: #f0f0f0;
...