@pmndrs/uikit
Version:
Build performant 3D user interfaces with Three.js and yoga.
64 lines (63 loc) • 2.73 kB
JavaScript
import { computed, effect, Signal } from '@preact/signals-core';
import { computedInheritableProperty } from './properties/index.js';
export const percentageRegex = /(-?\d+(?:\.\d+)?)%/;
export function abortableEffect(fn, abortSignal) {
if (abortSignal.aborted) {
return;
}
const unsubscribe = effect(fn);
abortSignal.addEventListener('abort', unsubscribe);
}
export const alignmentXMap = { left: 0.5, center: 0, middle: 0, right: -0.5 };
export const alignmentYMap = { top: -0.5, center: 0, middle: 0, bottom: 0.5 };
export const alignmentZMap = { back: -0.5, center: 0, middle: 0, front: 0.5 };
/**
* calculates the offsetX, offsetY, and scale to fit content with size [aspectRatio, 1] inside
*/
export function fitNormalizedContentInside(offsetTarget, scaleTarget, size, paddingInset, borderInset, pixelSize, aspectRatio) {
if (size.value == null || paddingInset.value == null || borderInset.value == null) {
return;
}
const [width, height] = size.value;
const [pTop, pRight, pBottom, pLeft] = paddingInset.value;
const [bTop, bRight, bBottom, bLeft] = borderInset.value;
const topInset = pTop + bTop;
const rightInset = pRight + bRight;
const bottomInset = pBottom + bBottom;
const leftInset = pLeft + bLeft;
offsetTarget.set((leftInset - rightInset) * 0.5 * pixelSize, (bottomInset - topInset) * 0.5 * pixelSize, 0);
const innerWidth = width - leftInset - rightInset;
const innerHeight = height - topInset - bottomInset;
const flexRatio = innerWidth / innerHeight;
if (flexRatio > aspectRatio) {
scaleTarget.setScalar(innerHeight * pixelSize);
return;
}
scaleTarget.setScalar((innerWidth * pixelSize) / aspectRatio);
}
export function readReactive(value) {
return value instanceof Signal ? value.value : value;
}
export function createConditionalPropertyTranslator(condition) {
const signalMap = new Map();
return (properties, merged) => {
if (typeof properties != 'object') {
throw new Error(`Invalid properties "${properties}"`);
}
for (const key in properties) {
const value = properties[key];
if (value === undefined) {
return;
}
let result = signalMap.get(value);
if (result == null) {
signalMap.set(value, (result = computed(() => (condition() ? readReactive(value) : undefined))));
}
merged.add(key, result);
}
};
}
export function computedBorderInset(propertiesSignal, keys) {
const sizes = keys.map((key) => computedInheritableProperty(propertiesSignal, key, 0));
return computed(() => sizes.map((size) => size.value));
}