Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
@@ -1 +1 @@
# Roact-Flow
# React-Flow
2 changes: 1 addition & 1 deletion default.project.json
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
{
"name": "roact-flow",
"name": "react-flow",
"tree": {
"$path": "src"
}
Expand Down
78 changes: 0 additions & 78 deletions src/Animation.lua

This file was deleted.

14 changes: 14 additions & 0 deletions src/Animations/Base.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
local BaseAnimation = {}

function BaseAnimation.new()
local self = {}

self.listener = nil
self.SetListener = function(_, listener: (any) -> ())
self.listener = listener
end

return self
end

return BaseAnimation
78 changes: 78 additions & 0 deletions src/Animations/Types/Spring.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,78 @@
local BaseAnimation = require(script.Parent.Parent.Base)
local Promise = require(script.Parent.Parent.Parent.Promise)
local SpringValue = require(script.Parent.Parent.Parent.Utility.SpringValue)

local Spring = {}
Spring.__index = Spring

export type Spring = typeof(Spring.new())
export type SpringProperties = {
damper: number?,
speed: number?,
start: any,
target: any,
}

function Spring.new(props: SpringProperties)
local self = setmetatable(BaseAnimation.new(), Spring) :: Spring

self.props = props
self.player = nil

return self
end

function Spring:Play(from: any?)
if self.playing then
self:Stop()
end

local baseFromValue = self.props.start or from :: any
local baseToValue = self.props.target :: any
local force = self.props.force :: any

assert(baseFromValue, "No start value provided")
assert(baseToValue, "No target value provided")

if baseFromValue == baseToValue and not force then
return Promise.resolve()
end

local newSpring = SpringValue.new(baseFromValue, self.props.speed, self.props.damper)
newSpring:SetGoal(baseToValue)

if self._oldSpring then
newSpring:Impulse(self._oldSpring:GetVelocity())
end

if force then
newSpring:Impulse(force)
end

local animation = newSpring:Run(function()
if self.listener then
self.listener(newSpring:GetValue())
end
end)

self.playing = true
self.player = animation
self._oldSpring = newSpring

return animation
end

function Spring:Stop()
if not self.playing then
return
end

if self.player then
self.player:cancel()
self.player = nil
end

self.playing = false
end

return Spring
132 changes: 132 additions & 0 deletions src/Animations/Types/Tween.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
local TweenService = game:GetService("TweenService")

local BaseAnimation = require(script.Parent.Parent.Base)
local Promise = require(script.Parent.Parent.Parent.Promise)
local LinearValue = require(script.Parent.Parent.Parent.Utility.LinearValue)

local Tween = {}
Tween.__index = Tween

export type Tween = typeof(Tween.new())
export type TweenProperties<T> = {
info: TweenInfo,
startImmediate: T?,
start: T,
target: T,
delay: number?,
}

local function playTween(tweenInfo, callback: (number) -> nil, completed: () -> nil)
local numberValue = Instance.new("NumberValue")
numberValue.Value = 0
numberValue:GetPropertyChangedSignal("Value"):Connect(function()
callback(numberValue.Value)
end)

local tween = TweenService:Create(numberValue, tweenInfo, {
Value = 1,
})

tween.Completed:Connect(function()
numberValue:Destroy()
completed()
end)

return function()
callback(0)
tween:Play()
end, function()
numberValue:Destroy()
tween:Cancel()
end
end

function Tween.new<T>(props: TweenProperties<T>)
local self = setmetatable(BaseAnimation.new(), Tween) :: Tween

self.props = props
self.player = nil

return self
end

function Tween:Play(from: any?)
if self.playing then
self:Stop()
end

local tweenInfo = self.props.info :: TweenInfo
local baseFromValue = self.props.startImmediate or self.props.start or from :: any
local baseToValue = self.props.target :: any

-- start immediately will start the tween but not update the listener
local startImmediately = self.props.startImmediate ~= nil
local delayTime = self.props.delay :: number

if not delayTime then
assert(startImmediately == false, "Cannot start immediately without a delay")
else
if startImmediately then
assert(delayTime > 0, "DelayTime must be greater than zero")
end
end

assert(baseFromValue, "No start value provided")
assert(baseToValue, "No target value provided")

assert(tweenInfo, "No tween info provided")
assert(tweenInfo.RepeatCount == 0, "RepeatCount must be 0")
assert(tweenInfo.Reverses == false, "Reverses must be false")
assert(tweenInfo.DelayTime == 0, "DelayTime must be 0")

if baseFromValue == baseToValue then
return Promise.resolve()
end

local fromValue = LinearValue.fromValue(baseFromValue)
local toValue = LinearValue.fromValue(baseToValue)

local animation = Promise.new(function(resolve, _, onCancel)
local play, cancel = playTween(tweenInfo, function(value)
local newValue = fromValue:Lerp(toValue, value):ToValue()
self.listener(newValue)
end, function()
self.playing = false
self.player = nil
resolve()
end)

onCancel(cancel)

if not delayTime then
play()
else
if startImmediately then
self.listener(baseFromValue)
end

task.wait(delayTime)
play()
end
end)

self.playing = true
self.player = animation

return animation
end

function Tween:Stop()
if not self.playing then
return
end

if self.player then
self.player:cancel()
self.player = nil
end

self.playing = false
end

return Tween
4 changes: 4 additions & 0 deletions src/Animations/init.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
return {
Spring = require(script.Types.Spring).new,
Tween = require(script.Types.Tween).new,
}
Loading