wuira 0.1.4 → 0.1.6
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 +102 -1
- package/README.md +347 -0
- package/lib/Spells.d.ts +21 -0
- package/lib/Spells.lua +41 -0
- package/lib/datasources/AuraTimer.d.ts +21 -0
- package/lib/datasources/AuraTimer.lua +322 -0
- package/lib/datasources/CastTimer.d.ts +9 -0
- package/lib/datasources/CastTimer.lua +240 -0
- package/lib/datasources/DataSource.d.ts +4 -0
- package/lib/datasources/DataSource.lua +24 -0
- package/lib/datasources/KnownSpells.d.ts +21 -0
- package/lib/datasources/KnownSpells.lua +794 -0
- package/lib/datasources/ManaRegenTimer.d.ts +29 -0
- package/lib/datasources/ManaRegenTimer.lua +674 -0
- package/lib/datasources/ProgressSource.d.ts +6 -2
- package/lib/datasources/ProgressSource.lua +34 -3
- package/lib/datasources/Resources.d.ts +33 -2
- package/lib/datasources/Resources.lua +562 -10
- package/lib/datasources/SpellCooldown.d.ts +12 -0
- package/lib/datasources/SpellCooldown.lua +218 -0
- package/lib/datasources/SpellSource.d.ts +14 -0
- package/lib/datasources/SpellSource.lua +224 -0
- package/lib/datasources/SwingTimer.d.ts +31 -0
- package/lib/datasources/SwingTimer.lua +641 -0
- package/lib/datasources/TextureSource.d.ts +10 -0
- package/lib/datasources/TextureSource.lua +83 -0
- package/lib/datasources/TimerSource.d.ts +20 -0
- package/lib/datasources/TimerSource.lua +338 -0
- package/lib/datasources/TotemTimer.d.ts +10 -0
- package/lib/datasources/TotemTimer.lua +260 -0
- package/lib/datasources/index.d.ts +16 -1
- package/lib/datasources/index.lua +43 -0
- package/lib/index.d.ts +11 -0
- package/lib/index.lua +24 -0
- package/lib/platform/ActionBars.d.ts +27 -0
- package/lib/platform/ActionBars.lua +726 -0
- package/lib/platform/AddonSettings.d.ts +9 -0
- package/lib/platform/AddonSettings.lua +36 -0
- package/lib/platform/BlizzardUI.d.ts +17 -0
- package/lib/platform/BlizzardUI.lua +689 -0
- package/lib/platform/MicroMenu.d.ts +15 -0
- package/lib/platform/MicroMenu.lua +219 -0
- package/lib/platform/SecureButton.d.ts +5 -0
- package/lib/platform/SecureButton.lua +196 -0
- package/lib/platform/SlashCommands.d.ts +3 -0
- package/lib/platform/SlashCommands.lua +309 -0
- package/lib/platform/forever.d.ts +115 -2
- package/lib/skins/MicroBar.d.ts +8 -0
- package/lib/skins/MicroBar.lua +65 -0
- package/lib/skins/NativeSkin.d.ts +26 -0
- package/lib/skins/NativeSkin.lua +601 -0
- package/lib/skins/index.d.ts +3 -0
- package/lib/skins/index.lua +11 -0
- package/lib/store/index.lua +13 -0
- package/lib/ui/Button.d.ts +10 -0
- package/lib/ui/Button.lua +9 -0
- package/lib/ui/Cell.d.ts +7 -1
- package/lib/ui/FrameMover.d.ts +21 -0
- package/lib/ui/FrameMover.lua +123 -0
- package/lib/ui/HoverTracker.d.ts +20 -0
- package/lib/ui/HoverTracker.lua +88 -0
- package/lib/ui/Icon.d.ts +8 -0
- package/lib/ui/Icon.lua +8 -0
- package/lib/ui/KeybindCapture.d.ts +20 -0
- package/lib/ui/KeybindCapture.lua +488 -0
- package/lib/ui/Label.d.ts +10 -0
- package/lib/ui/Label.lua +8 -0
- package/lib/ui/ProgressBar.d.ts +5 -1
- package/lib/ui/SecureButton.d.ts +44 -0
- package/lib/ui/SecureButton.lua +9 -0
- package/lib/ui/index.d.ts +13 -0
- package/lib/ui/index.lua +28 -0
- package/lib/ui/layout/measureLayout.lua +11 -2
- package/lib/ui/mount.lua +679 -74
- package/lib/ui/primitives/jsx.d.ts +15 -2
- package/lib/wuira.d.ts +3 -0
- package/lib/wuira.lua +5 -0
- package/package.json +8 -1
- package/tools/build-library.mjs +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -7,7 +7,108 @@ with the release date and highlight breaking changes explicitly.
|
|
|
7
7
|
|
|
8
8
|
## Unreleased
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
## 0.1.6 — 2026-10-14
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- `wuira.registerCommand("/command", callback)` registers native slash commands,
|
|
15
|
+
passes parsed arguments as `(...args: string[])` and returns idempotent cleanup.
|
|
16
|
+
Quoted arguments preserve spaces and empty values. Names are case-insensitive;
|
|
17
|
+
existing commands are preserved and native hash/proxy entries are cleaned up.
|
|
18
|
+
- Native `AddonSettings` canvas registration, normal JSX `Button` controls and
|
|
19
|
+
Cell `onMount` lifecycle callbacks with cleanup.
|
|
20
|
+
- Generic `FrameMover` drag proxies and `KeybindCapture` hover-to-bind overlays.
|
|
21
|
+
Both stop editing in combat; protected actions remain configured outside combat.
|
|
22
|
+
- `KnownSpells` caches learned player spellbook IDs, with rank-aware `Has`,
|
|
23
|
+
event-driven `onChange` subscriptions and disposal. World entry, level,
|
|
24
|
+
training and talent events refresh the list; reading it never polls the book.
|
|
25
|
+
- `Cell.alpha` accepts fixed opacity or a live visual callback, including on
|
|
26
|
+
secure buttons. Opacity updates do not enable, disable or rewrite actions.
|
|
27
|
+
- Named `Spells.HolyShock` and `Spells.Exorcism` identifiers.
|
|
28
|
+
- Named Paladin utility spell identifiers: Divine Favor, Lay on Hands, Blessing
|
|
29
|
+
of Protection, Blessing of Freedom, Voice of Truth, and Hammer of Justice.
|
|
30
|
+
- `TotemTimer` reads player-owned ground effects by spell ID or localized name,
|
|
31
|
+
matching ranks and passing opaque native durations directly to progress bars.
|
|
32
|
+
Restricted effect identities are not inspected or guessed.
|
|
33
|
+
- `SecureButton`, a Cell-compatible JSX primitive backed by Forever's native
|
|
34
|
+
`SecureActionButtonTemplate`. Supports static spell, item, existing macro,
|
|
35
|
+
action-slot and target actions, a selected mouse button, and one visual child.
|
|
36
|
+
Native click handlers are preserved; actions execute on mouse release.
|
|
37
|
+
Protected trees must mount outside combat; visibility and unmount are deferred
|
|
38
|
+
until combat ends. Click-cast presets are not included yet.
|
|
39
|
+
- Secure buttons accept temporary `binding` overrides with native key labels,
|
|
40
|
+
radial `cooldown` sources and a native completion flash through `finishGlow`.
|
|
41
|
+
Overrides are removed on unmount without changing saved key bindings.
|
|
42
|
+
- `SpellSource` exposes localized secure actions, textures and cooldowns that
|
|
43
|
+
ignore the global cooldown. Added Judgement, Holy Strike and Consecration IDs.
|
|
44
|
+
- `BlizzardUI.SkinMicroMenu()` styles Forever's existing micro menu with a flat
|
|
45
|
+
panel, muted icons and accent highlights. Native click handlers, tooltips,
|
|
46
|
+
notifications and layout remain owned by the game; styling waits during combat.
|
|
47
|
+
- `wuira/skins` with `MicroBar` and a shared `NativeSkin` adapter. `render` receives
|
|
48
|
+
the adapter, including `mount(view, anchor)` and `OnHover`; custom mounts are
|
|
49
|
+
disposed with the skin without replacing native button scripts.
|
|
50
|
+
- Generic `HoverTracker` secure trigger/popup frames, configurable auto-hide delay
|
|
51
|
+
and extra hover regions. Addons own layout, launcher presentation and themes.
|
|
52
|
+
- Explicit action-slot capture/clear/restore APIs and opt-in empty native bars.
|
|
53
|
+
New backups require a manual reload before the explicit clear command. Native bar
|
|
54
|
+
descendants, event/update managers, and action UI registrations are disabled;
|
|
55
|
+
suppression runs independently of slot operations. Clear/restore never run
|
|
56
|
+
from world-entry or cursor events; refused calls are reported without automatic
|
|
57
|
+
retries. A restore command re-enables the stock UI after manual reload. No replacement bar
|
|
58
|
+
is created. Unsupported action types and conflicting restores are rejected.
|
|
59
|
+
- Resource `onChange` subscriptions with unsubscribe callbacks. Widgets and
|
|
60
|
+
observers share one lazy native event listener per resource, reading its
|
|
61
|
+
current value once per event. Secret amounts never reach user callbacks.
|
|
62
|
+
- `Mana.UseRegenTimer()` and its `RegenTimer` accessory: a cast-driven five-second
|
|
63
|
+
window followed by estimated two-second sweeps kept alive by mana events.
|
|
64
|
+
Full readable mana stops the clock; native alpha curves mask full secret mana.
|
|
65
|
+
Unmount cancels timers and detaches the accessory without stopping other users.
|
|
66
|
+
|
|
67
|
+
### Fixed
|
|
68
|
+
|
|
69
|
+
- Preserve saved entries in initially empty Store records when loading a new
|
|
70
|
+
registry; Lua's empty-table ambiguity no longer resets custom binding maps.
|
|
71
|
+
- Honor explicit non-top-left anchors on a Cell's child, allowing thin overlays
|
|
72
|
+
to sit on the bottom edge of a progress bar.
|
|
73
|
+
|
|
74
|
+
## 0.1.5 — 2026-10-14
|
|
75
|
+
|
|
76
|
+
### Added
|
|
77
|
+
|
|
78
|
+
- Event-driven `.When(value => boolean)` source conditions. Inactive bindings
|
|
79
|
+
hide their visual and skip writes; secret inputs never reach callbacks.
|
|
80
|
+
Repeated conditions combine with AND, and fresh `.Value` reads remain unchanged.
|
|
81
|
+
- Opt-in `HP.UseHealPrediction()` and `HP.UseAbsorbPrediction()` channels,
|
|
82
|
+
with lazy allocation, capability checks, and optional event subscriptions.
|
|
83
|
+
- Independently styled healing and shield overlays on HP progress bars,
|
|
84
|
+
including direct native handling of secret amounts and clipping at bar bounds.
|
|
85
|
+
- Opt-in `BlizzardUI.Hide` for stock action bars and player/target/focus frames,
|
|
86
|
+
with combat deferral and a restore callback, preserving native event handlers.
|
|
87
|
+
- Cell visibility predicates and live label text, with cleanup on unmount.
|
|
88
|
+
- Timer activity flags and cast/channel spell names for conditional UI rows.
|
|
89
|
+
- Public `Spells` enum with named Paladin Seal spell IDs.
|
|
90
|
+
- Player swing countdown sources for main-hand, off-hand, and ranged attacks,
|
|
91
|
+
driven by Forever's native swing events and native StatusBar timer animation.
|
|
92
|
+
- Explicit unknown timing before the first readable event, secret-value guards,
|
|
93
|
+
weapon-change resets, and source disposal.
|
|
94
|
+
- Label and Icon primitives, with event-driven texture sources.
|
|
95
|
+
- Native duration sources for aura timers, spell/global cooldowns, and cast/channel
|
|
96
|
+
countdowns. Selected aura icons share the aura source's selection policy.
|
|
97
|
+
|
|
98
|
+
### Fixed
|
|
99
|
+
|
|
100
|
+
- Initialize native timer and swing bars with a normalized 0–1 range instead
|
|
101
|
+
of the default resource range.
|
|
102
|
+
- Mount lifecycle now runs datasource binding cleanup callbacks on unmount.
|
|
103
|
+
|
|
104
|
+
### Validation and limitations
|
|
105
|
+
|
|
106
|
+
- Lua tests cover conditional activation/reactivation, secret callback guards,
|
|
107
|
+
optional prediction reads/events, overlay placement, and unmount cleanup.
|
|
108
|
+
- Prediction amounts require the client's native unit APIs. Incoming healing
|
|
109
|
+
is raw (not reduced by heal-absorb debuffs); overheal is visually clipped.
|
|
110
|
+
HP overrides are incompatible with prediction overlays. In-game prediction
|
|
111
|
+
visuals still need validation in Forever.
|
|
11
112
|
|
|
12
113
|
## 0.1.4 — 2026-10-14
|
|
13
114
|
|
package/README.md
CHANGED
|
@@ -94,6 +94,353 @@ 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
|
+
### Slash commands
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
import { wuira } from "wuira";
|
|
149
|
+
|
|
150
|
+
const unregister = wuira.registerCommand("/myaddon", (...args: string[]) => {
|
|
151
|
+
console.log("Arguments:", ...args);
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
// /myaddon arg1 arg2 arg3 passes three string arguments.
|
|
155
|
+
// /myaddon alone calls the callback with no arguments.
|
|
156
|
+
// Call unregister() when the command is no longer needed.
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
Command names start with a slash and a letter, followed by letters, digits,
|
|
160
|
+
underscores or hyphens. Names are case-insensitive and cannot replace an existing
|
|
161
|
+
command. Register aliases separately with the same callback.
|
|
162
|
+
|
|
163
|
+
Arguments are separated by whitespace and retain their case. Single or double
|
|
164
|
+
quotes group words into one argument; `""` passes an empty string. Within quotes,
|
|
165
|
+
a backslash can escape the matching quote or another backslash. An unclosed quote
|
|
166
|
+
reports an error without calling the callback. Argument counts are unrestricted;
|
|
167
|
+
validate required arguments inside your callback.
|
|
168
|
+
|
|
169
|
+
### Addon settings and editing tools
|
|
170
|
+
|
|
171
|
+
Register a normal JSX view in Forever's native addon settings list:
|
|
172
|
+
|
|
173
|
+
```tsx
|
|
174
|
+
import { UI, AddonSettings } from "wuira";
|
|
175
|
+
import { FlowLayout, Button, Label } from "wuira/ui";
|
|
176
|
+
|
|
177
|
+
const settings = new AddonSettings("MyAddon", () => (
|
|
178
|
+
<FlowLayout width={560} height={300} padding={20} gap={12}>
|
|
179
|
+
<Label height={28} text="MyAddon settings" />
|
|
180
|
+
<Button width={180} height={32} onClick={() => console.log("Settings opened")}>
|
|
181
|
+
<Label text="Example control" align="CENTER" />
|
|
182
|
+
</Button>
|
|
183
|
+
</FlowLayout>
|
|
184
|
+
));
|
|
185
|
+
settings.Open();
|
|
186
|
+
```
|
|
187
|
+
|
|
188
|
+
`Cell.onMount` receives the configured native frame and may return an unmount
|
|
189
|
+
cleanup. `FrameMover` provides a drag proxy with screen-center coordinates
|
|
190
|
+
(positive y down). `KeybindCapture` provides hover-to-bind overlays, modifier keys,
|
|
191
|
+
Delete/Backspace clearing, and an Escape callback. These tools stop editing in
|
|
192
|
+
combat. Addons own mode controls, saved positions, binding conflict policy and
|
|
193
|
+
rebuilding protected buttons outside combat.
|
|
194
|
+
|
|
195
|
+
### Learned spells
|
|
196
|
+
|
|
197
|
+
`KnownSpells` keeps a cached snapshot of learned player spellbook IDs. It refreshes
|
|
198
|
+
on world entry, level, training and talent events without polling. Named entries
|
|
199
|
+
in `Spells` are numeric IDs; `Has` also matches a representative ID against learned
|
|
200
|
+
ranks by localized name. Future and inactive-spec spellbook entries are excluded.
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
import { Spells } from "wuira";
|
|
204
|
+
import { KnownSpells } from "wuira/datasources";
|
|
205
|
+
|
|
206
|
+
const known = new KnownSpells();
|
|
207
|
+
const spellIds = known.Value; // readonly number[], read from the cache
|
|
208
|
+
const canJudge = known.Has(Spells.Judgement);
|
|
209
|
+
const stop = known.onChange(ids => console.log("Learned spells:", ids.length));
|
|
210
|
+
// On disposal: stop(); known.Dispose();
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
Protected button trees must be rebuilt outside combat; applications can defer a
|
|
214
|
+
changed selection until `PLAYER_REGEN_ENABLED`. `Cell.alpha` changes appearance
|
|
215
|
+
without changing a button's protected action or its interaction state.
|
|
216
|
+
|
|
217
|
+
### Empty native action bars
|
|
218
|
+
|
|
219
|
+
This is opt-in and removes real action-slot assignments, not just their visuals.
|
|
220
|
+
Declare a character-specific backup variable in the addon's TOC:
|
|
221
|
+
|
|
222
|
+
```text
|
|
223
|
+
## SavedVariablesPerCharacter: MyAddonActionBarBackup
|
|
224
|
+
```
|
|
225
|
+
|
|
226
|
+
```ts
|
|
227
|
+
import { ActionBars } from "wuira";
|
|
228
|
+
|
|
229
|
+
ActionBars.InstallEmptyMode({
|
|
230
|
+
addon: "MyAddon",
|
|
231
|
+
variable: "MyAddonActionBarBackup",
|
|
232
|
+
clearCommand: "/myaddonclearbars",
|
|
233
|
+
restoreCommand: "/myaddonrestorebars",
|
|
234
|
+
});
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
The first world entry captures supported spell, item, and macro assignments.
|
|
238
|
+
Use `/reload` to persist a new backup, then `/myaddonclearbars` outside combat to
|
|
239
|
+
clear the 180 action slots used by the installed Forever implementation. Slot
|
|
240
|
+
changes run directly from the command, never from world-entry or cursor events.
|
|
241
|
+
Independently, initialization hides stock bars, removes their descendant event/update handlers, disables their
|
|
242
|
+
shared action-bar event managers, and detaches native action UI registrations.
|
|
243
|
+
It does not create a replacement bar or remove key-binding assignments.
|
|
244
|
+
Changes wait until combat ends, and a busy cursor blocks slot changes.
|
|
245
|
+
|
|
246
|
+
The restore command puts assignments back into empty or identical slots. Use
|
|
247
|
+
`/reload` afterwards to restore native handlers and visibility. The stock bars
|
|
248
|
+
remain enabled on future loads. A refused slot operation leaves bar suppression
|
|
249
|
+
active and is not automatically retried. Blocked/forbidden native calls report
|
|
250
|
+
their API name in the local console; command execution does not bypass client restrictions.
|
|
251
|
+
Unsupported action types, secret slot data, uncovered assignments, and conflicting
|
|
252
|
+
restores stop the operation. `Capture()`, `Clear(backup)`, and `Restore(backup)` are
|
|
253
|
+
also available for applications that manage their own persistence and lifecycle.
|
|
254
|
+
|
|
255
|
+
### Secure action buttons
|
|
256
|
+
|
|
257
|
+
`SecureButton` extends Cell's descriptor and props, including size, positioning,
|
|
258
|
+
decorations and one child. Mount it like any other component:
|
|
259
|
+
|
|
260
|
+
```tsx
|
|
261
|
+
import { UI, wuira } from "wuira";
|
|
262
|
+
import { SecureButton, Label } from "wuira/ui";
|
|
263
|
+
|
|
264
|
+
wuira.Mount(() => (
|
|
265
|
+
<SecureButton width={80} height={24}
|
|
266
|
+
action={{ type: "spell", spell: 635, unit: "player" }}>
|
|
267
|
+
<Label text="Holy Light" align="CENTER" />
|
|
268
|
+
</SecureButton>
|
|
269
|
+
));
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
Supported actions are `{ type: "spell", spell, unit? }`,
|
|
273
|
+
`{ type: "item", item, unit? }`, `{ type: "macro", macro }`,
|
|
274
|
+
`{ type: "action", slot, unit? }` and `{ type: "target", unit }`.
|
|
275
|
+
Spell and macro references accept IDs/indices or names. Items accept an ID
|
|
276
|
+
(converted to `item:ID`) or the native item string. Macros refer to existing
|
|
277
|
+
game macros, not arbitrary Lua callbacks or generated macro text.
|
|
278
|
+
|
|
279
|
+
The default is left-button release; `button="RightButton"` selects another
|
|
280
|
+
button. Secure buttons always receive mouse input, while visual children remain
|
|
281
|
+
click-through by default. Omitting `action` creates an inert secure button.
|
|
282
|
+
|
|
283
|
+
Actions and units are static mount-time attributes. Changing the descriptor
|
|
284
|
+
later does not rewrite them. Mounting a protected tree during combat raises an
|
|
285
|
+
error before any frame is created. Visibility changes and unmount requests wait
|
|
286
|
+
until combat ends, including changes to ancestors containing secure buttons.
|
|
287
|
+
Click-cast presets are not provided by this primitive yet. The native action mapping
|
|
288
|
+
follows [Forever's secure templates](https://github.com/Gethe/wow-ui-source/blob/forever/Interface/AddOns/Blizzard_FrameXML/SecureTemplates.lua).
|
|
289
|
+
|
|
290
|
+
For an icon action with a radial cooldown and temporary key binding:
|
|
291
|
+
|
|
292
|
+
```tsx
|
|
293
|
+
import { Spells } from "wuira";
|
|
294
|
+
import { SpellSource } from "wuira/datasources";
|
|
295
|
+
import { Icon } from "wuira/ui";
|
|
296
|
+
|
|
297
|
+
const judgement = new SpellSource(Spells.Judgement);
|
|
298
|
+
const button = (
|
|
299
|
+
<SecureButton width={40} height={40} action={judgement.Action}
|
|
300
|
+
binding="1" cooldown={judgement.Cooldown} finishGlow>
|
|
301
|
+
<Icon textureSource={judgement.Texture} />
|
|
302
|
+
</SecureButton>
|
|
303
|
+
);
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
`binding` temporarily routes the key to this native button and adds its label;
|
|
307
|
+
`showHotkey={false}` suppresses the label. Unmount removes the override and leaves
|
|
308
|
+
saved bindings intact. The radial widget owns countdown timing and the short
|
|
309
|
+
completion flash, including opaque combat durations. `SpellSource.Cooldown`
|
|
310
|
+
ignores the GCD so unrelated casts do not trigger a completion flash.
|
|
311
|
+
|
|
312
|
+
### Native skins
|
|
313
|
+
|
|
314
|
+
Skin Forever's existing character, professions, spellbook and other micro-menu
|
|
315
|
+
buttons while keeping the game's click handlers, tooltips and notifications:
|
|
316
|
+
|
|
317
|
+
```tsx
|
|
318
|
+
import { UI } from "wuira";
|
|
319
|
+
import { MicroBar } from "wuira/skins";
|
|
320
|
+
import { Cell, Background } from "wuira/ui";
|
|
321
|
+
|
|
322
|
+
const micro = new MicroBar();
|
|
323
|
+
micro.render(bar => {
|
|
324
|
+
bar.Style({
|
|
325
|
+
background: { r: 0.035, g: 0.045, b: 0.065, a: 0.9 },
|
|
326
|
+
accent: { r: 0.4, g: 0.75, b: 1 },
|
|
327
|
+
padding: 6,
|
|
328
|
+
});
|
|
329
|
+
bar.mount(() => (
|
|
330
|
+
<Cell width={12} height={2} decorations={{
|
|
331
|
+
background: new Background({ color: { r: 0.4, g: 0.75, b: 1 } }),
|
|
332
|
+
}} />
|
|
333
|
+
), "TOP");
|
|
334
|
+
bar.OnHover(hovered => console.log("Micro menu hover:", hovered));
|
|
335
|
+
return bar;
|
|
336
|
+
});
|
|
337
|
+
```
|
|
338
|
+
|
|
339
|
+
`render` receives the skin adapter once its game-owned frame is ready. The same
|
|
340
|
+
object exposes `Frame`, `Style`, `OnHover`, and `mount`; mounts become children of
|
|
341
|
+
the native frame and are released by `Dispose()`. Native clicks, events and
|
|
342
|
+
tooltips remain intact. Rendering waits until combat ends.
|
|
343
|
+
|
|
344
|
+
`HoverTracker` supplies generic secure trigger/popup frames and auto-hide regions;
|
|
345
|
+
the addon owns their visuals, contents and positioning. Compact menu launchers
|
|
346
|
+
and themes belong in the consuming UI rather than the framework. Hover callbacks
|
|
347
|
+
are ordinary addon callbacks; use secure hover visibility for protected panels.
|
|
348
|
+
|
|
349
|
+
`BlizzardUI.SkinMicroMenu(options)` is also available for styling alone. Stopping
|
|
350
|
+
styling hides its added panel; reload restores original native textures.
|
|
351
|
+
|
|
352
|
+
### Resource observation and mana regen
|
|
353
|
+
|
|
354
|
+
Resource changes can also be observed without mounting a widget:
|
|
355
|
+
|
|
356
|
+
```ts
|
|
357
|
+
const mana = new Mana(Unit.Player).UseRegenTimer();
|
|
358
|
+
const unsubscribe = mana.onChange(value => console.log(value));
|
|
359
|
+
// Call unsubscribe() when this consumer is removed.
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
`onChange` reports future readable value changes, with no initial callback.
|
|
363
|
+
It honors `.When()` and never sends secret values to user code. Native bar
|
|
364
|
+
bindings still accept secret values directly. Bars, observers, and the regen
|
|
365
|
+
accessory share one lazy native event listener; it unregisters when the last
|
|
366
|
+
consumer detaches. `.Value` is still available for a one-time read.
|
|
367
|
+
|
|
368
|
+
`mana.RegenTimer` can be bound to a thin `ProgressBar`. Its `Phase` is
|
|
369
|
+
`fiveSecondRule`, `estimatedTick`, or `inactive`. Successful mana-cost casts
|
|
370
|
+
start/restart a five-second window, followed by estimated two-second cycles.
|
|
371
|
+
Mana events keep those cycles alive without resetting a running cycle. No
|
|
372
|
+
server tick clock is exposed: this is an estimate, including when the cost is
|
|
373
|
+
secret. Zero-cost casts do not restart the window. The native widget animates
|
|
374
|
+
the fill; one-shot callbacks handle phase transitions, with no Lua frame polling.
|
|
375
|
+
Full readable mana cancels the clock. When mana is secret, a native step curve
|
|
376
|
+
hides full mana visually; Lua cannot use that hidden result to dispose the timer,
|
|
377
|
+
so the estimate stops when mana events cease. The frame is reused on the next
|
|
378
|
+
cast. Configure this player-only accessory before mounting.
|
|
379
|
+
|
|
380
|
+
### Native aura, cooldown, and cast timers
|
|
381
|
+
|
|
382
|
+
```tsx
|
|
383
|
+
import { UI, Spells } from "wuira";
|
|
384
|
+
import { FlowLayout, ProgressBar, Icon, Label } from "wuira/ui";
|
|
385
|
+
import { AuraTimer, GlobalCooldown, CastTimer, Unit } from "wuira/datasources";
|
|
386
|
+
|
|
387
|
+
const aura = new AuraTimer(Unit.Player, { spellIds: [Spells.SealOfRighteousness], filter: "HELPFUL" });
|
|
388
|
+
const gcd = new GlobalCooldown();
|
|
389
|
+
const cast = new CastTimer(Unit.Player);
|
|
390
|
+
|
|
391
|
+
function Timers() {
|
|
392
|
+
return (
|
|
393
|
+
<FlowLayout width={200} height={94} direction="vertical" gap={2}>
|
|
394
|
+
<Icon width={24} height={24} textureSource={aura.Texture} />
|
|
395
|
+
<ProgressBar height={24} source={aura}><Label text="Aura" /></ProgressBar>
|
|
396
|
+
<ProgressBar height={18} source={gcd} />
|
|
397
|
+
<ProgressBar height={22} source={cast} />
|
|
398
|
+
</FlowLayout>
|
|
399
|
+
);
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
These timers pass opaque native duration objects to `SetTimerDuration`; they do
|
|
404
|
+
not calculate restricted durations in Lua. `SpellCooldown(spellId)` tracks a
|
|
405
|
+
specific spell, and `GlobalCooldown` supplies the GCD identifier internally.
|
|
406
|
+
`CastTimer` follows casts and channels. `AuraTimer` resolves localized spell names
|
|
407
|
+
and exposes an associated `Texture` source, with status indicating active,
|
|
408
|
+
inactive, restricted, or unavailable data. Aura access still follows the client's
|
|
409
|
+
restrictions; missing readable data is not reconstructed from combat events.
|
|
410
|
+
`Label` and `Icon` are visual Cells. Application code supplies which spells to
|
|
411
|
+
track; native API declarations and reads remain in wuira.
|
|
412
|
+
|
|
413
|
+
### Swing timers
|
|
414
|
+
|
|
415
|
+
```tsx
|
|
416
|
+
import { UI, wuira } from "wuira";
|
|
417
|
+
import { ProgressBar } from "wuira/ui";
|
|
418
|
+
import { SwingTimer, SwingHand } from "wuira/datasources";
|
|
419
|
+
|
|
420
|
+
const mainHand = new SwingTimer(SwingHand.MainHand);
|
|
421
|
+
const view = wuira.Mount(<ProgressBar width={200} height={12} source={mainHand} />);
|
|
422
|
+
|
|
423
|
+
// Other choices: SwingHand.OffHand and SwingHand.Ranged.
|
|
424
|
+
// mainHand.Value: remaining seconds; Max.Value: duration; Percent.Value: remaining percent.
|
|
425
|
+
// When removing the feature:
|
|
426
|
+
if (view !== undefined) wuira.Unmount(view);
|
|
427
|
+
mainHand.Dispose();
|
|
428
|
+
```
|
|
429
|
+
|
|
430
|
+
This source follows the player's `PLAYER_SWING(duration, swingType)` events.
|
|
431
|
+
It does not reconstruct swings from the combat log or track enemy attack cycles.
|
|
432
|
+
`HasTiming` is false until the first readable event and after a weapon/world reset;
|
|
433
|
+
zero before that event is not evidence of a synchronized swing. After a recorded
|
|
434
|
+
cycle expires, remaining time reaches zero. Secret payloads block datasource
|
|
435
|
+
computation until a readable event or reset arrives.
|
|
436
|
+
|
|
437
|
+
Native progress binding uses `C_DurationUtil` and `StatusBar:SetTimerDuration`,
|
|
438
|
+
with no Lua per-frame animation. Range/current overrides are not supported for
|
|
439
|
+
this binding. Unmount detaches each bar; call `Dispose()` to stop the source's
|
|
440
|
+
event listener when its owning feature ends. Support is capability-checked;
|
|
441
|
+
actual timing still needs validation in Forever. The adapter follows the
|
|
442
|
+
[Forever swing API definition](https://github.com/Gethe/wow-ui-source/blob/bd2470aed543f72697a044e989285b6c83e63f73/Interface/AddOns/Blizzard_APIDocumentationGenerated/SwingTimerDocumentation.lua).
|
|
443
|
+
|
|
97
444
|
### Group members
|
|
98
445
|
|
|
99
446
|
```ts
|
package/lib/Spells.d.ts
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** Representative spell IDs; aura sources resolve localized names across ranks. */
|
|
2
|
+
export declare enum Spells {
|
|
3
|
+
Judgement = 20271,
|
|
4
|
+
HolyStrike = 679,
|
|
5
|
+
Consecration = 26573,
|
|
6
|
+
HolyShock = 20473,
|
|
7
|
+
Exorcism = 879,
|
|
8
|
+
DivineFavor = 20216,
|
|
9
|
+
LayOnHands = 633,
|
|
10
|
+
BlessingOfProtection = 1022,
|
|
11
|
+
BlessingOfFreedom = 1044,
|
|
12
|
+
VoiceOfTruth = 1310897,
|
|
13
|
+
HammerOfJustice = 853,
|
|
14
|
+
SealOfRighteousness = 21084,
|
|
15
|
+
SealOfTheCrusader = 21082,
|
|
16
|
+
SealOfCommand = 20375,
|
|
17
|
+
SealOfJustice = 20164,
|
|
18
|
+
SealOfLight = 20165,
|
|
19
|
+
SealOfWisdom = 20166,
|
|
20
|
+
SealOfFury = 20163
|
|
21
|
+
}
|
package/lib/Spells.lua
ADDED
|
@@ -0,0 +1,41 @@
|
|
|
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.Judgement = 20271
|
|
6
|
+
____exports.Spells[____exports.Spells.Judgement] = "Judgement"
|
|
7
|
+
____exports.Spells.HolyStrike = 679
|
|
8
|
+
____exports.Spells[____exports.Spells.HolyStrike] = "HolyStrike"
|
|
9
|
+
____exports.Spells.Consecration = 26573
|
|
10
|
+
____exports.Spells[____exports.Spells.Consecration] = "Consecration"
|
|
11
|
+
____exports.Spells.HolyShock = 20473
|
|
12
|
+
____exports.Spells[____exports.Spells.HolyShock] = "HolyShock"
|
|
13
|
+
____exports.Spells.Exorcism = 879
|
|
14
|
+
____exports.Spells[____exports.Spells.Exorcism] = "Exorcism"
|
|
15
|
+
____exports.Spells.DivineFavor = 20216
|
|
16
|
+
____exports.Spells[____exports.Spells.DivineFavor] = "DivineFavor"
|
|
17
|
+
____exports.Spells.LayOnHands = 633
|
|
18
|
+
____exports.Spells[____exports.Spells.LayOnHands] = "LayOnHands"
|
|
19
|
+
____exports.Spells.BlessingOfProtection = 1022
|
|
20
|
+
____exports.Spells[____exports.Spells.BlessingOfProtection] = "BlessingOfProtection"
|
|
21
|
+
____exports.Spells.BlessingOfFreedom = 1044
|
|
22
|
+
____exports.Spells[____exports.Spells.BlessingOfFreedom] = "BlessingOfFreedom"
|
|
23
|
+
____exports.Spells.VoiceOfTruth = 1310897
|
|
24
|
+
____exports.Spells[____exports.Spells.VoiceOfTruth] = "VoiceOfTruth"
|
|
25
|
+
____exports.Spells.HammerOfJustice = 853
|
|
26
|
+
____exports.Spells[____exports.Spells.HammerOfJustice] = "HammerOfJustice"
|
|
27
|
+
____exports.Spells.SealOfRighteousness = 21084
|
|
28
|
+
____exports.Spells[____exports.Spells.SealOfRighteousness] = "SealOfRighteousness"
|
|
29
|
+
____exports.Spells.SealOfTheCrusader = 21082
|
|
30
|
+
____exports.Spells[____exports.Spells.SealOfTheCrusader] = "SealOfTheCrusader"
|
|
31
|
+
____exports.Spells.SealOfCommand = 20375
|
|
32
|
+
____exports.Spells[____exports.Spells.SealOfCommand] = "SealOfCommand"
|
|
33
|
+
____exports.Spells.SealOfJustice = 20164
|
|
34
|
+
____exports.Spells[____exports.Spells.SealOfJustice] = "SealOfJustice"
|
|
35
|
+
____exports.Spells.SealOfLight = 20165
|
|
36
|
+
____exports.Spells[____exports.Spells.SealOfLight] = "SealOfLight"
|
|
37
|
+
____exports.Spells.SealOfWisdom = 20166
|
|
38
|
+
____exports.Spells[____exports.Spells.SealOfWisdom] = "SealOfWisdom"
|
|
39
|
+
____exports.Spells.SealOfFury = 20163
|
|
40
|
+
____exports.Spells[____exports.Spells.SealOfFury] = "SealOfFury"
|
|
41
|
+
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
|
+
}
|