@quenty/inputkeymaputils 14.35.0-canary.643.622f151.0 → 14.35.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,7 +3,32 @@
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
- # [14.35.0-canary.643.622f151.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/inputkeymaputils@14.34.0...@quenty/inputkeymaputils@14.35.0-canary.643.622f151.0) (2026-01-19)
6
+ # [14.35.0](https://github.com/Quenty/NevermoreEngine/compare/@quenty/inputkeymaputils@14.34.2...@quenty/inputkeymaputils@14.35.0) (2026-01-26)
7
+
8
+
9
+ ### Bug Fixes
10
+
11
+ * Fix lint ([7c77d1f](https://github.com/Quenty/NevermoreEngine/commit/7c77d1f6d95657072fc756e6f93bed1484646ad9))
12
+ * Remove holding state from input system ([b20d6f8](https://github.com/Quenty/NevermoreEngine/commit/b20d6f88725703864fe8112517dd4a5270274e3a))
13
+
14
+
15
+ ### Features
16
+
17
+ * Add Holdable option to InputKeyMapList ([0422fb6](https://github.com/Quenty/NevermoreEngine/commit/0422fb61671d80b110b06c6bf2da00fb293698bb))
18
+
19
+
20
+
21
+
22
+
23
+ ## [14.34.2](https://github.com/Quenty/NevermoreEngine/compare/@quenty/inputkeymaputils@14.34.1...@quenty/inputkeymaputils@14.34.2) (2026-01-23)
24
+
25
+ **Note:** Version bump only for package @quenty/inputkeymaputils
26
+
27
+
28
+
29
+
30
+
31
+ ## [14.34.1](https://github.com/Quenty/NevermoreEngine/compare/@quenty/inputkeymaputils@14.34.0...@quenty/inputkeymaputils@14.34.1) (2026-01-21)
7
32
 
8
33
  **Note:** Version bump only for package @quenty/inputkeymaputils
9
34
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@quenty/inputkeymaputils",
3
- "version": "14.35.0-canary.643.622f151.0",
3
+ "version": "14.35.0",
4
4
  "description": "System to define rebindable key bindings and inputs for Roblox.",
5
5
  "keywords": [
6
6
  "Roblox",
@@ -30,25 +30,25 @@
30
30
  ],
31
31
  "dependencies": {
32
32
  "@quenty/baseobject": "10.9.3",
33
- "@quenty/brio": "14.25.0-canary.643.622f151.0",
34
- "@quenty/clienttranslator": "14.30.0-canary.643.622f151.0",
33
+ "@quenty/brio": "14.24.1",
34
+ "@quenty/clienttranslator": "14.29.2",
35
35
  "@quenty/ducktype": "5.9.3",
36
36
  "@quenty/enumutils": "3.4.5",
37
- "@quenty/inputmode": "13.28.0-canary.643.622f151.0",
37
+ "@quenty/inputmode": "13.27.1",
38
38
  "@quenty/loader": "10.9.3",
39
39
  "@quenty/maid": "3.5.3",
40
- "@quenty/observablecollection": "12.31.0-canary.643.622f151.0",
40
+ "@quenty/observablecollection": "12.30.2",
41
41
  "@quenty/pseudolocalize": "3.5.2",
42
- "@quenty/rx": "13.24.0-canary.643.622f151.0",
42
+ "@quenty/rx": "13.23.1",
43
43
  "@quenty/servicebag": "11.13.6",
44
- "@quenty/statestack": "14.27.0-canary.643.622f151.0",
44
+ "@quenty/statestack": "14.26.1",
45
45
  "@quenty/string": "3.3.6",
46
46
  "@quenty/table": "3.9.2",
47
- "@quenty/valuebaseutils": "13.25.0-canary.643.622f151.0",
48
- "@quenty/valueobject": "13.26.0-canary.643.622f151.0"
47
+ "@quenty/valuebaseutils": "13.24.1",
48
+ "@quenty/valueobject": "13.25.1"
49
49
  },
50
50
  "publishConfig": {
51
51
  "access": "public"
52
52
  },
53
- "gitHead": "622f15117c0a16a8842c8015752c49d63ba96eae"
53
+ "gitHead": "6fd82c03003b22a03c83d00cac39fe2b2f7f8aa1"
54
54
  }
@@ -0,0 +1,217 @@
1
+ --!strict
2
+ --[=[
3
+ Tracks hold state for an input. Handles the timing logic
4
+ and exposes observables for hold progress.
5
+
6
+ ```lua
7
+ local holdableInputModel = HoldableInputModel.new(1.5)
8
+ -- Or set it later:
9
+ -- holdableInputModel:SetMaxHoldDuration(1.5)
10
+
11
+ maid:GiveTask(holdableInputModel.HoldReleased:Connect(function(holdPercent)
12
+ print("Released at", holdPercent)
13
+ end))
14
+
15
+ -- When input begins
16
+ holdableInputModel:StartHold()
17
+
18
+ -- When input ends
19
+ holdableInputModel:StopHold()
20
+ ```
21
+
22
+ @class HoldableInputModel
23
+ ]=]
24
+
25
+ local require = require(script.Parent.loader).load(script)
26
+
27
+ local RunService = game:GetService("RunService")
28
+
29
+ local BaseObject = require("BaseObject")
30
+ local Maid = require("Maid")
31
+ local Observable = require("Observable")
32
+ local Signal = require("Signal")
33
+ local ValueObject = require("ValueObject")
34
+
35
+ local HoldableInputModel = setmetatable({}, BaseObject)
36
+ HoldableInputModel.ClassName = "HoldableInputModel"
37
+ HoldableInputModel.__index = HoldableInputModel
38
+
39
+ export type HoldableInputModel =
40
+ typeof(setmetatable(
41
+ {} :: {
42
+ _maxHoldDuration: ValueObject.ValueObject<number>,
43
+ _holdPercent: ValueObject.ValueObject<number>,
44
+ _isHolding: ValueObject.ValueObject<boolean>,
45
+ HoldStarted: Signal.Signal<()>,
46
+ HoldUpdated: Signal.Signal<number>,
47
+ HoldReleased: Signal.Signal<number>,
48
+ },
49
+ {} :: typeof({ __index = HoldableInputModel })
50
+ ))
51
+ & BaseObject.BaseObject
52
+
53
+ --[=[
54
+ Constructs a new HoldableInputModel
55
+
56
+ @param maxHoldDuration number? -- Optional max hold duration in seconds (defaults to 1)
57
+ @return HoldableInputModel
58
+ ]=]
59
+ function HoldableInputModel.new(maxHoldDuration: number?): HoldableInputModel
60
+ local self = setmetatable(BaseObject.new() :: any, HoldableInputModel)
61
+
62
+ self._maxHoldDuration = self._maid:Add(ValueObject.new(maxHoldDuration or 1, "number"))
63
+ self._holdPercent = self._maid:Add(ValueObject.new(0, "number"))
64
+ self._isHolding = self._maid:Add(ValueObject.new(false, "boolean"))
65
+
66
+ --[=[
67
+ Fires when a hold begins
68
+ @prop HoldStarted Signal<>
69
+ @within HoldableInputModel
70
+ ]=]
71
+ self.HoldStarted = self._maid:Add(Signal.new())
72
+
73
+ --[=[
74
+ Fires when the hold percent updates
75
+ @prop HoldUpdated Signal<number>
76
+ @within HoldableInputModel
77
+ ]=]
78
+ self.HoldUpdated = self._maid:Add(Signal.new())
79
+
80
+ --[=[
81
+ Fires when a hold is released with the final hold percent
82
+ @prop HoldReleased Signal<number>
83
+ @within HoldableInputModel
84
+ ]=]
85
+ self.HoldReleased = self._maid:Add(Signal.new())
86
+
87
+ return self
88
+ end
89
+
90
+ --[=[
91
+ Sets the maximum hold duration in seconds
92
+
93
+ @param duration number | Observable<number>
94
+ @return MaidTask
95
+ ]=]
96
+ function HoldableInputModel.SetMaxHoldDuration(
97
+ self: HoldableInputModel,
98
+ duration: number | Observable.Observable<number>
99
+ )
100
+ return self._maxHoldDuration:Mount(duration)
101
+ end
102
+
103
+ --[=[
104
+ Gets the maximum hold duration
105
+
106
+ @return number
107
+ ]=]
108
+ function HoldableInputModel.GetMaxHoldDuration(self: HoldableInputModel): number
109
+ return self._maxHoldDuration.Value
110
+ end
111
+
112
+ --[=[
113
+ Observes the maximum hold duration
114
+
115
+ @return Observable<number>
116
+ ]=]
117
+ function HoldableInputModel.ObserveMaxHoldDuration(self: HoldableInputModel): Observable.Observable<number>
118
+ return self._maxHoldDuration:Observe()
119
+ end
120
+
121
+ --[=[
122
+ Observes the current hold percent (0-1)
123
+
124
+ @return Observable<number>
125
+ ]=]
126
+ function HoldableInputModel.ObserveHoldPercent(self: HoldableInputModel): Observable.Observable<number>
127
+ return self._holdPercent:Observe()
128
+ end
129
+
130
+ --[=[
131
+ Gets the current hold percent (0-1)
132
+
133
+ @return number
134
+ ]=]
135
+ function HoldableInputModel.GetHoldPercent(self: HoldableInputModel): number
136
+ return self._holdPercent.Value
137
+ end
138
+
139
+ --[=[
140
+ Observes whether currently holding
141
+
142
+ @return Observable<boolean>
143
+ ]=]
144
+ function HoldableInputModel.ObserveIsHolding(self: HoldableInputModel): Observable.Observable<boolean>
145
+ return self._isHolding:Observe()
146
+ end
147
+
148
+ --[=[
149
+ Returns whether currently holding
150
+
151
+ @return boolean
152
+ ]=]
153
+ function HoldableInputModel.IsHolding(self: HoldableInputModel): boolean
154
+ return self._isHolding.Value
155
+ end
156
+
157
+ --[=[
158
+ Starts tracking a hold. Call this when input begins.
159
+ ]=]
160
+ function HoldableInputModel.StartHold(self: HoldableInputModel): ()
161
+ self._maid._holdMaid = nil
162
+
163
+ local maid = Maid.new()
164
+ local elapsed = 0
165
+ local maxDuration = self._maxHoldDuration.Value or 1
166
+
167
+ self._isHolding.Value = true
168
+ self._holdPercent.Value = 0
169
+ self.HoldStarted:Fire()
170
+
171
+ maid:GiveTask(RunService.Heartbeat:Connect(function(dt)
172
+ elapsed += dt
173
+ local newPercent = math.clamp(elapsed / maxDuration, 0, 1)
174
+ if self._holdPercent.Value ~= newPercent then
175
+ self._holdPercent.Value = newPercent
176
+ self.HoldUpdated:Fire(newPercent)
177
+ end
178
+ end))
179
+
180
+ maid:GiveTask(function()
181
+ local finalPercent = self._holdPercent.Value
182
+ self._holdPercent.Value = 0
183
+ self._isHolding.Value = false
184
+ self.HoldReleased:Fire(finalPercent)
185
+ end)
186
+
187
+ self._maid._holdMaid = maid
188
+ end
189
+
190
+ --[=[
191
+ Stops tracking a hold and fires HoldReleased with the final percent.
192
+ Call this when input ends.
193
+ ]=]
194
+ function HoldableInputModel.StopHold(self: HoldableInputModel): ()
195
+ self._maid._holdMaid = nil
196
+ end
197
+
198
+ --[=[
199
+ Cancels a hold without firing HoldReleased.
200
+ Use this when the hold should be aborted (e.g., interrupted by stun).
201
+ ]=]
202
+ function HoldableInputModel.CancelHold(self: HoldableInputModel): ()
203
+ if self._maid._holdMaid then
204
+ self._isHolding.Value = false
205
+ self._holdPercent.Value = 0
206
+ -- Clear without triggering cleanup function
207
+ local holdMaid = self._maid._holdMaid
208
+ self._maid._holdMaid = nil
209
+ if holdMaid and holdMaid.Destroy then
210
+ -- Destroy without the cleanup function firing HoldReleased
211
+ holdMaid._tasks = {}
212
+ holdMaid:Destroy()
213
+ end
214
+ end
215
+ end
216
+
217
+ return HoldableInputModel