wuira 0.1.3 → 0.1.5

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +50 -0
  2. package/README.md +181 -0
  3. package/lib/Spells.d.ts +10 -0
  4. package/lib/Spells.lua +19 -0
  5. package/lib/datasources/AuraTimer.d.ts +21 -0
  6. package/lib/datasources/AuraTimer.lua +322 -0
  7. package/lib/datasources/CastTimer.d.ts +9 -0
  8. package/lib/datasources/CastTimer.lua +240 -0
  9. package/lib/datasources/DataSource.d.ts +4 -0
  10. package/lib/datasources/DataSource.lua +24 -0
  11. package/lib/datasources/ProgressSource.d.ts +6 -2
  12. package/lib/datasources/ProgressSource.lua +20 -2
  13. package/lib/datasources/Resources.d.ts +21 -2
  14. package/lib/datasources/Resources.lua +473 -0
  15. package/lib/datasources/SpellCooldown.d.ts +10 -0
  16. package/lib/datasources/SpellCooldown.lua +207 -0
  17. package/lib/datasources/SwingTimer.d.ts +31 -0
  18. package/lib/datasources/SwingTimer.lua +641 -0
  19. package/lib/datasources/TextureSource.d.ts +10 -0
  20. package/lib/datasources/TextureSource.lua +83 -0
  21. package/lib/datasources/TimerSource.d.ts +18 -0
  22. package/lib/datasources/TimerSource.lua +284 -0
  23. package/lib/datasources/index.d.ts +9 -1
  24. package/lib/datasources/index.lua +27 -0
  25. package/lib/index.d.ts +5 -0
  26. package/lib/index.lua +13 -0
  27. package/lib/platform/BlizzardUI.d.ts +12 -0
  28. package/lib/platform/BlizzardUI.lua +352 -0
  29. package/lib/platform/forever.d.ts +40 -2
  30. package/lib/store/index.d.ts +37 -0
  31. package/lib/store/index.lua +921 -0
  32. package/lib/ui/Cell.d.ts +3 -1
  33. package/lib/ui/Icon.d.ts +8 -0
  34. package/lib/ui/Icon.lua +8 -0
  35. package/lib/ui/Label.d.ts +10 -0
  36. package/lib/ui/Label.lua +8 -0
  37. package/lib/ui/ProgressBar.d.ts +5 -1
  38. package/lib/ui/index.d.ts +4 -0
  39. package/lib/ui/index.lua +8 -0
  40. package/lib/ui/layout/measureLayout.lua +8 -1
  41. package/lib/ui/mount.lua +267 -45
  42. package/lib/ui/primitives/jsx.d.ts +7 -2
  43. package/package.json +8 -1
  44. package/tools/build-library.mjs +1 -1
package/CHANGELOG.md CHANGED
@@ -9,6 +9,56 @@ with the release date and highlight breaking changes explicitly.
9
9
 
10
10
  No changes yet.
11
11
 
12
+ ## 0.1.5 — 2026-10-14
13
+
14
+ ### Added
15
+
16
+ - Event-driven `.When(value => boolean)` source conditions. Inactive bindings
17
+ hide their visual and skip writes; secret inputs never reach callbacks.
18
+ Repeated conditions combine with AND, and fresh `.Value` reads remain unchanged.
19
+ - Opt-in `HP.UseHealPrediction()` and `HP.UseAbsorbPrediction()` channels,
20
+ with lazy allocation, capability checks, and optional event subscriptions.
21
+ - Independently styled healing and shield overlays on HP progress bars,
22
+ including direct native handling of secret amounts and clipping at bar bounds.
23
+ - Opt-in `BlizzardUI.Hide` for stock action bars and player/target/focus frames,
24
+ with combat deferral and a restore callback, preserving native event handlers.
25
+ - Cell visibility predicates and live label text, with cleanup on unmount.
26
+ - Timer activity flags and cast/channel spell names for conditional UI rows.
27
+ - Public `Spells` enum with named Paladin Seal spell IDs.
28
+ - Player swing countdown sources for main-hand, off-hand, and ranged attacks,
29
+ driven by Forever's native swing events and native StatusBar timer animation.
30
+ - Explicit unknown timing before the first readable event, secret-value guards,
31
+ weapon-change resets, and source disposal.
32
+ - Label and Icon primitives, with event-driven texture sources.
33
+ - Native duration sources for aura timers, spell/global cooldowns, and cast/channel
34
+ countdowns. Selected aura icons share the aura source's selection policy.
35
+
36
+ ### Fixed
37
+
38
+ - Initialize native timer and swing bars with a normalized 0–1 range instead
39
+ of the default resource range.
40
+ - Mount lifecycle now runs datasource binding cleanup callbacks on unmount.
41
+
42
+ ### Validation and limitations
43
+
44
+ - Lua tests cover conditional activation/reactivation, secret callback guards,
45
+ optional prediction reads/events, overlay placement, and unmount cleanup.
46
+ - Prediction amounts require the client's native unit APIs. Incoming healing
47
+ is raw (not reduced by heal-absorb debuffs); overheal is visually clipped.
48
+ HP overrides are incompatible with prediction overlays. In-game prediction
49
+ visuals still need validation in Forever.
50
+
51
+ ## 0.1.4 — 2026-10-14
52
+
53
+ ### Added
54
+
55
+ - Class-based stores with optional stable tokens, one-time readonly snapshots,
56
+ transactional callback updates, and observer subscriptions.
57
+ - Memory-only stores when no token is declared; SavedVariables-backed records
58
+ when a token and registry persistence configuration are provided.
59
+ - SavedVariables initialization after the owning addon's `ADDON_LOADED` event,
60
+ default restoration, collision checks, and serializable data validation.
61
+
12
62
  ## 0.1.3 — 2026-10-14
13
63
 
14
64
  ### Added
package/README.md CHANGED
@@ -94,6 +94,118 @@ function App() {
94
94
  wuira.Mount(App);
95
95
  ```
96
96
 
97
+ ### Conditional sources and health predictions
98
+
99
+ ```tsx
100
+ import { UI } from "wuira";
101
+ import { ProgressBar } from "wuira/ui";
102
+ import { HP, Unit } from "wuira/datasources";
103
+
104
+ const hp = new HP(Unit.Player)
105
+ .UseHealPrediction()
106
+ .UseAbsorbPrediction()
107
+ .When(value => value >= 20); // Current health points, not a percentage.
108
+
109
+ const view = (
110
+ <ProgressBar width={220} height={24} source={hp}
111
+ healPrediction={{ texture: "blizzard", color: { r: 0.4, g: 1, b: 0.5, a: 0.5 } }}
112
+ absorbPrediction={{ texture: "solid", color: { r: 0.8, g: 0.9, b: 1, a: 0.55 } }} />
113
+ );
114
+ ```
115
+
116
+ Configure sources before mounting. `.When()` filters native binding updates using
117
+ the source's own value; repeated calls combine with AND. A false condition hides
118
+ the bound bar and suppresses writes until a relevant event makes it true again.
119
+ The basic health events remain subscribed so the source can reactivate; there is
120
+ no health polling. Predicates should depend on this source's event-driven state,
121
+ not unrelated mutable values. `.Value` remains a fresh, checked snapshot rather
122
+ than a filtered subscription. Secret values never reach condition callbacks:
123
+ a conditional binding becomes inactive until readable data returns. Without a
124
+ condition, opaque values continue directly to native widgets.
125
+
126
+ Each prediction channel is allocated and its event registered only when explicitly
127
+ enabled and supported. No prediction snapshots are cached. Access
128
+ `hp.HealPrediction?.Value` and `hp.AbsorbPrediction?.Value` when readable, or check
129
+ the channel's `IsAvailable` flag. Direct reads retain the usual secret-value guard.
130
+ The APIs provide incoming healing and existing damage-absorb shields, not a
131
+ forecast of future damage. The adapter uses
132
+ [Blizzard's unit prediction APIs](https://github.com/Gethe/wow-ui-source/blob/live/Interface/AddOns/Blizzard_APIDocumentationGenerated/UnitDocumentation.lua).
133
+
134
+ Enabled channels draw by default; `healPrediction={false}` or
135
+ `absorbPrediction={false}` suppresses an individual overlay. Incoming healing starts
136
+ at the native health-fill edge and clips at the bar boundary. Shields overlay
137
+ inward from the opposite edge, remaining visible even at full health. Both accept
138
+ independent textures/colors and support horizontal, vertical, and reversed bars.
139
+ There is no arithmetic on secret health or prediction amounts. Raw incoming heals
140
+ are not reduced by heal-absorb debuffs; overheal is visually clipped. Prediction
141
+ overlays require the native health scale, so min/max/current overrides are rejected.
142
+ Prediction reads pause while the parent HP condition is inactive. The renderer
143
+ cleans up the overlays and resource subscriptions on unmount.
144
+
145
+ ### Native aura, cooldown, and cast timers
146
+
147
+ ```tsx
148
+ import { UI, Spells } from "wuira";
149
+ import { FlowLayout, ProgressBar, Icon, Label } from "wuira/ui";
150
+ import { AuraTimer, GlobalCooldown, CastTimer, Unit } from "wuira/datasources";
151
+
152
+ const aura = new AuraTimer(Unit.Player, { spellIds: [Spells.SealOfRighteousness], filter: "HELPFUL" });
153
+ const gcd = new GlobalCooldown();
154
+ const cast = new CastTimer(Unit.Player);
155
+
156
+ function Timers() {
157
+ return (
158
+ <FlowLayout width={200} height={94} direction="vertical" gap={2}>
159
+ <Icon width={24} height={24} textureSource={aura.Texture} />
160
+ <ProgressBar height={24} source={aura}><Label text="Aura" /></ProgressBar>
161
+ <ProgressBar height={18} source={gcd} />
162
+ <ProgressBar height={22} source={cast} />
163
+ </FlowLayout>
164
+ );
165
+ }
166
+ ```
167
+
168
+ These timers pass opaque native duration objects to `SetTimerDuration`; they do
169
+ not calculate restricted durations in Lua. `SpellCooldown(spellId)` tracks a
170
+ specific spell, and `GlobalCooldown` supplies the GCD identifier internally.
171
+ `CastTimer` follows casts and channels. `AuraTimer` resolves localized spell names
172
+ and exposes an associated `Texture` source, with status indicating active,
173
+ inactive, restricted, or unavailable data. Aura access still follows the client's
174
+ restrictions; missing readable data is not reconstructed from combat events.
175
+ `Label` and `Icon` are visual Cells. Application code supplies which spells to
176
+ track; native API declarations and reads remain in wuira.
177
+
178
+ ### Swing timers
179
+
180
+ ```tsx
181
+ import { UI, wuira } from "wuira";
182
+ import { ProgressBar } from "wuira/ui";
183
+ import { SwingTimer, SwingHand } from "wuira/datasources";
184
+
185
+ const mainHand = new SwingTimer(SwingHand.MainHand);
186
+ const view = wuira.Mount(<ProgressBar width={200} height={12} source={mainHand} />);
187
+
188
+ // Other choices: SwingHand.OffHand and SwingHand.Ranged.
189
+ // mainHand.Value: remaining seconds; Max.Value: duration; Percent.Value: remaining percent.
190
+ // When removing the feature:
191
+ if (view !== undefined) wuira.Unmount(view);
192
+ mainHand.Dispose();
193
+ ```
194
+
195
+ This source follows the player's `PLAYER_SWING(duration, swingType)` events.
196
+ It does not reconstruct swings from the combat log or track enemy attack cycles.
197
+ `HasTiming` is false until the first readable event and after a weapon/world reset;
198
+ zero before that event is not evidence of a synchronized swing. After a recorded
199
+ cycle expires, remaining time reaches zero. Secret payloads block datasource
200
+ computation until a readable event or reset arrives.
201
+
202
+ Native progress binding uses `C_DurationUtil` and `StatusBar:SetTimerDuration`,
203
+ with no Lua per-frame animation. Range/current overrides are not supported for
204
+ this binding. Unmount detaches each bar; call `Dispose()` to stop the source's
205
+ event listener when its owning feature ends. Support is capability-checked;
206
+ actual timing still needs validation in Forever. The adapter follows the
207
+ [Forever swing API definition](https://github.com/Gethe/wow-ui-source/blob/bd2470aed543f72697a044e989285b6c83e63f73/Interface/AddOns/Blizzard_APIDocumentationGenerated/SwingTimerDocumentation.lua).
208
+
97
209
  ### Group members
98
210
 
99
211
  ```ts
@@ -309,6 +421,75 @@ Relative output paths resolve from the project directory. Absolute paths can tar
309
421
 
310
422
  The CLI, configuration, and build plugin use ESM (`.mjs`). Only Lua and TOC files are needed in game. `npm run build` in the framework repository generates distributable Lua modules and TypeScript declarations in `lib/`; addon builds include the framework modules they import.
311
423
 
424
+ ## Stores
425
+
426
+ Use data classes to define defaults. Without a static token, records live only
427
+ in memory and are keyed by the class itself:
428
+
429
+ ```ts
430
+ import { Store, StoreRegistry } from "wuira/store";
431
+
432
+ class SessionSettings extends Store {
433
+ CastSpellId = 1232;
434
+ }
435
+
436
+ const store = new StoreRegistry();
437
+ const snapshot = store.get(SessionSettings); // One-time, deeply readonly copy.
438
+
439
+ const unsubscribe = store.subscribe(SessionSettings, settings => {
440
+ console.log("New spell:", settings.CastSpellId);
441
+ });
442
+
443
+ store.set(SessionSettings, settings => {
444
+ settings.CastSpellId = 635;
445
+ return settings;
446
+ });
447
+
448
+ unsubscribe();
449
+ ```
450
+
451
+ `get()` does not subscribe. `subscribe()` observes future commits and returns an
452
+ unsubscribe function; call `get()` for initial data. Each subscriber receives an
453
+ independent snapshot. `set()` works on a detached draft, validates the returned
454
+ data, commits it, and sends one notification per observer. If the updater throws,
455
+ the previous record is preserved. Stores contain data fields, not class methods.
456
+
457
+ For persistence, declare a stable token and the owning addon's SavedVariables:
458
+
459
+ ```toc
460
+ ## SavedVariables: LumaUIDB
461
+ ```
462
+
463
+ ```ts
464
+ class LumaSettings extends Store {
465
+ static readonly Token = "luma.settings";
466
+ CastSpellId = 1232;
467
+ Width = 220;
468
+ }
469
+
470
+ const store = new StoreRegistry({ addon: "LumaUI", variable: "LumaUIDB" });
471
+ store.onReady(() => {
472
+ console.log(store.get(LumaSettings).Width);
473
+ store.set(LumaSettings, settings => {
474
+ settings.Width = 240;
475
+ return settings;
476
+ });
477
+ });
478
+ ```
479
+
480
+ Add the TOC declaration to the addon's `addon.toc.in`. The registry waits for
481
+ `ADDON_LOADED` before opening persistent records. Tokenless records can still be
482
+ used immediately. WoW writes the saved table on normal logout/reload; `set()`
483
+ does not force a disk flush. Keep tokens stable across versions. New default
484
+ fields are filled in and incompatible saved field types fall back to defaults;
485
+ renaming keys or changing schema meaning still requires an application migration.
486
+
487
+ Supported values are finite numbers, strings, booleans, arrays, and nested data
488
+ objects. Functions, cycles, and secret values cannot be saved. Two classes cannot
489
+ claim the same token within a registry. Share one registry instance per database.
490
+ `Dispose()` removes its observers and pending initialization listener. Profile
491
+ selection, schema migrations, and reactive widget binding are separate features.
492
+
312
493
  ## Development
313
494
 
314
495
  ```sh
@@ -0,0 +1,10 @@
1
+ /** Representative spell IDs; aura sources resolve localized names across ranks. */
2
+ export declare enum Spells {
3
+ SealOfRighteousness = 21084,
4
+ SealOfTheCrusader = 21082,
5
+ SealOfCommand = 20375,
6
+ SealOfJustice = 20164,
7
+ SealOfLight = 20165,
8
+ SealOfWisdom = 20166,
9
+ SealOfFury = 20163
10
+ }
package/lib/Spells.lua ADDED
@@ -0,0 +1,19 @@
1
+ --[[ Generated with https://github.com/TypeScriptToLua/TypeScriptToLua ]]
2
+ local ____exports = {}
3
+ --- Representative spell IDs; aura sources resolve localized names across ranks.
4
+ ____exports.Spells = ____exports.Spells or ({})
5
+ ____exports.Spells.SealOfRighteousness = 21084
6
+ ____exports.Spells[____exports.Spells.SealOfRighteousness] = "SealOfRighteousness"
7
+ ____exports.Spells.SealOfTheCrusader = 21082
8
+ ____exports.Spells[____exports.Spells.SealOfTheCrusader] = "SealOfTheCrusader"
9
+ ____exports.Spells.SealOfCommand = 20375
10
+ ____exports.Spells[____exports.Spells.SealOfCommand] = "SealOfCommand"
11
+ ____exports.Spells.SealOfJustice = 20164
12
+ ____exports.Spells[____exports.Spells.SealOfJustice] = "SealOfJustice"
13
+ ____exports.Spells.SealOfLight = 20165
14
+ ____exports.Spells[____exports.Spells.SealOfLight] = "SealOfLight"
15
+ ____exports.Spells.SealOfWisdom = 20166
16
+ ____exports.Spells[____exports.Spells.SealOfWisdom] = "SealOfWisdom"
17
+ ____exports.Spells.SealOfFury = 20163
18
+ ____exports.Spells[____exports.Spells.SealOfFury] = "SealOfFury"
19
+ return ____exports
@@ -0,0 +1,21 @@
1
+ import { TimerSource } from "./TimerSource";
2
+ import { TextureSource } from "./TextureSource";
3
+ import { UnitSource } from "./UnitSource";
4
+ import type { UnitInput } from "./UnitSource";
5
+ export interface AuraTimerOptions {
6
+ /** Spell IDs resolve to localized names, so different ranks share a lookup. */
7
+ spellIds: readonly number[];
8
+ filter?: "HELPFUL" | "HARMFUL" | "HELPFUL|PLAYER" | "HARMFUL|PLAYER";
9
+ }
10
+ export type AuraTimerStatus = "active" | "inactive" | "restricted" | "unavailable";
11
+ /** Selected aura duration and icon; selection policy belongs to the application. */
12
+ export declare class AuraTimer extends TimerSource {
13
+ private readonly options;
14
+ readonly target: UnitSource;
15
+ readonly Texture: TextureSource;
16
+ private status;
17
+ constructor(unit: UnitInput, options: AuraTimerOptions);
18
+ get Status(): AuraTimerStatus;
19
+ private ReadAura;
20
+ private ReadDuration;
21
+ }
@@ -0,0 +1,322 @@
1
+ --[[ Generated with https://github.com/TypeScriptToLua/TypeScriptToLua ]]
2
+ -- Lua Library inline imports
3
+ local function __TS__Class(self)
4
+ local c = {prototype = {}}
5
+ c.prototype.__index = c.prototype
6
+ c.prototype.constructor = c
7
+ return c
8
+ end
9
+
10
+ local function __TS__ClassExtends(target, base)
11
+ target.____super = base
12
+ local staticMetatable = setmetatable({__index = base}, base)
13
+ setmetatable(target, staticMetatable)
14
+ local baseMetatable = getmetatable(base)
15
+ if baseMetatable then
16
+ if type(baseMetatable.__index) == "function" then
17
+ staticMetatable.__index = baseMetatable.__index
18
+ end
19
+ if type(baseMetatable.__newindex) == "function" then
20
+ staticMetatable.__newindex = baseMetatable.__newindex
21
+ end
22
+ end
23
+ setmetatable(target.prototype, base.prototype)
24
+ if type(base.prototype.__index) == "function" then
25
+ target.prototype.__index = base.prototype.__index
26
+ end
27
+ if type(base.prototype.__newindex) == "function" then
28
+ target.prototype.__newindex = base.prototype.__newindex
29
+ end
30
+ if type(base.prototype.__tostring) == "function" then
31
+ target.prototype.__tostring = base.prototype.__tostring
32
+ end
33
+ end
34
+
35
+ local function __TS__New(target, ...)
36
+ local instance = setmetatable({}, target.prototype)
37
+ instance:____constructor(...)
38
+ return instance
39
+ end
40
+
41
+ local function __TS__CloneDescriptor(____bindingPattern0)
42
+ local value
43
+ local writable
44
+ local set
45
+ local get
46
+ local configurable
47
+ local enumerable
48
+ enumerable = ____bindingPattern0.enumerable
49
+ configurable = ____bindingPattern0.configurable
50
+ get = ____bindingPattern0.get
51
+ set = ____bindingPattern0.set
52
+ writable = ____bindingPattern0.writable
53
+ value = ____bindingPattern0.value
54
+ local descriptor = {enumerable = enumerable == true, configurable = configurable == true}
55
+ local hasGetterOrSetter = get ~= nil or set ~= nil
56
+ local hasValueOrWritableAttribute = writable ~= nil or value ~= nil
57
+ if hasGetterOrSetter and hasValueOrWritableAttribute then
58
+ error("Invalid property descriptor. Cannot both specify accessors and a value or writable attribute.", 0)
59
+ end
60
+ if get or set then
61
+ descriptor.get = get
62
+ descriptor.set = set
63
+ else
64
+ descriptor.value = value
65
+ descriptor.writable = writable == true
66
+ end
67
+ return descriptor
68
+ end
69
+
70
+ local __TS__DescriptorGet
71
+ do
72
+ local getmetatable = _G.getmetatable
73
+ local ____rawget = _G.rawget
74
+ function __TS__DescriptorGet(self, metatable, key)
75
+ while metatable do
76
+ local rawResult = ____rawget(metatable, key)
77
+ if rawResult ~= nil then
78
+ return rawResult
79
+ end
80
+ local descriptors = ____rawget(metatable, "_descriptors")
81
+ if descriptors then
82
+ local descriptor = descriptors[key]
83
+ if descriptor ~= nil then
84
+ if descriptor.get then
85
+ return descriptor.get(self)
86
+ end
87
+ return descriptor.value
88
+ end
89
+ end
90
+ metatable = getmetatable(metatable)
91
+ end
92
+ end
93
+ end
94
+
95
+ local __TS__DescriptorSet
96
+ do
97
+ local getmetatable = _G.getmetatable
98
+ local ____rawget = _G.rawget
99
+ local rawset = _G.rawset
100
+ function __TS__DescriptorSet(self, metatable, key, value)
101
+ while metatable do
102
+ local descriptors = ____rawget(metatable, "_descriptors")
103
+ if descriptors then
104
+ local descriptor = descriptors[key]
105
+ if descriptor ~= nil then
106
+ if descriptor.set then
107
+ descriptor.set(self, value)
108
+ else
109
+ if descriptor.writable == false then
110
+ error(
111
+ ((("Cannot assign to read only property '" .. key) .. "' of object '") .. tostring(self)) .. "'",
112
+ 0
113
+ )
114
+ end
115
+ descriptor.value = value
116
+ end
117
+ return
118
+ end
119
+ end
120
+ metatable = getmetatable(metatable)
121
+ end
122
+ rawset(self, key, value)
123
+ end
124
+ end
125
+
126
+ local __TS__SetDescriptor
127
+ do
128
+ local getmetatable = _G.getmetatable
129
+ local function descriptorIndex(self, key)
130
+ return __TS__DescriptorGet(
131
+ self,
132
+ getmetatable(self),
133
+ key
134
+ )
135
+ end
136
+ local function descriptorNewIndex(self, key, value)
137
+ return __TS__DescriptorSet(
138
+ self,
139
+ getmetatable(self),
140
+ key,
141
+ value
142
+ )
143
+ end
144
+ function __TS__SetDescriptor(target, key, desc, isPrototype)
145
+ if isPrototype == nil then
146
+ isPrototype = false
147
+ end
148
+ local ____isPrototype_0
149
+ if isPrototype then
150
+ ____isPrototype_0 = target
151
+ else
152
+ ____isPrototype_0 = getmetatable(target)
153
+ end
154
+ local metatable = ____isPrototype_0
155
+ if not metatable then
156
+ metatable = {}
157
+ setmetatable(target, metatable)
158
+ end
159
+ if not isPrototype and not rawget(metatable, "_isOwnDescriptorMetatable") then
160
+ local instanceMetatable = {}
161
+ instanceMetatable._isOwnDescriptorMetatable = true
162
+ setmetatable(instanceMetatable, metatable)
163
+ setmetatable(target, instanceMetatable)
164
+ metatable = instanceMetatable
165
+ end
166
+ local value = rawget(target, key)
167
+ if value ~= nil then
168
+ rawset(target, key, nil)
169
+ end
170
+ if not rawget(metatable, "_descriptors") then
171
+ metatable._descriptors = {}
172
+ end
173
+ metatable._descriptors[key] = __TS__CloneDescriptor(desc)
174
+ metatable.__index = descriptorIndex
175
+ metatable.__newindex = descriptorNewIndex
176
+ end
177
+ end
178
+ -- End of Lua Library inline imports
179
+ local ____exports = {}
180
+ local ____TimerSource = require("datasources.TimerSource")
181
+ local TimerSource = ____TimerSource.TimerSource
182
+ local ____TextureSource = require("datasources.TextureSource")
183
+ local TextureSource = ____TextureSource.TextureSource
184
+ local ____UnitSource = require("datasources.UnitSource")
185
+ local resolveUnit = ____UnitSource.resolveUnit
186
+ --- Selected aura duration and icon; selection policy belongs to the application.
187
+ ____exports.AuraTimer = __TS__Class()
188
+ local AuraTimer = ____exports.AuraTimer
189
+ AuraTimer.name = "AuraTimer"
190
+ __TS__ClassExtends(AuraTimer, TimerSource)
191
+ function AuraTimer.prototype.____constructor(self, unit, options)
192
+ local target = resolveUnit(nil, unit)
193
+ local events = {
194
+ "UNIT_AURA",
195
+ "PLAYER_ENTERING_WORLD",
196
+ "PLAYER_TARGET_CHANGED",
197
+ "PLAYER_FOCUS_CHANGED",
198
+ "SPELLS_CHANGED"
199
+ }
200
+ TimerSource.prototype.____constructor(
201
+ self,
202
+ function() return self:ReadDuration() end,
203
+ events,
204
+ target.Token
205
+ )
206
+ self.options = options
207
+ self.status = "inactive"
208
+ self.target = target
209
+ self.Texture = __TS__New(
210
+ TextureSource,
211
+ function()
212
+ local ____opt_0 = self:ReadAura()
213
+ return ____opt_0 and ____opt_0.icon
214
+ end,
215
+ events,
216
+ target.Token
217
+ )
218
+ end
219
+ function AuraTimer.prototype.ReadAura(self)
220
+ local query = C_UnitAuras and C_UnitAuras.GetAuraDataBySpellName
221
+ local getName = C_Spell and C_Spell.GetSpellName
222
+ if query == nil or getName == nil then
223
+ self.status = "unavailable"
224
+ return nil
225
+ end
226
+ do
227
+ local function ____catch()
228
+ self.status = "unavailable"
229
+ end
230
+ local ____try, ____hasReturned, ____returnValue = pcall(function()
231
+ for ____, id in ipairs(self.options.spellIds) do
232
+ do
233
+ local __continue8
234
+ repeat
235
+ local name = getName(id)
236
+ if issecretvalue(name) then
237
+ self.status = "restricted"
238
+ return true, nil
239
+ end
240
+ if name == nil then
241
+ __continue8 = true
242
+ break
243
+ end
244
+ local aura = query(self.target.Token, name, self.options.filter or "HELPFUL")
245
+ if issecretvalue(aura) then
246
+ self.status = "restricted"
247
+ return true, nil
248
+ end
249
+ if aura ~= nil then
250
+ self.status = "active"
251
+ return true, aura
252
+ end
253
+ __continue8 = true
254
+ until true
255
+ if not __continue8 then
256
+ break
257
+ end
258
+ end
259
+ end
260
+ local ____opt_6 = C_Secrets and C_Secrets.ShouldAurasBeSecret
261
+ local restricted = ____opt_6 and ____opt_6()
262
+ self.status = (issecretvalue(restricted) or restricted == true) and "restricted" or "inactive"
263
+ end)
264
+ if not ____try then
265
+ ____hasReturned, ____returnValue = ____catch()
266
+ end
267
+ if ____hasReturned then
268
+ return ____returnValue
269
+ end
270
+ end
271
+ return nil
272
+ end
273
+ function AuraTimer.prototype.ReadDuration(self)
274
+ local aura = self:ReadAura()
275
+ if aura == nil then
276
+ return nil
277
+ end
278
+ do
279
+ local function ____catch()
280
+ self.status = "unavailable"
281
+ return true, nil
282
+ end
283
+ local ____try, ____hasReturned, ____returnValue = pcall(function()
284
+ local id = aura.auraInstanceID
285
+ if (C_UnitAuras and C_UnitAuras.GetAuraDuration) ~= nil and (issecretvalue(id) or id ~= nil) then
286
+ return true, C_UnitAuras.GetAuraDuration(self.target.Token, id)
287
+ end
288
+ local total = aura.duration
289
+ local ____end = aura.expirationTime
290
+ if issecretvalue(total) or issecretvalue(____end) then
291
+ self.status = "restricted"
292
+ return true, nil
293
+ end
294
+ if total == nil or ____end == nil or total <= 0 then
295
+ return true, nil
296
+ end
297
+ if C_DurationUtil == nil then
298
+ self.status = "unavailable"
299
+ return true, nil
300
+ end
301
+ local timer = C_DurationUtil.CreateDuration()
302
+ timer:SetTimeFromStart(____end - total, total)
303
+ return true, timer
304
+ end)
305
+ if not ____try then
306
+ ____hasReturned, ____returnValue = ____catch()
307
+ end
308
+ if ____hasReturned then
309
+ return ____returnValue
310
+ end
311
+ end
312
+ end
313
+ __TS__SetDescriptor(
314
+ AuraTimer.prototype,
315
+ "Status",
316
+ {get = function(self)
317
+ self:ReadAura()
318
+ return self.status
319
+ end},
320
+ true
321
+ )
322
+ return ____exports
@@ -0,0 +1,9 @@
1
+ import { TimerSource } from "./TimerSource";
2
+ import { UnitSource } from "./UnitSource";
3
+ import type { UnitInput } from "./UnitSource";
4
+ /** Remaining cast/channel time using the native duration object. */
5
+ export declare class CastTimer extends TimerSource {
6
+ readonly target: UnitSource;
7
+ get SpellName(): string;
8
+ constructor(unit?: UnitInput);
9
+ }