diff --git a/readme.md b/readme.md
index 4bccada..189d86a 100644
--- a/readme.md
+++ b/readme.md
@@ -17,6 +17,7 @@ I should put this in the game sometime, but the option to open the configuration
# Todo
* Better null checking for the clientState.character (can cause errors atm)
+* Swap to pretty-roact-hooks
* Custom player list
* Custom chat
* Add guns
diff --git a/src/ReplicatedStorage/ui/components/canvas.tsx b/src/ReplicatedStorage/ui/components/canvas.tsx
new file mode 100644
index 0000000..47f4151
--- /dev/null
+++ b/src/ReplicatedStorage/ui/components/canvas.tsx
@@ -0,0 +1,59 @@
+import Roact from "@rbxts/roact"
+import { BindingOrValue, mapBinding } from "ReplicatedStorage/utils/bindingUtil"
+
+interface canvasProps extends Roact.JsxInstanceProperties {
+ size?: BindingOrValue
+ position?: BindingOrValue
+ anchor?: Vector2
+ padding?: {
+ top?: BindingOrValue
+ right?: BindingOrValue
+ bottom?: BindingOrValue
+ left?: BindingOrValue
+ }
+ clipsDescendants?: boolean
+ zIndex?: number
+ [Roact.Children]?: Roact.Children
+
+ Event?: Roact.JsxInstanceEvents
+ Change?: Roact.JsxInstanceChangeEvents
+}
+
+function canvas(props: canvasProps): Roact.Element {
+ const { size, position, anchor, padding, clipsDescendants, zIndex } = props
+
+ const spreadableProps = { ...props } as Partial
+ delete spreadableProps.size
+ delete spreadableProps.position
+ delete spreadableProps.anchor
+ delete spreadableProps.padding
+ delete spreadableProps.clipsDescendants
+ delete spreadableProps.zIndex
+ delete spreadableProps[Roact.Children]
+
+ return (
+
+ {padding !== undefined && (
+ new UDim(0, px))}
+ PaddingRight={mapBinding(padding.right, (px) => new UDim(0, px))}
+ PaddingBottom={mapBinding(padding.bottom, (px) => new UDim(0, px))}
+ PaddingLeft={mapBinding(padding.left, (px) => new UDim(0, px))}
+ />
+ )}
+
+ {props[Roact.Children]}
+
+ )
+}
+
+export default canvas
\ No newline at end of file
diff --git a/src/ReplicatedStorage/ui/components/fill.tsx b/src/ReplicatedStorage/ui/components/fill.tsx
new file mode 100644
index 0000000..4e2e274
--- /dev/null
+++ b/src/ReplicatedStorage/ui/components/fill.tsx
@@ -0,0 +1,42 @@
+import Roact from "@rbxts/roact"
+import { BindingOrValue, mapBinding } from "ReplicatedStorage/utils/bindingUtil"
+
+interface fillProps extends Roact.JsxInstanceProperties {
+ color?: BindingOrValue
+ transparency?: BindingOrValue
+ radius?: BindingOrValue
+ [Roact.Children]?: Roact.Children
+
+ Event?: Roact.JsxInstanceEvents
+ Change?: Roact.JsxInstanceChangeEvents
+}
+
+function fill(props: fillProps): Roact.Element {
+ const { color, transparency, radius } = props
+
+ const spreadableProps = { ...props } as Partial
+ delete spreadableProps.color
+ delete spreadableProps.transparency
+ delete spreadableProps.radius
+ delete spreadableProps[Roact.Children]
+
+ return (
+
+ {radius !== undefined && (
+ (r === "circular" ? new UDim(1, 0) : new UDim(0, r)))}
+ />
+ )}
+
+ {props[Roact.Children]}
+
+ )
+}
+
+export default fill
\ No newline at end of file
diff --git a/src/ReplicatedStorage/ui/components/padding.tsx b/src/ReplicatedStorage/ui/components/padding.tsx
deleted file mode 100644
index 402d2cf..0000000
--- a/src/ReplicatedStorage/ui/components/padding.tsx
+++ /dev/null
@@ -1,31 +0,0 @@
-import Roact from "@rbxts/roact"
-
-interface paddingProps extends Roact.JsxInstanceProperties {
- padding?: UDim | Roact.Binding
- paddingX?: UDim | Roact.Binding
- paddingY?: UDim | Roact.Binding
-
- Event?: Roact.JsxInstanceEvents
- Change?: Roact.JsxInstanceChangeEvents
-}
-
-function padding(props: paddingProps): Roact.Element {
- const { padding, paddingX, paddingY } = props
-
- const spreadableProps = { ...props } as Partial
- delete spreadableProps.padding
- delete spreadableProps.paddingX
- delete spreadableProps.paddingY
-
- return (
-
- )
-}
-
-export default padding
\ No newline at end of file
diff --git a/src/ReplicatedStorage/ui/components/surface.tsx b/src/ReplicatedStorage/ui/components/surface.tsx
new file mode 100644
index 0000000..25f2a8f
--- /dev/null
+++ b/src/ReplicatedStorage/ui/components/surface.tsx
@@ -0,0 +1,70 @@
+import Roact from "@rbxts/roact"
+import Canvas from "./canvas"
+import Acrylic from "./acrylic"
+import Fill from "./fill"
+import { BindingOrValue } from "ReplicatedStorage/utils/bindingUtil"
+
+interface surfaceProps extends Roact.JsxInstanceProperties {
+ size: BindingOrValue
+ position: BindingOrValue
+ ratio?: BindingOrValue
+ color?: BindingOrValue
+ blur?: BindingOrValue
+ [Roact.Children]?: Roact.Children
+
+ Event?: Roact.JsxInstanceEvents
+ Change?: Roact.JsxInstanceChangeEvents
+}
+
+function surface(props: surfaceProps): Roact.Element {
+ const { size, position, ratio, color, blur } = props
+
+ const spreadableProps = { ...props } as Partial
+ delete spreadableProps.size
+ delete spreadableProps.position
+ delete spreadableProps.ratio
+ delete spreadableProps.color
+ delete spreadableProps.blur
+ delete spreadableProps[Roact.Children]
+
+ return (
+
+ )
+}
+
+export default surface
\ No newline at end of file
diff --git a/src/ReplicatedStorage/ui/components/text.tsx b/src/ReplicatedStorage/ui/components/text.tsx
new file mode 100644
index 0000000..8403910
--- /dev/null
+++ b/src/ReplicatedStorage/ui/components/text.tsx
@@ -0,0 +1,40 @@
+import Roact from "@rbxts/roact"
+
+interface textProps extends Roact.JsxInstanceProperties {
+ bold?: boolean
+ paddingX?: UDim
+ paddingY?: UDim
+
+ Event?: Roact.JsxInstanceEvents
+ Change?: Roact.JsxInstanceChangeEvents
+}
+
+function text(props: textProps): Roact.Element {
+ const { bold, paddingX, paddingY, Text, TextXAlignment } = props
+
+ const spreadableProps = { ...props } as Partial
+ delete spreadableProps.bold
+ delete spreadableProps.paddingX
+ delete spreadableProps.paddingY
+
+ return (
+
+
+
+ )
+}
+
+export default text
\ No newline at end of file
diff --git a/src/ReplicatedStorage/ui/components/toggleButton.tsx b/src/ReplicatedStorage/ui/components/toggleButton.tsx
deleted file mode 100644
index 44ac02b..0000000
--- a/src/ReplicatedStorage/ui/components/toggleButton.tsx
+++ /dev/null
@@ -1,73 +0,0 @@
-import Roact from "@rbxts/roact"
-import Padding from "ReplicatedStorage/ui/components/padding"
-import { Spring } from "@rbxts/flipper"
-import { useGroupMotor } from "@rbxts/roact-hooked-plus"
-
-interface toggleButtonProps extends Roact.JsxInstanceProperties {
- active: boolean
- enableCallback: () => void
- disableCallback: () => void
-
- Event?: Roact.JsxInstanceEvents
- Change?: Roact.JsxInstanceChangeEvents
-}
-
-const BUTTON_DEFAULT = [new Spring(0, { frequency: 6 })]
-const BUTTON_ACTIVE = [new Spring(1, { frequency: 6 })]
-
-function toggleButton(props: toggleButtonProps): Roact.Element {
- let { active } = props
- const { enableCallback, disableCallback, Text } = props
-
- const spreadableProps = { ...props } as Partial
- delete spreadableProps.active
- delete spreadableProps.enableCallback
- delete spreadableProps.disableCallback
-
- const [buttonBorderColorMap, setButtonGoal] = useGroupMotor([0])
- const buttonBorderColor = buttonBorderColorMap.map((t) => t[0]).map((val) => {
- return Color3.fromHex("#6c7086").Lerp(Color3.fromHex("#b4befe"), val)
- })
-
- return (
- {
- active = !active
- if (active) {
- setButtonGoal(BUTTON_ACTIVE)
- enableCallback()
- } else {
- setButtonGoal(BUTTON_DEFAULT)
- disableCallback()
- }
- }
- }}
- >
-
-
-
-
- )
-}
-
-export default toggleButton
\ No newline at end of file
diff --git a/src/ReplicatedStorage/ui/store/producer/config.ts b/src/ReplicatedStorage/ui/store/producer/config.ts
index 220eec8..d0f997f 100644
--- a/src/ReplicatedStorage/ui/store/producer/config.ts
+++ b/src/ReplicatedStorage/ui/store/producer/config.ts
@@ -9,13 +9,8 @@ const initialState: ConfigState = {
}
export const configProducer = createProducer(initialState, {
- enableAcrylic: (state) => ({
+ toggleConfig: (state, action: keyof ConfigState) => ({
...state,
- acrylicBlur: true
- }),
-
- disableAcrylic: (state) => ({
- ...state,
- acrylicBlur: false
+ [action]: !state[action]
})
})
\ No newline at end of file
diff --git a/src/ReplicatedStorage/utils/bindingUtil.ts b/src/ReplicatedStorage/utils/bindingUtil.ts
new file mode 100644
index 0000000..36a479f
--- /dev/null
+++ b/src/ReplicatedStorage/utils/bindingUtil.ts
@@ -0,0 +1,15 @@
+import Roact from "@rbxts/roact"
+
+export type BindingOrValue = T | Roact.Binding
+
+export function isBinding(binding: unknown): binding is Roact.Binding {
+ return typeIs(binding, "table") && "getValue" in binding
+}
+
+export function mapBinding(value: BindingOrValue, transform: (value: T) => U): Roact.Binding {
+ return isBinding(value) ? value.map(transform) : Roact.createBinding(transform(value))[0]
+}
+
+export function asBinding(value: BindingOrValue): Roact.Binding {
+ return isBinding(value) ? value : Roact.createBinding(value)[0]
+}
\ No newline at end of file
diff --git a/src/StarterPlayer/StarterPlayerScripts/ui/config/config.tsx b/src/StarterPlayer/StarterPlayerScripts/ui/config/config.tsx
index fb046f0..d1f6138 100644
--- a/src/StarterPlayer/StarterPlayerScripts/ui/config/config.tsx
+++ b/src/StarterPlayer/StarterPlayerScripts/ui/config/config.tsx
@@ -1,12 +1,10 @@
import Roact from "@rbxts/roact"
-import Padding from "ReplicatedStorage/ui/components/padding"
import Acrylic from "ReplicatedStorage/ui/components/acrylic"
-import ToggleButton from "ReplicatedStorage/ui/components/toggleButton"
import { ContextActionService, HttpService } from "@rbxts/services"
import { Spring } from "@rbxts/flipper"
import { useGroupMotor } from "@rbxts/roact-hooked-plus"
import { useEffect } from "@rbxts/roact-hooked"
-import { useRootProducer } from "ReplicatedStorage/ui/store/hooks/useUiProducer"
+import Item from "./item"
interface ConfigProps extends Roact.JsxInstanceProperties {
shown: boolean
@@ -19,8 +17,6 @@ const CONFIG_DEFAULT = [new Spring(1.5, { frequency: 6 }), new Spring(0, { frequ
const CONFIG_ACTIVE = [new Spring(.5, { frequency: 6 }), new Spring(1, { frequency: 6 })]
function config(props: ConfigProps): Roact.Element {
- const { disableAcrylic, enableAcrylic } = useRootProducer()
-
let { shown } = props
const spreadableProps = { ...props } as Partial
@@ -88,14 +84,11 @@ function config(props: ConfigProps): Roact.Element {
Thickness={1}
Color={configBorderColor}
/>
-
-
diff --git a/src/StarterPlayer/StarterPlayerScripts/ui/config/item.story.tsx b/src/StarterPlayer/StarterPlayerScripts/ui/config/item.story.tsx
new file mode 100644
index 0000000..015afb4
--- /dev/null
+++ b/src/StarterPlayer/StarterPlayerScripts/ui/config/item.story.tsx
@@ -0,0 +1,25 @@
+import Roact from "@rbxts/roact"
+import { withHookDetection } from "@rbxts/roact-hooked"
+import { ReflexProvider, useSelector } from "@rbxts/roact-reflex"
+import { producer } from "ReplicatedStorage/ui/store/producer"
+import Item from "./item"
+
+export = (target: Frame) => {
+ withHookDetection(Roact)
+
+ const tree = Roact.mount(
+
+
+ ,
+ target
+ )
+
+ return () => {
+ Roact.unmount(tree)
+ }
+}
\ No newline at end of file
diff --git a/src/StarterPlayer/StarterPlayerScripts/ui/config/item.tsx b/src/StarterPlayer/StarterPlayerScripts/ui/config/item.tsx
new file mode 100644
index 0000000..bb7fdf5
--- /dev/null
+++ b/src/StarterPlayer/StarterPlayerScripts/ui/config/item.tsx
@@ -0,0 +1,54 @@
+import Roact from "@rbxts/roact"
+import Fill from "ReplicatedStorage/ui/components/fill"
+import Text from "ReplicatedStorage/ui/components/text"
+import Canvas from "ReplicatedStorage/ui/components/canvas"
+import { useRootProducer, useRootSelector } from "ReplicatedStorage/ui/store/hooks/useUiProducer"
+import { ConfigState } from "ReplicatedStorage/ui/store/producer/config"
+
+interface itemProps extends Roact.JsxInstanceProperties {
+ size: UDim2
+ position: UDim2
+ text: string
+ action: keyof ConfigState
+
+ Event?: Roact.JsxInstanceEvents
+ Change?: Roact.JsxInstanceChangeEvents
+}
+
+function item(props: itemProps): Roact.Element {
+ const { size, position, text, action } = props
+
+ const { toggleConfig } = useRootProducer()
+
+ const active = useRootSelector((state) => state.configProducer[action])
+
+ const spreadableProps = { ...props } as Partial
+ delete spreadableProps.size
+ delete spreadableProps.position
+ delete spreadableProps.text
+ delete spreadableProps.action
+
+ return (
+
+
+
+
+ toggleConfig(action)
+ }}
+ Size={new UDim2(1, 0, 1, 0)}
+ Transparency={1}
+ Text={""}
+ />
+
+ )
+}
+
+export default item
\ No newline at end of file
diff --git a/src/StarterPlayer/StarterPlayerScripts/ui/hotbar/hotbar.tsx b/src/StarterPlayer/StarterPlayerScripts/ui/hotbar/hotbar.tsx
index b196570..a27cda5 100644
--- a/src/StarterPlayer/StarterPlayerScripts/ui/hotbar/hotbar.tsx
+++ b/src/StarterPlayer/StarterPlayerScripts/ui/hotbar/hotbar.tsx
@@ -1,7 +1,7 @@
import Roact from "@rbxts/roact"
import Slot from "./slot"
import { useWorldContext } from "../contexts/worldContext"
-import Padding from "ReplicatedStorage/ui/components/padding"
+import Canvas from "ReplicatedStorage/ui/components/canvas"
import { StarterGui } from "@rbxts/services"
interface HotbarProps extends Roact.JsxInstanceProperties {
@@ -41,23 +41,17 @@ function hotbar(props: HotbarProps): Roact.Element {
})
return (
-
-
{...items}
-
+
)
}
diff --git a/src/StarterPlayer/StarterPlayerScripts/ui/hotbar/slot.tsx b/src/StarterPlayer/StarterPlayerScripts/ui/hotbar/slot.tsx
index fff7f6b..2b61e12 100644
--- a/src/StarterPlayer/StarterPlayerScripts/ui/hotbar/slot.tsx
+++ b/src/StarterPlayer/StarterPlayerScripts/ui/hotbar/slot.tsx
@@ -2,8 +2,8 @@ import Roact from "@rbxts/roact"
import { useEffect } from "@rbxts/roact-hooked"
import { useWorldContext } from "../contexts/worldContext"
import { ContextActionService, HttpService } from "@rbxts/services"
-import Padding from "ReplicatedStorage/ui/components/padding"
-import Acrylic from "ReplicatedStorage/ui/components/acrylic"
+import Text from "ReplicatedStorage/ui/components/text"
+import Surface from "ReplicatedStorage/ui/components/surface"
import { Spring } from "@rbxts/flipper"
import { useGroupMotor } from "@rbxts/roact-hooked-plus"
@@ -28,9 +28,6 @@ function slot(props: SlotProps): Roact.Element {
delete spreadableProps.tool
const [slotBorderColorAndSlotRatio, setSlotGoal] = useGroupMotor([0, 6])
- const slotBorderColor = slotBorderColorAndSlotRatio.map((t) => t[0]).map((val) => {
- return Color3.fromHex("#6c7086").Lerp(Color3.fromHex("#b4befe"), val)
- })
const slotRatio = slotBorderColorAndSlotRatio.map((t) => t[1])
const { clientState } = useWorldContext()
@@ -63,49 +60,25 @@ function slot(props: SlotProps): Roact.Element {
})
return (
-
-
-
-
-
-
-
-
-
-
-
+
)
}
diff --git a/src/StarterPlayer/StarterPlayerScripts/ui/main.tsx b/src/StarterPlayer/StarterPlayerScripts/ui/main.tsx
index 755ea44..1522406 100644
--- a/src/StarterPlayer/StarterPlayerScripts/ui/main.tsx
+++ b/src/StarterPlayer/StarterPlayerScripts/ui/main.tsx
@@ -1,7 +1,8 @@
import Roact from "@rbxts/roact"
+import { withHookDetection } from "@rbxts/roact-hooked"
import Hotbar from "./hotbar/hotbar"
import Config from "./config/config"
-import { withHookDetection } from "@rbxts/roact-hooked"
+import Canvas from "ReplicatedStorage/ui/components/canvas"
interface MainProps extends Roact.JsxInstanceEvents {
Event?: Roact.JsxInstanceEvents
@@ -14,18 +15,28 @@ export default function main(props: MainProps): Roact.Element {
withHookDetection(Roact)
return (
-
-
-
+
+
+
+
+
)
}
\ No newline at end of file