JSFiddle - React, Tailwind, and code Playground
HTML
<div id="container">
</div>
<div id="controls">
<button id="add">Add Column</button>
<button id="remove">Remove Column</button>
<div>
<input type="range" id="padding" name="padding" min="0" max="16" value="8" />
<label for="padding">Padding</label>
</div>
<div>
<input type="checkbox" id="callUnobserve" name="callUnobserve" checked />
<label for="callUnobserve">Explicitly call unobserve()</label>
</div>
</div>
CSS
#controls > * {
font-family: system-ui, sans;
font-size: 16px;
}
#controls,
#controls > div {
margin-top: 8px;
}
#container {
display: block;
overflow: hidden;
position: relative;
width: 300px;
height: 150px;
resize: both;
}
.GridView {
position: absolute;
top: 8px; left: 8px; right: 8px; bottom: 8px;
}
JavaScript
let gridView;
let sColorIndex = 0;
let sResizeObserverMap = new Map();
let sResizeObserver = new ResizeObserver((entries) => {
for (let entry of entries) {
let view = sResizeObserverMap.get(entry.target);
if (!view) continue;
let width = entry.borderBoxSize[0].inlineSize;
let height = entry.borderBoxSize[0].blockSize;
view.layout({ x: 0, y: 0, width, height });
}
});
function sRequestLayout(view) {
sResizeObserverMap.set(view.element, view);
if (document.getElementById("callUnobserve").checked) {
sResizeObserver.unobserve(view.element);
}
sResizeObserver.observe(view.element);
}
class ColorView {
#frame;
constructor() {
this.element = document.createElement("div");
this.element.style.backgroundColor = ["#800000", "#008000", "#000080"][
sColorIndex
];
sColorIndex = ++sColorIndex % 3;
}
get frame() {
return this.#frame;
}
set frame(frame) {
this.#frame = frame;
let style = this.element.style;
style.position = "absolute";
style.left = frame.x + "px";
style.top = frame.y + "px";
style.width = frame.width + "px";
style.height = frame.height + "px";
}
}
class GridView {
#subviews = [];
constructor() {
this.element = document.createElement("div");
this.element.classList.add("GridView");
sRequestLayout(this);
}
layout(bounds) {
console.log(bounds);
let padding = parseInt(document.getElementById("padding").value, 10);
console.log(padding);
let count = this.#subviews.length;
let segments = [];
let totalPadding = padding * (count - 1);
let per = (bounds.width - totalPadding) / count;
let error = 0.0;
let currentX = bounds.x;
for (let i = 0; i < count; i++) {
let raw = per + error;
let rounded = Math.round(raw);
error = raw - rounded;
this.#subviews[i].frame = {
x:...