Resizable Experiment
by Nicholas Berlette
HTML
<div style="--width:300px;--height:300px;margin:100px auto;--bg:#eee;--stroke:#ff33aa;--stroke-width:2px;width:var(--width);height:var(--height);" id="box-1">
<v-handles data-label-id="box-1" backdrop="#789"></v-handles>
</div>
<script>
const $ = document.querySelectorAll.bind(document);
const VARIABLES_CSS = getVariablesCss();
const isFixed = elem => {
do {
if (window.getComputedStyle(elem).position == 'fixed') return true;
} while (elem = elem.offsetParent);
return false;
};
// <v-handle />
window.Handle = class Handle extends HTMLElement {
constructor() {
super();
this.$shadow = this.attachShadow({
mode: 'closed'
});
this.styles = [Handle.styles];
this.hooks = {
button: ['pointerdown', this.on_element_resize_start.bind(this)]
};
}
get styles() {
return this._styles || (this.styles = Handle.styles);
}
set styles(value) {
(this._styles ??= new CSSStyleSheet()).replaceSync([value].flat(2));
if (this.$shadow) {
this.$shadow.adoptedStyleSheets = [this._styles];
}
}
connectedCallback() {
this.$connected = true;
this.render();
this.button = this.$shadow.querySelector('button');
for (const key in this.hooks) {
if (!(key in this)) continue;
const [event, listener] = this.hooks[key];
this[key].addEventListener(event, listener);
}
this.placement = this.getAttribute('placement');
}
attributeChangedCallback(name, oldValue, newValue) {
if (oldValue !== newValue) {
if (name === 'placement') this.placement = newValue;
if (name === 'styles') this.styles = newValue;
this.render();
}
}
disconnectedCallback() {
this.$connected = false;
for (const key in this.hooks) {
if (!(key in this)) continue;
const [event, listener] = this.hooks[key];
this[key].removeEventListener(event,...