@wonderlandengine/react-ui
Version:
React-based UI in Wonderland Engine.
84 lines (83 loc) • 4.71 kB
JavaScript
import React, { createContext, forwardRef, useContext, useMemo, useState, } from 'react';
import { FlexDirection, Align, PositionType, } from './renderer.js';
import { parseColor } from './utils.js';
export const MaterialContext = createContext({});
export const ThemeContext = createContext({});
const tempColor = new Float32Array(4);
export const Container = forwardRef((props, ref) => {
return (React.createElement("container", { ...props, ref: ref }, props.children));
});
Container.displayName = 'Container';
export const Panel = forwardRef((props, ref) => {
const context = useContext(MaterialContext);
const mat = useMemo(() => context.panelMaterial?.clone(), []);
mat &&
mat.setColor(parseColor(props.backgroundColor ?? 'fff', tempColor));
const bmat = useMemo(() => context.panelMaterial?.clone(), []);
bmat &&
bmat.setColor(parseColor(props.borderColor ?? 'fff', tempColor));
return (React.createElement("roundedRectangle", { ...props, material: props.material ?? mat, borderMaterial: props.borderMaterial ?? bmat, ref: ref }, props.children));
});
Panel.displayName = 'Panel';
export const Panel9Slice = forwardRef((props, ref) => {
const context = useContext(MaterialContext);
const mat = useMemo(() => context.panelMaterialTextured?.clone(), []);
if (mat && props.texture)
mat.flatTexture = props.texture;
return (React.createElement("nineSlice", { ...props, material: props.material ?? mat, ref: ref }, props.children));
});
Panel9Slice.displayName = 'Panel9Slice';
export const Image = forwardRef((props, ref) => {
const context = useContext(MaterialContext);
const mat = props.material ?? useMemo(() => context.panelMaterialTextured?.clone(), []);
const texture = typeof props.src === 'string'
? useMemo(() => mat.engine.textures.load(props.src), [props.src])
: Promise.resolve(props.src);
texture.then((t) => (mat.flatTexture = t));
return (React.createElement(Panel, { ...props, material: mat, ref: ref }, props.children));
});
Image.displayName = 'Image';
export const Plane = forwardRef((props, ref) => {
return (React.createElement("mesh", { ...props, ref: ref }, props.children));
});
Plane.displayName = 'Plane';
export const Column = forwardRef((props, ref) => {
return (React.createElement(Container, { flexDirection: FlexDirection.Column, ...props, ref: ref }, props.children));
});
Column.displayName = 'Column';
export const Row = forwardRef((props, ref) => {
return (React.createElement(Container, { flexDirection: FlexDirection.Row, ...props, ref: ref }, props.children));
});
Row.displayName = 'Row';
export const Text = forwardRef((props, ref) => {
const context = useContext(MaterialContext);
const theme = useContext(ThemeContext);
const mat = props.material ?? useMemo(() => context.textMaterial?.clone(), []);
if (mat) {
mat.setColor(parseColor(props.color ??
theme.colors?.text ??
(props.material ?? context.textMaterial)
.color, tempColor));
}
return (React.createElement("text3d", { ...props, text: props.children?.toString() ?? props.text, material: mat, ref: ref }));
});
Text.displayName = 'Text';
export const Button = forwardRef((props, ref) => {
const [hovered, setHovered] = useState(false);
const [active, setActive] = useState(false);
let propsMerged = {
...props,
...(hovered ? props.hovered : undefined),
...(active ? props.active : undefined),
};
return (React.createElement(Panel, { ...propsMerged, onHover: () => setHovered(true), onUnhover: () => setHovered(false), onDown: () => setActive(true), onUp: () => setActive(false), ref: ref }, props.children));
});
Button.displayName = 'Button';
export const ProgressBar = forwardRef((props, ref) => {
const rounding = props.rounding ?? 30;
const value = Math.max(Math.min(1, props.value), 0); // clamp between 0 and 1
return (React.createElement(Panel, { material: props.bgMaterial, backgroundColor: props.bgColor, ...props, flexDirection: FlexDirection.Row, padding: props.padding ?? 6, paddingLeft: props.paddingLeft ?? 8, paddingRight: props.paddingRight ?? 8, resolution: 6, rounding: rounding * 1.5, ref: ref },
React.createElement(Container, { alignItems: Align.FlexStart, position: PositionType.Absolute, width: "100%", height: "100%", left: props.barLeftMargin ?? 12 }, props.children),
React.createElement(Panel, { width: `${100 * value}%`, minWidth: rounding * 2, height: "100%", material: props.fgMaterial, backgroundColor: props.fgColor, alignItems: Align.Center, rounding: rounding })));
});
ProgressBar.displayName = 'ProgressBar';