Skip to content

Commit 28c29a5

Browse files
sasial-devlittensy
andauthored
feat: add useSpring hook (#16)
* feat: add `useSpring` hook * fix: apply review commments * refactor: use props param --------- Co-authored-by: richard <56808540+littensy@users.noreply.github.com>
1 parent 2f19297 commit 28c29a5

File tree

5 files changed

+72
-0
lines changed

5 files changed

+72
-0
lines changed

src/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ export * from "./use-motion";
2626
export * from "./use-mount-effect";
2727
export * from "./use-mouse";
2828
export * from "./use-previous";
29+
export * from "./use-spring";
2930
export * from "./use-tagged";
3031
export * from "./use-throttle-callback";
3132
export * from "./use-throttle-effect";

src/use-spring/README.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
## 🪝 `useSpring`
2+
3+
```ts
4+
function useSpring<T extends MotionGoal>(goal: T | Binding<T>, options?: SpringOptions): Binding<T>
5+
```
6+
7+
Applies spring animations to the given value, and updates the goal with the latest value on every re-render. Returns a binding that updates with the Motion.
8+
9+
### 📕 Parameters
10+
11+
- `goal` - The goal of the motor.
12+
- `options` - Options for the spring (or a spring config).
13+
14+
### 📗 Returns
15+
16+
- A binding of the motor's value.
17+
18+
### 📘 Example
19+
20+
A button changes to the colour of its props.
21+
22+
```tsx
23+
function Button({ color }: Props) {
24+
const color = useSpring(color, config.spring.stiff);
25+
26+
return (
27+
<textbutton Size={new UDim2(0, 100, 0, 100)} BackgroundColor3={color} />
28+
);
29+
}
30+
```

src/use-spring/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export * from "./use-spring";

src/use-spring/use-spring.spec.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
/// <reference types="@rbxts/testez/globals" />
2+
3+
import { renderHook } from "../utils/testez";
4+
import { useSpring } from "./use-spring";
5+
6+
export = () => {
7+
it("should return a binding", () => {
8+
const { result, unmount } = renderHook(() => useSpring(0));
9+
10+
expect(result.current.getValue()).to.be.a("number");
11+
expect(result.current.getValue()).to.equal(0);
12+
13+
unmount();
14+
});
15+
};

src/use-spring/use-spring.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import type { Binding } from "@rbxts/react";
2+
import { useRef } from "@rbxts/react";
3+
import type { MotionGoal, SpringOptions } from "@rbxts/ripple";
4+
import { useMotion } from "../use-motion";
5+
import { getBindingValue } from "../utils/binding";
6+
import { useEventListener } from "../use-event-listener";
7+
import { RunService } from "@rbxts/services";
8+
9+
export function useSpring(goal: number | Binding<number>, options?: SpringOptions): Binding<number>;
10+
export function useSpring<T extends MotionGoal>(goal: T | Binding<T>, options?: SpringOptions): Binding<T>;
11+
export function useSpring(goal: MotionGoal | Binding<MotionGoal>, options?: SpringOptions) {
12+
const [binding, motion] = useMotion(getBindingValue(goal));
13+
const previousValue = useRef(getBindingValue(goal));
14+
15+
useEventListener(RunService.Heartbeat, () => {
16+
const currentValue = getBindingValue(goal);
17+
18+
if (currentValue !== previousValue.current) {
19+
previousValue.current = currentValue;
20+
motion.spring(currentValue, options);
21+
}
22+
});
23+
24+
return binding;
25+
}

0 commit comments

Comments
 (0)