You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
132 lines
3.0 KiB
132 lines
3.0 KiB
import "./Blob.sass";
|
|
|
|
import {WithChildren} from "../Shared";
|
|
import {CSSProperties, useCallback, useMemo} from "react";
|
|
import {Size} from "../../models/Shared";
|
|
|
|
interface BlobProps extends WithChildren {
|
|
onClick?: () => void
|
|
disabled?: boolean
|
|
fillOn?: Size
|
|
flex?: number
|
|
color?: "gray" | "green" | "blue" | "red" | "yellow" | "indigo"
|
|
}
|
|
|
|
function Blob({onClick, fillOn, disabled, flex, color, children}: BlobProps) {
|
|
const style: CSSProperties = useMemo(() => {
|
|
return flex ? {flex} : {};
|
|
}, [flex]);
|
|
const classNames = useMemo(() => {
|
|
const val = ["Blob"];
|
|
if (onClick !== undefined && !disabled) {
|
|
val.push("Blob-clickable")
|
|
}
|
|
if (fillOn) {
|
|
val.push(`Blob-fill-on-${fillOn}`);
|
|
}
|
|
val.push(`Blob-${color || "gray"}`)
|
|
|
|
return val;
|
|
}, [onClick, fillOn, disabled, color]);
|
|
|
|
return (
|
|
<div style={style} className={classNames.join(" ")} onClick={disabled ? undefined : onClick}>
|
|
<div className="Blob-body">
|
|
{children}
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
interface BlobTextProps extends WithChildren {
|
|
centered?: boolean
|
|
flex?: number
|
|
}
|
|
|
|
export function BlobText({centered, children, flex}: BlobTextProps) {
|
|
const clazz = useMemo(() => {
|
|
const classNames = ["BlobText"];
|
|
if (centered) {
|
|
classNames.push("BlobText-centered");
|
|
}
|
|
|
|
return classNames.join(" ");
|
|
}, [centered]);
|
|
|
|
return (
|
|
<div className={clazz} style={{flex}}>
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
interface BlobTextLineProps extends WithChildren {
|
|
secondary?: boolean
|
|
flex?: number
|
|
}
|
|
|
|
export function BlobTextLine({secondary, flex, children}: BlobTextLineProps) {
|
|
const clazz = useMemo(() => {
|
|
const classNames = ["BlobTextLine"];
|
|
if (secondary) {
|
|
classNames.push("BlobTextLine-secondary");
|
|
}
|
|
|
|
return classNames.join(" ");
|
|
}, [secondary]);
|
|
|
|
return (
|
|
<div className={clazz} style={{flex}}>
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
type BlobInputProps =
|
|
| BaseBlobInputProps<"number", number>
|
|
| BaseBlobInputProps<"text" | "password" | undefined, string>
|
|
|
|
interface BaseBlobInputProps<T, V> {
|
|
type: T
|
|
name?: string
|
|
flex?: number
|
|
value: V
|
|
disabled?: boolean
|
|
onChange?: (newValue: V) => void
|
|
placeholder?: string
|
|
}
|
|
|
|
export function BlobInput({type, name, flex, disabled, value, onChange, placeholder}: BlobInputProps) {
|
|
const actualOnChange = useCallback((input: string) => {
|
|
if (onChange === undefined) return;
|
|
|
|
if (type === "number") {
|
|
onChange(parseInt(input, 10) || 0);
|
|
} else {
|
|
onChange(input);
|
|
}
|
|
}, [onChange]);
|
|
|
|
return (
|
|
<input
|
|
placeholder={placeholder}
|
|
disabled={disabled}
|
|
className="BlobInput"
|
|
name={name}
|
|
type={type || "text"}
|
|
value={`${value || ""}`}
|
|
style={flex ? {flex} : {width: 50}}
|
|
onChange={e => actualOnChange(e.target.value || "")}
|
|
/>
|
|
);
|
|
}
|
|
|
|
export function BlobGroup({children}: WithChildren) {
|
|
return (
|
|
<div className="BlobGroup">
|
|
{children}
|
|
</div>
|
|
);
|
|
}
|
|
|
|
export default Blob;
|