@teaui/core
Version:
A high-level terminal UI library for Node
99 lines • 3.15 kB
JavaScript
import { Container } from '../Container.js';
import { Rect, Point, Size } from '../geometry.js';
/**
* Overlays children on top of each other. Each child receives the full
* available size. Children are rendered in order, so later children appear
* above earlier ones.
*
* When `align` is set, each child is positioned at the specified alignment
* within the available space, and the ZStack takes up all available space.
*/
export class ZStack extends Container {
#location;
constructor(props = {}) {
super(props);
this.#update(props);
}
get align() {
return this.#location;
}
set align(value) {
if (value === this.#location)
return;
this.#location = value;
this.invalidateSize();
}
update(props) {
this.#update(props);
super.update(props);
}
#update({ location: align }) {
this.#location = align;
}
naturalSize(available) {
if (this.#location !== undefined) {
return available;
}
const size = Size.zero.mutableCopy();
for (const child of this.children) {
if (!child.isVisible)
continue;
const childSize = child.naturalSize(available);
size.width = Math.max(size.width, childSize.width);
size.height = Math.max(size.height, childSize.height);
}
return size;
}
render(viewport) {
if (viewport.isEmpty) {
return super.render(viewport);
}
if (this.#location !== undefined) {
for (const child of this.children) {
if (!child.isVisible)
continue;
const childSize = child
.naturalSize(viewport.contentSize)
.max(viewport.contentSize);
const origin = computeOrigin(this.#location, viewport.contentSize, childSize);
viewport.clipped(new Rect(origin, childSize), inside => {
child.render(inside);
});
}
}
else {
for (const child of this.children) {
if (!child.isVisible)
continue;
child.render(viewport);
}
}
}
}
function computeOrigin(align, available, childSize) {
let x, y;
// horizontal
if (align === 'top-left' || align === 'left' || align === 'bottom-left') {
x = 0;
}
else if (align === 'top-center' ||
align === 'center' ||
align === 'bottom-center') {
x = Math.round((available.width - childSize.width) / 2);
}
else {
x = available.width - childSize.width;
}
// vertical
if (align === 'top-left' || align === 'top-center' || align === 'top-right') {
y = 0;
}
else if (align === 'left' || align === 'center' || align === 'right') {
y = Math.round((available.height - childSize.height) / 2);
}
else {
y = available.height - childSize.height;
}
return new Point(Math.max(0, x), Math.max(0, y));
}
//# sourceMappingURL=ZStack.js.map