Created
June 28, 2023 21:49
-
-
Save littensy/8ecfc2ebd9a6fe737be66e54912665bd to your computer and use it in GitHub Desktop.
Border component for Roact Hooked
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { joinAnyBindings, mapBinding } from "@rbxts/pretty-roact-hooks"; | |
import Roact from "@rbxts/roact"; | |
import { useMemo } from "@rbxts/roact-hooked"; | |
import { roundEven } from "client/utils/number-utils"; | |
import { Frame } from "./frame"; | |
interface BorderProps extends Roact.PropsWithChildren { | |
borderMode?: BorderMode; | |
borderColor?: Color3 | Roact.Binding<Color3>; | |
borderThickness?: number | Roact.Binding<number>; | |
borderTransparency?: number | Roact.Binding<number>; | |
borderRadius?: UDim | Roact.Binding<UDim>; | |
} | |
export type BorderMode = "inside" | "outside" | "center"; | |
export function Border({ | |
borderMode = "outside", | |
borderColor = Color3.fromRGB(255, 255, 255), | |
borderThickness = 1, | |
borderTransparency = 0, | |
borderRadius = new UDim(), | |
[Roact.Children]: children, | |
}: BorderProps) { | |
const borderOffset = useMemo(() => { | |
// By default, all UIStroke effects are outer borders. To center or make | |
// an inner border, we need to offset the border by half the thickness. | |
if (borderMode === "outside") { | |
return new UDim2(1, 0, 1, 0); | |
} else if (borderMode === "inside") { | |
return mapBinding(borderThickness, (px) => new UDim2(1, roundEven(-2 * px), 1, roundEven(-2 * px))); | |
} else if (borderMode === "center") { | |
return mapBinding(borderThickness, (px) => new UDim2(1, roundEven(-px), 1, roundEven(-px))); | |
} | |
}, [borderThickness, borderMode]); | |
const borderCornerRadius = useMemo(() => { | |
const binding = joinAnyBindings([borderRadius, borderThickness] as const); | |
// Offsetting the border container means that the corner size will not | |
// match up with the container's corner size. To fix this, we need to | |
// adjust the corner size by the offset. | |
if (borderMode === "outside") { | |
return borderRadius; | |
} else if (borderMode === "inside") { | |
return binding.map(([radius, thickness]) => radius.sub(new UDim(0, thickness))); | |
} else if (borderMode === "center") { | |
return binding.map(([radius, thickness]) => radius.sub(new UDim(0, thickness))); | |
} | |
}, [borderRadius, borderThickness, borderMode]); | |
return ( | |
<Frame | |
anchorPoint={new Vector2(0.5, 0.5)} | |
size={borderOffset} | |
position={new UDim2(0.5, 0, 0.5, 0)} | |
cornerRadius={borderCornerRadius} | |
backgroundTransparency={1} | |
> | |
<uistroke Color={borderColor} Transparency={borderTransparency} Thickness={borderThickness}> | |
{children} | |
</uistroke> | |
</Frame> | |
); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment