@quenty/transitionmodel 1.1.0 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/CHANGELOG.md CHANGED
@@ -3,6 +3,17 @@
3
3
  All notable changes to this project will be documented in this file.
4
4
  See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
5
5
 
6
+ # [1.2.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/transitionmodel@1.1.0...@quenty/transitionmodel@1.2.0) (2023-03-06)
7
+
8
+
9
+ ### Features
10
+
11
+ * Add additional methods to transition model and documentation ([8466e0b](https://github.com/Quenty/NevermoreEngine/commit/8466e0bc4726c15070438bfa251992b04c5b0c15))
12
+
13
+
14
+
15
+
16
+
6
17
  # 1.1.0 (2023-03-05)
7
18
 
8
19
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quenty/transitionmodel",
3
- "version": "1.1.0",
3
+ "version": "1.2.0",
4
4
  "description": "Helps with Gui visiblity showing and hiding",
5
5
  "keywords": [
6
6
  "Roblox",
@@ -26,15 +26,17 @@
26
26
  ],
27
27
  "dependencies": {
28
28
  "@quenty/baseobject": "^6.2.0",
29
- "@quenty/basicpane": "^7.7.0",
30
- "@quenty/blend": "^6.10.0",
29
+ "@quenty/basicpane": "^7.8.0",
30
+ "@quenty/blend": "^6.11.0",
31
+ "@quenty/instanceutils": "^7.8.0",
31
32
  "@quenty/loader": "^6.2.0",
32
33
  "@quenty/maid": "^2.5.0",
33
34
  "@quenty/promise": "^6.3.0",
35
+ "@quenty/rx": "^7.7.0",
34
36
  "@quenty/signal": "^2.3.0"
35
37
  },
36
38
  "publishConfig": {
37
39
  "access": "public"
38
40
  },
39
- "gitHead": "e62b5eac2e5d9084ab9083f128452dd2d98b6f1a"
41
+ "gitHead": "ce54e6f72519719e6155643418f2496f30a55f8e"
40
42
  }
@@ -14,6 +14,14 @@ local SpringTransitionModel = setmetatable({}, BasicPane)
14
14
  SpringTransitionModel.ClassName = "SpringTransitionModel"
15
15
  SpringTransitionModel.__index = SpringTransitionModel
16
16
 
17
+ --[=[
18
+ A transition model that has a spring underlying it. Very useful
19
+ for animations on tracks that need to be on a spring.
20
+
21
+ @param showTarget T? -- Defaults to 1
22
+ @param hideTarget T? -- Defaults to 0*showTarget
23
+ @return SpringTransitionModel<T>
24
+ ]=]
17
25
  function SpringTransitionModel.new(showTarget, hideTarget)
18
26
  local self = setmetatable(BasicPane.new(), SpringTransitionModel)
19
27
 
@@ -42,12 +50,53 @@ function SpringTransitionModel.new(showTarget, hideTarget)
42
50
  return self
43
51
  end
44
52
 
53
+ --[=[
54
+ Returns true if showing is complete
55
+ @return boolean
56
+ ]=]
57
+ function SpringTransitionModel:IsShowingComplete()
58
+ return self._transitionModel:IsShowingComplete()
59
+ end
60
+
61
+ --[=[
62
+ Returns true if hiding is complete
63
+ @return boolean
64
+ ]=]
65
+ function SpringTransitionModel:IsHidingComplete()
66
+ return self._transitionModel:IsHidingComplete()
67
+ end
68
+
69
+ --[=[
70
+ Observe is showing is complete
71
+ @return Observable<boolean>
72
+ ]=]
73
+ function SpringTransitionModel:ObserveIsShowingComplete()
74
+ return self._transitionModel:ObserveIsShowingComplete()
75
+ end
76
+
77
+ --[=[
78
+ Observe is hiding is complete
79
+ @return Observable<boolean>
80
+ ]=]
81
+ function SpringTransitionModel:ObserveIsHidingComplete()
82
+ return self._transitionModel:ObserveIsHidingComplete()
83
+ end
84
+
85
+ --[=[
86
+ Binds the transition model to the actual visiblity of the pane
87
+
88
+ @param pane BasicPane
89
+ @return function -- Cleanup function
90
+ ]=]
45
91
  function SpringTransitionModel:BindToPaneVisbility(pane)
46
92
  local maid = Maid.new()
47
93
 
48
94
  maid:GiveTask(pane.VisibleChanged:Connect(function(isVisible, doNotAnimate)
49
95
  self:SetVisible(isVisible, doNotAnimate)
50
96
  end))
97
+ maid:GiveTask(self.VisibleChanged:Connect(function(isVisible, doNotAnimate)
98
+ pane:SetVisible(isVisible, doNotAnimate)
99
+ end))
51
100
 
52
101
  self:SetVisible(pane:IsVisible())
53
102
 
@@ -60,46 +109,105 @@ function SpringTransitionModel:BindToPaneVisbility(pane)
60
109
  end
61
110
  end
62
111
 
112
+ --[=[
113
+ Returns the spring's velocity
114
+
115
+ @return T
116
+ ]=]
117
+ function SpringTransitionModel:GetVelocity()
118
+ return self._springObject.Velocity
119
+ end
120
+
121
+ --[=[
122
+ Sets the springs epsilon. This can affect how long the spring takes
123
+ to finish.
124
+
125
+ @param epsilon number
126
+ ]=]
127
+ function SpringTransitionModel:SetEpsilon(epsilon)
128
+ assert(type(epsilon) == "number", "Bad epsilon")
129
+
130
+ self._springObject.Epsilon = epsilon
131
+ end
132
+
133
+ --[=[
134
+ Sets the springs speed
135
+
136
+ @param speed number
137
+ ]=]
63
138
  function SpringTransitionModel:SetSpeed(speed)
139
+ assert(type(speed) == "number", "Bad speed")
140
+
64
141
  self._springObject.Speed = speed
65
142
  end
66
143
 
144
+ --[=[
145
+ Sets the springs damper
146
+
147
+ @param damper number
148
+ ]=]
67
149
  function SpringTransitionModel:SetDamper(damper)
150
+ assert(type(damper) == "number", "Bad damper")
151
+
68
152
  self._springObject.Damper = damper
69
153
  end
70
154
 
155
+ --[=[
156
+ Observes the spring animating
157
+ @return Observable<T>
158
+ ]=]
71
159
  function SpringTransitionModel:ObserveRenderStepped()
72
160
  return self._springObject:ObserveRenderStepped()
73
161
  end
74
162
 
163
+ --[=[
164
+ Shows the model and promises when the showing is complete.
165
+
166
+ @param doNotAnimate boolean
167
+ @return Promise
168
+ ]=]
75
169
  function SpringTransitionModel:PromiseShow(doNotAnimate)
76
170
  return self._transitionModel:PromiseShow(doNotAnimate)
77
171
  end
78
172
 
173
+ --[=[
174
+ Hides the model and promises when the showing is complete.
175
+
176
+ @param doNotAnimate boolean
177
+ @return Promise
178
+ ]=]
79
179
  function SpringTransitionModel:PromiseHide(doNotAnimate)
80
180
  return self._transitionModel:PromiseHide(doNotAnimate)
81
181
  end
82
182
 
183
+ --[=[
184
+ Toggles the model and promises when the transition is complete.
185
+
186
+ @param doNotAnimate boolean
187
+ @return Promise
188
+ ]=]
83
189
  function SpringTransitionModel:PromiseToggle(doNotAnimate)
84
190
  return self._transitionModel:PromiseToggle(doNotAnimate)
85
191
  end
86
192
 
87
- function SpringTransitionModel:_promiseShow(maid)
88
- local promise = Promise.new()
89
- maid:GiveTask(promise)
90
-
91
- self._springObject.t = self._showTarget
193
+ function SpringTransitionModel:_promiseShow(maid, doNotAnimate)
194
+ self._springObject:SetTarget(self._showTarget, doNotAnimate)
92
195
 
93
- return maid:GivePromise(self._springObject:PromiseFinished())
196
+ if doNotAnimate then
197
+ return Promise.resolved()
198
+ else
199
+ return maid:GivePromise(self._springObject:PromiseFinished())
200
+ end
94
201
  end
95
202
 
96
- function SpringTransitionModel:_promiseHide(maid)
97
- local promise = Promise.new()
98
- maid:GiveTask(promise)
203
+ function SpringTransitionModel:_promiseHide(maid, doNotAnimate)
204
+ self._springObject:SetTarget(self._hideTarget, doNotAnimate)
99
205
 
100
- self._springObject.t = self._hideTarget
101
-
102
- return maid:GivePromise(self._springObject:PromiseFinished())
206
+ if doNotAnimate then
207
+ return Promise.resolved()
208
+ else
209
+ return maid:GivePromise(self._springObject:PromiseFinished())
210
+ end
103
211
  end
104
212
 
105
213
  return SpringTransitionModel
@@ -0,0 +1,145 @@
1
+ --[=[
2
+ A sustain model is much like a [TransitionModel] but is responsible for
3
+ sustaining some animation or state. Useful to represent the sustained state
4
+ of an animation or something.
5
+
6
+ @class SustainModel
7
+ ]=]
8
+
9
+ local require = require(script.Parent.loader).load(script)
10
+
11
+ local BaseObject = require("BaseObject")
12
+ local Maid = require("Maid")
13
+ local Promise = require("Promise")
14
+ local Signal = require("Signal")
15
+
16
+ local SustainModel = setmetatable({}, BaseObject)
17
+ SustainModel.ClassName = "SustainModel"
18
+ SustainModel.__index = SustainModel
19
+
20
+ function SustainModel.new()
21
+ local self = setmetatable(BaseObject.new(), SustainModel)
22
+
23
+ self._isSustained = false
24
+ self._sustainCallback = nil
25
+
26
+ self.SustainChanged = Signal.new() -- :Fire(isSustained, doNotAnimate)
27
+ self._maid:GiveTask(self.SustainChanged)
28
+
29
+ self._maid:GiveTask(self.SustainChanged:Connect(function(isSustained, doNotAnimate)
30
+ if isSustained then
31
+ self:_executeSustain(doNotAnimate)
32
+ else
33
+ self._maid._sustaining = nil
34
+ end
35
+ end))
36
+
37
+ return self
38
+ end
39
+
40
+ --[=[
41
+ Sets the callback which will handle sustaining the animation.
42
+
43
+ @param sustainCallback function? -- Callback which should return a promise
44
+ ]=]
45
+ function SustainModel:SetPromiseSustain(sustainCallback)
46
+ assert(type(sustainCallback) == "function" or sustainCallback == nil, "Bad sustainCallback")
47
+
48
+ self._sustainCallback = sustainCallback
49
+ end
50
+
51
+ --[=[
52
+ Sets whether we should be sustaining or not
53
+
54
+ @param isSustained boolean
55
+ @param doNotAnimate boolean? -- True if animation should be skipped
56
+ ]=]
57
+ function SustainModel:SetIsSustained(isSustained, doNotAnimate)
58
+ assert(type(isSustained) == "boolean", "Bad isSustained")
59
+
60
+ if self._isSustained ~= isSustained then
61
+ self._isSustained = isSustained
62
+ self.SustainChanged:Fire(self._isSustained, doNotAnimate)
63
+ end
64
+ end
65
+
66
+ --[=[
67
+ Starts sustaining
68
+
69
+ @param doNotAnimate boolean? -- True if animation should be skipped
70
+ ]=]
71
+ function SustainModel:Sustain(doNotAnimate)
72
+ self:SetIsSustained(true, doNotAnimate)
73
+ end
74
+
75
+ --[=[
76
+ Stops sustaining
77
+
78
+ @param doNotAnimate boolean? -- True if animation should be skipped
79
+ ]=]
80
+ function SustainModel:Stop(doNotAnimate)
81
+ self:SetIsSustained(false, doNotAnimate)
82
+ end
83
+
84
+ --[=[
85
+ Starts sustaining. The promise will resolve when sustaining is done.
86
+ If sustaining is already happening, it will not start, but will continue
87
+ to sustain until the promise is done.
88
+
89
+ @param doNotAnimate boolean? -- True if animation should be skipped
90
+ @return Promise
91
+ ]=]
92
+ function SustainModel:PromiseSustain(doNotAnimate)
93
+ self:Sustain(doNotAnimate)
94
+
95
+ return self:_promiseSustained()
96
+ end
97
+
98
+ function SustainModel:_promiseSustained()
99
+ if not self._isSustained then
100
+ return Promise.resolved()
101
+ end
102
+
103
+ local promise = Promise.new()
104
+
105
+ local maid = Maid.new()
106
+ self._maid[promise] = maid
107
+
108
+ maid:GiveTask(self.SustainChanged:Connect(function(isSustained)
109
+ if not isSustained then
110
+ promise:Resolve()
111
+ end
112
+ end))
113
+
114
+ promise:Finally(function()
115
+ self._maid[promise] = nil
116
+ end)
117
+
118
+ return promise
119
+ end
120
+
121
+ function SustainModel:_executeSustain(doNotAnimate)
122
+ local maid = Maid.new()
123
+
124
+ local promise = Promise.new()
125
+ maid:GiveTask(promise)
126
+
127
+ if self._sustainCallback then
128
+ local result = self._sustainCallback(maid, doNotAnimate)
129
+ if Promise.isPromise(result) then
130
+ promise:Resolve(result)
131
+ else
132
+ promise:Reject()
133
+ error(string.format("[SustainModel] - Expected promise to be returned from sustainCallback, got %q", tostring(result)))
134
+ end
135
+ end
136
+
137
+ promise:Then(function()
138
+ self:SetIsSustained(false, doNotAnimate)
139
+ end)
140
+
141
+ self._maid._sustaining = maid
142
+ end
143
+
144
+
145
+ return SustainModel
@@ -1,6 +1,6 @@
1
1
  --[=[
2
2
  This model deduplicates and handles transitions for showing, hiding, and
3
- toggling.
3
+ toggling. Inherits from [BasicPane]. See for more API.
4
4
 
5
5
  @class TransitionModel
6
6
  ]=]
@@ -10,11 +10,20 @@ local require = require(script.Parent.loader).load(script)
10
10
  local BasicPane = require("BasicPane")
11
11
  local Promise = require("Promise")
12
12
  local Maid = require("Maid")
13
+ local RxInstanceUtils = require("RxInstanceUtils")
13
14
 
14
15
  local TransitionModel = setmetatable({}, BasicPane)
15
16
  TransitionModel.ClassName = "TransitionModel"
16
17
  TransitionModel.__index = TransitionModel
17
18
 
19
+ --[=[
20
+ A transition model that takes a set amount of time to show
21
+ and hide. Can be used just like a [BasicPane] (in fact, it
22
+ inherits from it), but additionally allows for variable length
23
+ show and hide calls.
24
+
25
+ @return TransitionModel
26
+ ]=]
18
27
  function TransitionModel.new()
19
28
  local self = setmetatable(BasicPane.new(), TransitionModel)
20
29
 
@@ -23,9 +32,12 @@ function TransitionModel.new()
23
32
  self._maid:GiveTask(self._isShowingComplete)
24
33
 
25
34
  self._isHidingComplete = Instance.new("BoolValue")
26
- self._isHidingComplete.Value = false
35
+ self._isHidingComplete.Value = true
27
36
  self._maid:GiveTask(self._isHidingComplete)
28
37
 
38
+ self._showCallback = nil
39
+ self._hideCallback = nil
40
+
29
41
  self._maid:GiveTask(self.VisibleChanged:Connect(function(visible, doNotAnimate)
30
42
  if visible then
31
43
  self:_executeShow(doNotAnimate)
@@ -37,18 +49,36 @@ function TransitionModel.new()
37
49
  return self
38
50
  end
39
51
 
52
+ --[=[
53
+ Shows the model and promises when the showing is complete.
54
+
55
+ @param doNotAnimate boolean
56
+ @return Promise
57
+ ]=]
40
58
  function TransitionModel:PromiseShow(doNotAnimate)
41
59
  self:Show(doNotAnimate)
42
60
 
43
61
  return self:_promiseIsShown()
44
62
  end
45
63
 
64
+ --[=[
65
+ Hides the model and promises when the showing is complete.
66
+
67
+ @param doNotAnimate boolean
68
+ @return Promise
69
+ ]=]
46
70
  function TransitionModel:PromiseHide(doNotAnimate)
47
71
  self:Hide(doNotAnimate)
48
72
 
49
73
  return self:_promiseIsHidden()
50
74
  end
51
75
 
76
+ --[=[
77
+ Toggles the model and promises when the transition is complete.
78
+
79
+ @param doNotAnimate boolean
80
+ @return Promise
81
+ ]=]
52
82
  function TransitionModel:PromiseToggle(doNotAnimate)
53
83
  if self:IsVisible() then
54
84
  return self:PromiseShow(doNotAnimate)
@@ -57,12 +87,53 @@ function TransitionModel:PromiseToggle(doNotAnimate)
57
87
  end
58
88
  end
59
89
 
90
+ --[=[
91
+ Returns true if showing is complete
92
+ @return boolean
93
+ ]=]
94
+ function TransitionModel:IsShowingComplete()
95
+ return self._isShowingComplete.Value
96
+ end
97
+
98
+ --[=[
99
+ Returns true if hiding is complete
100
+ @return boolean
101
+ ]=]
102
+ function TransitionModel:IsHidingComplete()
103
+ return self._isHidingComplete.Value
104
+ end
105
+
106
+ --[=[
107
+ Observe is showing is complete
108
+ @return Observable<boolean>
109
+ ]=]
110
+ function TransitionModel:ObserveIsShowingComplete()
111
+ return RxInstanceUtils.observeProperty(self._isShowingComplete, "Value")
112
+ end
113
+
114
+ --[=[
115
+ Observe is hiding is complete
116
+ @return Observable<boolean>
117
+ ]=]
118
+ function TransitionModel:ObserveIsHidingComplete()
119
+ return RxInstanceUtils.observeProperty(self._isHidingComplete, "Value")
120
+ end
121
+
122
+ --[=[
123
+ Binds the transition model to the actual visiblity of the pane
124
+
125
+ @param pane BasicPane
126
+ @return function -- Cleanup function
127
+ ]=]
60
128
  function TransitionModel:BindToPaneVisbility(pane)
61
129
  local maid = Maid.new()
62
130
 
63
131
  maid:GiveTask(pane.VisibleChanged:Connect(function(isVisible, doNotAnimate)
64
132
  self:SetVisible(isVisible, doNotAnimate)
65
133
  end))
134
+ maid:GiveTask(self.VisibleChanged:Connect(function(isVisible, doNotAnimate)
135
+ pane:SetVisible(isVisible, doNotAnimate)
136
+ end))
66
137
 
67
138
  self:SetVisible(pane:IsVisible())
68
139
 
@@ -75,14 +146,24 @@ function TransitionModel:BindToPaneVisbility(pane)
75
146
  end
76
147
  end
77
148
 
149
+ --[=[
150
+ Sets the callback which will handle showing the transition
151
+
152
+ @param showCallback function? -- Callback which should return a promise
153
+ ]=]
78
154
  function TransitionModel:SetPromiseShow(showCallback)
79
- assert(type(showCallback) == "function", "Bad showCallback")
155
+ assert(type(showCallback) == "function" or showCallback == nil, "Bad showCallback")
80
156
 
81
157
  self._showCallback = showCallback
82
158
  end
83
159
 
160
+ --[=[
161
+ Sets the callback which will handle hiding the transition
162
+
163
+ @param hideCallback function? -- Callback which should return a promise
164
+ ]=]
84
165
  function TransitionModel:SetPromiseHide(hideCallback)
85
- assert(type(hideCallback) == "function", "Bad hideCallback")
166
+ assert(type(hideCallback) == "function" or hideCallback == nil, "Bad hideCallback")
86
167
 
87
168
  self._hideCallback = hideCallback
88
169
  end
@@ -116,6 +197,7 @@ function TransitionModel:_promiseIsShown()
116
197
  return promise
117
198
  end
118
199
 
200
+
119
201
  function TransitionModel:_promiseIsHidden()
120
202
  if self._isHidingComplete.Value then
121
203
  return Promise.resolved()
@@ -186,7 +268,7 @@ function TransitionModel:_executeHide(doNotAnimate)
186
268
  promise:Resolve(result)
187
269
  else
188
270
  promise:Reject()
189
- error(string.format("[TransitionModel] - Expected promise to be returned from showCallback, got %q", tostring(result)))
271
+ error(string.format("[TransitionModel] - Expected promise to be returned from hideCallback, got %q", tostring(result)))
190
272
  end
191
273
  end
192
274
 
@@ -197,5 +279,4 @@ function TransitionModel:_executeHide(doNotAnimate)
197
279
  self._maid._transition = maid
198
280
  end
199
281
 
200
-
201
282
  return TransitionModel
@@ -8,6 +8,17 @@ local BasicPane = require("BasicPane")
8
8
 
9
9
  local TransitionUtils = {}
10
10
 
11
+ --[=[
12
+ Returns true if the value is a transition, that is, it implements the following
13
+ methods:
14
+
15
+ * PromiseShow
16
+ * PromiseHide
17
+ * PromiseToggle
18
+
19
+ @param value any
20
+ @return boolean
21
+ ]=]
11
22
  function TransitionUtils.isTransition(value)
12
23
  return BasicPane.isBasicPane(value)
13
24
  and type(value.PromiseShow) == "function"