wuira 0.2.0 → 0.2.2
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 +23 -0
- package/README.md +32 -15
- package/lib/WuiraApp.d.ts +12 -0
- package/lib/WuiraApp.lua +425 -0
- package/lib/datasources/EditModeLayouts.d.ts +33 -0
- package/lib/datasources/EditModeLayouts.lua +689 -0
- package/lib/datasources/index.d.ts +2 -0
- package/lib/datasources/index.lua +4 -0
- package/lib/index.d.ts +2 -1
- package/lib/index.lua +5 -0
- package/lib/platform/forever.d.ts +1 -0
- package/lib/rendering/decorations.d.ts +2 -0
- package/lib/rendering/decorations.lua +42 -0
- package/lib/rendering/layout.d.ts +16 -0
- package/lib/rendering/layout.lua +594 -0
- package/lib/rendering/progress.d.ts +2 -0
- package/lib/rendering/progress.lua +196 -0
- package/lib/rendering/secureButton.d.ts +2 -0
- package/lib/rendering/secureButton.lua +46 -0
- package/lib/rendering/types.d.ts +25 -0
- package/lib/rendering/types.lua +3 -0
- package/lib/rendering/updates.d.ts +3 -0
- package/lib/rendering/updates.lua +30 -0
- package/lib/rendering/visibility.d.ts +6 -0
- package/lib/rendering/visibility.lua +85 -0
- package/lib/rendering/widgets.d.ts +4 -0
- package/lib/rendering/widgets.lua +83 -0
- package/lib/wuira.d.ts +8 -4
- package/lib/wuira.lua +215 -27
- package/package.json +1 -1
- package/templates/addon/src/index.tsx +2 -2
- package/lib/ui/mount.d.ts +0 -5
- package/lib/ui/mount.lua +0 -1107
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,29 @@ with the release date and highlight breaking changes explicitly.
|
|
|
7
7
|
|
|
8
8
|
## Unreleased
|
|
9
9
|
|
|
10
|
+
## 0.2.2 — 2026-10-15
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- Event-driven EditModeLayouts source with native layout metadata, active layout,
|
|
15
|
+
availability status and disposable change subscriptions. Layout keys use native
|
|
16
|
+
type, interface style and name; indices are not persistent IDs.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Keep generated spell files in LF format on Windows checkouts so deterministic
|
|
21
|
+
generation checks compare identical bytes across operating systems.
|
|
22
|
+
|
|
23
|
+
## 0.2.1 — 2026-10-15
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- Make Wuira the static accessor for the addon's WuiraApp instance, which owns
|
|
28
|
+
mounted trees and their lifecycle. Keep wuira as a compatibility alias.
|
|
29
|
+
- Move the renderer out of ui/mount.ts into WuiraApp and focused rendering
|
|
30
|
+
helpers for geometry, widgets, visibility, decorations and updates.
|
|
31
|
+
- Generate new addon entry points using Wuira.Mount.
|
|
32
|
+
|
|
10
33
|
## 0.2.0 — 2026-10-15
|
|
11
34
|
|
|
12
35
|
### Removed
|
package/README.md
CHANGED
|
@@ -8,7 +8,7 @@ wuira is a UI framework and addon toolchain for developers who want to describe
|
|
|
8
8
|
|
|
9
9
|
An interface should be easy to understand by reading its source. A health display can be a progress bar inside a layout; a player display can be a composition of bars, labels, and icons rather than a special unit-frame class. wuira provides the foundations for that approach, with TypeScript checking your component props before the addon reaches the game.
|
|
10
10
|
|
|
11
|
-
The snippets below use the lowercase JSX primitives. In a generated project, import `{ UI,
|
|
11
|
+
The snippets below use the lowercase JSX primitives. In a generated project, import `{ UI, Wuira }` from `wuira` before mounting a view. Each view example is independent. Wuira is a static accessor; Wuira.App is the current addon's WuiraApp instance and owns its mounted trees and cleanup. Separate addons keep independent application state. The lowercase wuira export remains available for existing addons.
|
|
12
12
|
|
|
13
13
|
### JSX composition
|
|
14
14
|
|
|
@@ -29,7 +29,7 @@ function App() {
|
|
|
29
29
|
);
|
|
30
30
|
}
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
Wuira.Mount(App);
|
|
33
33
|
```
|
|
34
34
|
|
|
35
35
|
### Native widgets
|
|
@@ -48,7 +48,7 @@ const view = (
|
|
|
48
48
|
/>
|
|
49
49
|
);
|
|
50
50
|
|
|
51
|
-
|
|
51
|
+
Wuira.Mount(view);
|
|
52
52
|
```
|
|
53
53
|
|
|
54
54
|
### Layout primitives
|
|
@@ -65,7 +65,7 @@ const view = (
|
|
|
65
65
|
</flow>
|
|
66
66
|
);
|
|
67
67
|
|
|
68
|
-
|
|
68
|
+
Wuira.Mount(view);
|
|
69
69
|
```
|
|
70
70
|
|
|
71
71
|
For rows and columns, use `<grid columns={2} gap={8}>` with an explicit width and height.
|
|
@@ -91,7 +91,7 @@ function App() {
|
|
|
91
91
|
);
|
|
92
92
|
}
|
|
93
93
|
|
|
94
|
-
|
|
94
|
+
Wuira.Mount(App);
|
|
95
95
|
```
|
|
96
96
|
|
|
97
97
|
### Conditional sources and health predictions
|
|
@@ -145,9 +145,9 @@ cleans up the overlays and resource subscriptions on unmount.
|
|
|
145
145
|
### Slash commands
|
|
146
146
|
|
|
147
147
|
```ts
|
|
148
|
-
import {
|
|
148
|
+
import { Wuira } from "wuira";
|
|
149
149
|
|
|
150
|
-
const unregister =
|
|
150
|
+
const unregister = Wuira.registerCommand("/myaddon", (...args: string[]) => {
|
|
151
151
|
console.log("Arguments:", ...args);
|
|
152
152
|
});
|
|
153
153
|
|
|
@@ -324,10 +324,10 @@ also available for applications that manage their own persistence and lifecycle.
|
|
|
324
324
|
decorations and one child. Mount it like any other component:
|
|
325
325
|
|
|
326
326
|
```tsx
|
|
327
|
-
import { UI,
|
|
327
|
+
import { UI, Wuira } from "wuira";
|
|
328
328
|
import { SecureButton, Label } from "wuira/ui";
|
|
329
329
|
|
|
330
|
-
|
|
330
|
+
Wuira.Mount(() => (
|
|
331
331
|
<SecureButton width={80} height={24}
|
|
332
332
|
action={{ type: "spell", spell: 635, unit: "player" }}>
|
|
333
333
|
<Label text="Holy Light" align="CENTER" />
|
|
@@ -479,12 +479,12 @@ track; native API declarations and reads remain in wuira.
|
|
|
479
479
|
### Swing timers
|
|
480
480
|
|
|
481
481
|
```tsx
|
|
482
|
-
import { UI,
|
|
482
|
+
import { UI, Wuira } from "wuira";
|
|
483
483
|
import { ProgressBar } from "wuira/ui";
|
|
484
484
|
import { SwingTimer, SwingHand } from "wuira/datasources";
|
|
485
485
|
|
|
486
486
|
const mainHand = new SwingTimer(SwingHand.MainHand);
|
|
487
|
-
const view =
|
|
487
|
+
const view = Wuira.Mount(<ProgressBar width={200} height={12} source={mainHand} />);
|
|
488
488
|
|
|
489
489
|
// Other choices: SwingHand.OffHand and SwingHand.Ranged.
|
|
490
490
|
// mainHand.Value: remaining seconds; Max.Value: duration; Percent.Value: remaining percent.
|
|
@@ -507,6 +507,23 @@ event listener when its owning feature ends. Support is capability-checked;
|
|
|
507
507
|
actual timing still needs validation in Forever. The adapter follows the
|
|
508
508
|
[Forever swing API definition](https://github.com/Gethe/wow-ui-source/blob/bd2470aed543f72697a044e989285b6c83e63f73/Interface/AddOns/Blizzard_APIDocumentationGenerated/SwingTimerDocumentation.lua).
|
|
509
509
|
|
|
510
|
+
### Native Edit Mode layouts
|
|
511
|
+
|
|
512
|
+
```ts
|
|
513
|
+
import { EditModeLayouts } from "wuira/datasources";
|
|
514
|
+
|
|
515
|
+
const layouts = new EditModeLayouts();
|
|
516
|
+
console.log(layouts.Active?.name);
|
|
517
|
+
const stop = layouts.onChange(snapshot => console.log(snapshot.active?.key));
|
|
518
|
+
// On teardown: stop(); layouts.Dispose();
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
`Layouts` lists native indices, names, types and derived keys. `Value` is a detached
|
|
522
|
+
snapshot; native events refresh it without polling. Check `Status` for availability.
|
|
523
|
+
Forever exposes an index rather than a persistent UUID: `key` combines type,
|
|
524
|
+
interface style and name, survives index shifts, and changes on rename. These keys
|
|
525
|
+
describe local game layouts, not portable layout exports.
|
|
526
|
+
|
|
510
527
|
### Group members
|
|
511
528
|
|
|
512
529
|
```ts
|
|
@@ -610,7 +627,7 @@ const view = (
|
|
|
610
627
|
}} />
|
|
611
628
|
);
|
|
612
629
|
|
|
613
|
-
|
|
630
|
+
Wuira.Mount(view);
|
|
614
631
|
```
|
|
615
632
|
|
|
616
633
|
### Addon tooling
|
|
@@ -679,7 +696,7 @@ Alternatively, install globally with `npm install -g wuira`, then use `wuira cre
|
|
|
679
696
|
|
|
680
697
|
```tsx
|
|
681
698
|
import "wuira/console-polyfill";
|
|
682
|
-
import { UI,
|
|
699
|
+
import { UI, Wuira } from "wuira";
|
|
683
700
|
|
|
684
701
|
|
|
685
702
|
function App() {
|
|
@@ -687,14 +704,14 @@ function App() {
|
|
|
687
704
|
return <></>;
|
|
688
705
|
}
|
|
689
706
|
|
|
690
|
-
|
|
707
|
+
Wuira.Mount(App);
|
|
691
708
|
```
|
|
692
709
|
|
|
693
710
|
An empty fragment creates no native frame. Only empty fragments are currently supported; use a layout for multiple visual elements.
|
|
694
711
|
|
|
695
712
|
`console.log/info/warn/error` use a global WoW console polyfill. Output goes to the local chat window, never to other players. The addon uses no Node.js runtime or stdin/stdout. `console.error` does not throw. Arguments are formatted with Lua `tostring`; objects are not deeply inspected. The CLI uses its own Node.js terminal console.
|
|
696
713
|
|
|
697
|
-
Importing `wuira` installs the global console polyfill automatically. The shared TypeScript config loads its global declarations and uses Node16 module resolution for package exports; DOM typings are not required. `
|
|
714
|
+
Importing `wuira` installs the global console polyfill automatically. The shared TypeScript config loads its global declarations and uses Node16 module resolution for package exports; DOM typings are not required. `Wuira.Mount` accepts a `Cell`, no value, or a function returning `Cell | void`, so addons without a visual tree can simply log and return.
|
|
698
715
|
|
|
699
716
|
## Build and distribution
|
|
700
717
|
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Cell } from "./ui/Cell";
|
|
2
|
+
import type { Anchor } from "./types/Position";
|
|
3
|
+
import type { CommandCallback } from "./platform/SlashCommands";
|
|
4
|
+
/** Owns one application's native UI trees, bindings and cleanup. */
|
|
5
|
+
export declare class WuiraApp {
|
|
6
|
+
private readonly mountedFrames;
|
|
7
|
+
private readonly mountedTrees;
|
|
8
|
+
registerCommand(command: string, callback: CommandCallback): () => void;
|
|
9
|
+
Mount(component: Cell | void | (() => Cell | void), anchor?: Anchor, parent?: wuiraNativeFrame): wuiraNativeFrame | undefined;
|
|
10
|
+
Unmount(frame: wuiraNativeFrame): void;
|
|
11
|
+
private Protect;
|
|
12
|
+
}
|
package/lib/WuiraApp.lua
ADDED
|
@@ -0,0 +1,425 @@
|
|
|
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 __TS__Symbol, Symbol
|
|
11
|
+
do
|
|
12
|
+
local symbolMetatable = {__tostring = function(self)
|
|
13
|
+
return ("Symbol(" .. (self.description or "")) .. ")"
|
|
14
|
+
end}
|
|
15
|
+
function __TS__Symbol(description)
|
|
16
|
+
return setmetatable({description = description}, symbolMetatable)
|
|
17
|
+
end
|
|
18
|
+
Symbol = {
|
|
19
|
+
asyncDispose = __TS__Symbol("Symbol.asyncDispose"),
|
|
20
|
+
dispose = __TS__Symbol("Symbol.dispose"),
|
|
21
|
+
iterator = __TS__Symbol("Symbol.iterator"),
|
|
22
|
+
hasInstance = __TS__Symbol("Symbol.hasInstance"),
|
|
23
|
+
species = __TS__Symbol("Symbol.species"),
|
|
24
|
+
toStringTag = __TS__Symbol("Symbol.toStringTag")
|
|
25
|
+
}
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
local __TS__Iterator
|
|
29
|
+
do
|
|
30
|
+
local function iteratorGeneratorStep(self)
|
|
31
|
+
local co = self.____coroutine
|
|
32
|
+
local status, value = coroutine.resume(co)
|
|
33
|
+
if not status then
|
|
34
|
+
error(value, 0)
|
|
35
|
+
end
|
|
36
|
+
if coroutine.status(co) == "dead" then
|
|
37
|
+
return
|
|
38
|
+
end
|
|
39
|
+
return true, value
|
|
40
|
+
end
|
|
41
|
+
local function iteratorIteratorStep(self)
|
|
42
|
+
local result = self:next()
|
|
43
|
+
if result.done then
|
|
44
|
+
return
|
|
45
|
+
end
|
|
46
|
+
return true, result.value
|
|
47
|
+
end
|
|
48
|
+
local function iteratorStringStep(self, index)
|
|
49
|
+
index = index + 1
|
|
50
|
+
if index > #self then
|
|
51
|
+
return
|
|
52
|
+
end
|
|
53
|
+
return index, string.sub(self, index, index)
|
|
54
|
+
end
|
|
55
|
+
function __TS__Iterator(iterable)
|
|
56
|
+
if type(iterable) == "string" then
|
|
57
|
+
return iteratorStringStep, iterable, 0
|
|
58
|
+
elseif iterable.____coroutine ~= nil then
|
|
59
|
+
return iteratorGeneratorStep, iterable
|
|
60
|
+
elseif iterable[Symbol.iterator] then
|
|
61
|
+
local iterator = iterable[Symbol.iterator](iterable)
|
|
62
|
+
return iteratorIteratorStep, iterator
|
|
63
|
+
else
|
|
64
|
+
return ipairs(iterable)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
local Map
|
|
70
|
+
do
|
|
71
|
+
Map = __TS__Class()
|
|
72
|
+
Map.name = "Map"
|
|
73
|
+
function Map.prototype.____constructor(self, entries)
|
|
74
|
+
self[Symbol.toStringTag] = "Map"
|
|
75
|
+
self.items = {}
|
|
76
|
+
self.size = 0
|
|
77
|
+
self.nextKey = {}
|
|
78
|
+
self.previousKey = {}
|
|
79
|
+
if entries == nil then
|
|
80
|
+
return
|
|
81
|
+
end
|
|
82
|
+
local iterable = entries
|
|
83
|
+
if iterable[Symbol.iterator] then
|
|
84
|
+
local iterator = iterable[Symbol.iterator](iterable)
|
|
85
|
+
while true do
|
|
86
|
+
local result = iterator:next()
|
|
87
|
+
if result.done then
|
|
88
|
+
break
|
|
89
|
+
end
|
|
90
|
+
local value = result.value
|
|
91
|
+
self:set(value[1], value[2])
|
|
92
|
+
end
|
|
93
|
+
else
|
|
94
|
+
local array = entries
|
|
95
|
+
for ____, kvp in ipairs(array) do
|
|
96
|
+
self:set(kvp[1], kvp[2])
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
function Map.prototype.clear(self)
|
|
101
|
+
self.items = {}
|
|
102
|
+
self.nextKey = {}
|
|
103
|
+
self.previousKey = {}
|
|
104
|
+
self.firstKey = nil
|
|
105
|
+
self.lastKey = nil
|
|
106
|
+
self.size = 0
|
|
107
|
+
end
|
|
108
|
+
function Map.prototype.delete(self, key)
|
|
109
|
+
local contains = self:has(key)
|
|
110
|
+
if contains then
|
|
111
|
+
self.size = self.size - 1
|
|
112
|
+
local next = self.nextKey[key]
|
|
113
|
+
local previous = self.previousKey[key]
|
|
114
|
+
if next ~= nil and previous ~= nil then
|
|
115
|
+
self.nextKey[previous] = next
|
|
116
|
+
self.previousKey[next] = previous
|
|
117
|
+
elseif next ~= nil then
|
|
118
|
+
self.firstKey = next
|
|
119
|
+
self.previousKey[next] = nil
|
|
120
|
+
elseif previous ~= nil then
|
|
121
|
+
self.lastKey = previous
|
|
122
|
+
self.nextKey[previous] = nil
|
|
123
|
+
else
|
|
124
|
+
self.firstKey = nil
|
|
125
|
+
self.lastKey = nil
|
|
126
|
+
end
|
|
127
|
+
self.nextKey[key] = nil
|
|
128
|
+
self.previousKey[key] = nil
|
|
129
|
+
end
|
|
130
|
+
self.items[key] = nil
|
|
131
|
+
return contains
|
|
132
|
+
end
|
|
133
|
+
function Map.prototype.forEach(self, callback)
|
|
134
|
+
for ____, key in __TS__Iterator(self:keys()) do
|
|
135
|
+
callback(nil, self.items[key], key, self)
|
|
136
|
+
end
|
|
137
|
+
end
|
|
138
|
+
function Map.prototype.get(self, key)
|
|
139
|
+
return self.items[key]
|
|
140
|
+
end
|
|
141
|
+
function Map.prototype.has(self, key)
|
|
142
|
+
return self.nextKey[key] ~= nil or self.lastKey == key
|
|
143
|
+
end
|
|
144
|
+
function Map.prototype.set(self, key, value)
|
|
145
|
+
local isNewValue = not self:has(key)
|
|
146
|
+
if isNewValue then
|
|
147
|
+
self.size = self.size + 1
|
|
148
|
+
end
|
|
149
|
+
self.items[key] = value
|
|
150
|
+
if self.firstKey == nil then
|
|
151
|
+
self.firstKey = key
|
|
152
|
+
self.lastKey = key
|
|
153
|
+
elseif isNewValue then
|
|
154
|
+
self.nextKey[self.lastKey] = key
|
|
155
|
+
self.previousKey[key] = self.lastKey
|
|
156
|
+
self.lastKey = key
|
|
157
|
+
end
|
|
158
|
+
return self
|
|
159
|
+
end
|
|
160
|
+
Map.prototype[Symbol.iterator] = function(self)
|
|
161
|
+
return self:entries()
|
|
162
|
+
end
|
|
163
|
+
function Map.prototype.entries(self)
|
|
164
|
+
local function getFirstKey()
|
|
165
|
+
return self.firstKey
|
|
166
|
+
end
|
|
167
|
+
local items = self.items
|
|
168
|
+
local nextKey = self.nextKey
|
|
169
|
+
local key
|
|
170
|
+
local started = false
|
|
171
|
+
return {
|
|
172
|
+
[Symbol.iterator] = function(self)
|
|
173
|
+
return self
|
|
174
|
+
end,
|
|
175
|
+
next = function(self)
|
|
176
|
+
if not started then
|
|
177
|
+
started = true
|
|
178
|
+
key = getFirstKey(nil)
|
|
179
|
+
else
|
|
180
|
+
key = nextKey[key]
|
|
181
|
+
end
|
|
182
|
+
return {done = not key, value = {key, items[key]}}
|
|
183
|
+
end
|
|
184
|
+
}
|
|
185
|
+
end
|
|
186
|
+
function Map.prototype.keys(self)
|
|
187
|
+
local function getFirstKey()
|
|
188
|
+
return self.firstKey
|
|
189
|
+
end
|
|
190
|
+
local nextKey = self.nextKey
|
|
191
|
+
local key
|
|
192
|
+
local started = false
|
|
193
|
+
return {
|
|
194
|
+
[Symbol.iterator] = function(self)
|
|
195
|
+
return self
|
|
196
|
+
end,
|
|
197
|
+
next = function(self)
|
|
198
|
+
if not started then
|
|
199
|
+
started = true
|
|
200
|
+
key = getFirstKey(nil)
|
|
201
|
+
else
|
|
202
|
+
key = nextKey[key]
|
|
203
|
+
end
|
|
204
|
+
return {done = not key, value = key}
|
|
205
|
+
end
|
|
206
|
+
}
|
|
207
|
+
end
|
|
208
|
+
function Map.prototype.values(self)
|
|
209
|
+
local function getFirstKey()
|
|
210
|
+
return self.firstKey
|
|
211
|
+
end
|
|
212
|
+
local items = self.items
|
|
213
|
+
local nextKey = self.nextKey
|
|
214
|
+
local key
|
|
215
|
+
local started = false
|
|
216
|
+
return {
|
|
217
|
+
[Symbol.iterator] = function(self)
|
|
218
|
+
return self
|
|
219
|
+
end,
|
|
220
|
+
next = function(self)
|
|
221
|
+
if not started then
|
|
222
|
+
started = true
|
|
223
|
+
key = getFirstKey(nil)
|
|
224
|
+
else
|
|
225
|
+
key = nextKey[key]
|
|
226
|
+
end
|
|
227
|
+
return {done = not key, value = items[key]}
|
|
228
|
+
end
|
|
229
|
+
}
|
|
230
|
+
end
|
|
231
|
+
Map[Symbol.species] = Map
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
local function __TS__New(target, ...)
|
|
235
|
+
local instance = setmetatable({}, target.prototype)
|
|
236
|
+
instance:____constructor(...)
|
|
237
|
+
return instance
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
local function __TS__ArrayMap(self, callbackfn, thisArg)
|
|
241
|
+
local result = {}
|
|
242
|
+
for i = 1, #self do
|
|
243
|
+
result[i] = callbackfn(thisArg, self[i], i - 1, self)
|
|
244
|
+
end
|
|
245
|
+
return result
|
|
246
|
+
end
|
|
247
|
+
-- End of Lua Library inline imports
|
|
248
|
+
local ____exports = {}
|
|
249
|
+
local ____layout = require("rendering.layout")
|
|
250
|
+
local prepareLayout = ____layout.prepareLayout
|
|
251
|
+
local createFrames = ____layout.createFrames
|
|
252
|
+
local resolveAnchors = ____layout.resolveAnchors
|
|
253
|
+
local applyPosition = ____layout.applyPosition
|
|
254
|
+
local ____visibility = require("rendering.visibility")
|
|
255
|
+
local bindVisibility = ____visibility.bindVisibility
|
|
256
|
+
local ____widgets = require("rendering.widgets")
|
|
257
|
+
local renderWidget = ____widgets.renderWidget
|
|
258
|
+
local ____decorations = require("rendering.decorations")
|
|
259
|
+
local renderDecorations = ____decorations.renderDecorations
|
|
260
|
+
local ____updates = require("rendering.updates")
|
|
261
|
+
local startUpdates = ____updates.startUpdates
|
|
262
|
+
local ____SlashCommands = require("platform.SlashCommands")
|
|
263
|
+
local registerCommand = ____SlashCommands.registerCommand
|
|
264
|
+
--- Owns one application's native UI trees, bindings and cleanup.
|
|
265
|
+
____exports.WuiraApp = __TS__Class()
|
|
266
|
+
local WuiraApp = ____exports.WuiraApp
|
|
267
|
+
WuiraApp.name = "WuiraApp"
|
|
268
|
+
function WuiraApp.prototype.____constructor(self)
|
|
269
|
+
self.mountedFrames = __TS__New(Map)
|
|
270
|
+
self.mountedTrees = __TS__New(Map)
|
|
271
|
+
end
|
|
272
|
+
function WuiraApp.prototype.registerCommand(self, command, callback)
|
|
273
|
+
return registerCommand(nil, command, callback)
|
|
274
|
+
end
|
|
275
|
+
function WuiraApp.prototype.Mount(self, component, anchor, parent)
|
|
276
|
+
if parent == nil then
|
|
277
|
+
parent = UIParent
|
|
278
|
+
end
|
|
279
|
+
local ____temp_0
|
|
280
|
+
if type(component) == "function" then
|
|
281
|
+
____temp_0 = component(nil)
|
|
282
|
+
else
|
|
283
|
+
____temp_0 = component
|
|
284
|
+
end
|
|
285
|
+
local view = ____temp_0
|
|
286
|
+
if view == nil or view.kind == "empty" then
|
|
287
|
+
return nil
|
|
288
|
+
end
|
|
289
|
+
local ____prepareLayout_result_1 = prepareLayout(nil, view, parent, self.mountedFrames)
|
|
290
|
+
local measured = ____prepareLayout_result_1.measured
|
|
291
|
+
local protectedTree = ____prepareLayout_result_1.protectedTree
|
|
292
|
+
local ____createFrames_result_2 = createFrames(nil, measured, parent, self.mountedFrames)
|
|
293
|
+
local root = ____createFrames_result_2.root
|
|
294
|
+
local pending = ____createFrames_result_2.pending
|
|
295
|
+
local frames = ____createFrames_result_2.frames
|
|
296
|
+
local tree = {
|
|
297
|
+
frames = __TS__ArrayMap(
|
|
298
|
+
pending,
|
|
299
|
+
function(____, item) return item.frame end
|
|
300
|
+
),
|
|
301
|
+
cells = __TS__ArrayMap(
|
|
302
|
+
pending,
|
|
303
|
+
function(____, item) return item.cell end
|
|
304
|
+
),
|
|
305
|
+
decorations = {},
|
|
306
|
+
bindings = {},
|
|
307
|
+
protected = protectedTree,
|
|
308
|
+
pendingUnmount = false,
|
|
309
|
+
visibility = {}
|
|
310
|
+
}
|
|
311
|
+
self.mountedTrees:set(root, tree)
|
|
312
|
+
do
|
|
313
|
+
local function ____catch(failure)
|
|
314
|
+
self:Unmount(root)
|
|
315
|
+
error(failure, 0)
|
|
316
|
+
end
|
|
317
|
+
local ____try, ____hasReturned = pcall(function()
|
|
318
|
+
local anchors = resolveAnchors(nil, pending, frames)
|
|
319
|
+
local updates = {}
|
|
320
|
+
self:Protect(root, tree)
|
|
321
|
+
for ____, item in ipairs(pending) do
|
|
322
|
+
local visibility = bindVisibility(
|
|
323
|
+
nil,
|
|
324
|
+
item,
|
|
325
|
+
tree,
|
|
326
|
+
updates,
|
|
327
|
+
function() return self:Protect(root, tree) end
|
|
328
|
+
)
|
|
329
|
+
applyPosition(
|
|
330
|
+
nil,
|
|
331
|
+
item,
|
|
332
|
+
anchors,
|
|
333
|
+
root,
|
|
334
|
+
anchor
|
|
335
|
+
)
|
|
336
|
+
renderWidget(
|
|
337
|
+
nil,
|
|
338
|
+
item,
|
|
339
|
+
tree,
|
|
340
|
+
updates,
|
|
341
|
+
visibility.onActiveChange
|
|
342
|
+
)
|
|
343
|
+
renderDecorations(nil, item, tree)
|
|
344
|
+
self.mountedFrames:set(item.cell.props, item.frame)
|
|
345
|
+
visibility:refresh()
|
|
346
|
+
local ____this_4
|
|
347
|
+
____this_4 = item.cell.props
|
|
348
|
+
local ____opt_3 = ____this_4.onMount
|
|
349
|
+
local cleanup = ____opt_3 and ____opt_3(____this_4, item.frame)
|
|
350
|
+
if cleanup ~= nil then
|
|
351
|
+
local ____tree_bindings_5 = tree.bindings
|
|
352
|
+
____tree_bindings_5[#____tree_bindings_5 + 1] = cleanup
|
|
353
|
+
end
|
|
354
|
+
if visibility.dynamic then
|
|
355
|
+
updates[#updates + 1] = visibility.refresh
|
|
356
|
+
end
|
|
357
|
+
end
|
|
358
|
+
startUpdates(nil, parent, tree, updates)
|
|
359
|
+
end)
|
|
360
|
+
if not ____try then
|
|
361
|
+
____catch(____hasReturned)
|
|
362
|
+
end
|
|
363
|
+
end
|
|
364
|
+
return root
|
|
365
|
+
end
|
|
366
|
+
function WuiraApp.prototype.Unmount(self, frame)
|
|
367
|
+
local tree = self.mountedTrees:get(frame)
|
|
368
|
+
if tree == nil then
|
|
369
|
+
return
|
|
370
|
+
end
|
|
371
|
+
if self:Protect(frame, tree) and InCombatLockdown() then
|
|
372
|
+
tree.pendingUnmount = true
|
|
373
|
+
return
|
|
374
|
+
end
|
|
375
|
+
for ____, dispose in ipairs(tree.bindings) do
|
|
376
|
+
dispose(nil)
|
|
377
|
+
end
|
|
378
|
+
for ____, decoration in ipairs(tree.decorations) do
|
|
379
|
+
decoration:dispose()
|
|
380
|
+
end
|
|
381
|
+
for ____, child in ipairs(tree.frames) do
|
|
382
|
+
child:UnregisterAllEvents()
|
|
383
|
+
child:SetScript("OnEvent", nil)
|
|
384
|
+
child:SetScript("OnUpdate", nil)
|
|
385
|
+
child:Hide()
|
|
386
|
+
end
|
|
387
|
+
for ____, cell in ipairs(tree.cells) do
|
|
388
|
+
self.mountedFrames:delete(cell.props)
|
|
389
|
+
end
|
|
390
|
+
self.mountedTrees:delete(frame)
|
|
391
|
+
end
|
|
392
|
+
function WuiraApp.prototype.Protect(self, root, tree)
|
|
393
|
+
local ____temp_8 = not tree.protected
|
|
394
|
+
if ____temp_8 then
|
|
395
|
+
local ____this_7
|
|
396
|
+
____this_7 = root
|
|
397
|
+
local ____opt_6 = ____this_7.IsProtected
|
|
398
|
+
____temp_8 = (____opt_6 and ____opt_6(____this_7)) ~= true
|
|
399
|
+
end
|
|
400
|
+
if ____temp_8 then
|
|
401
|
+
return false
|
|
402
|
+
end
|
|
403
|
+
tree.protected = true
|
|
404
|
+
if tree.listener == nil then
|
|
405
|
+
local listener = CreateFrame("Frame", nil, UIParent)
|
|
406
|
+
tree.listener = listener
|
|
407
|
+
local ____tree_frames_9 = tree.frames
|
|
408
|
+
____tree_frames_9[#____tree_frames_9 + 1] = listener
|
|
409
|
+
listener:RegisterEvent("PLAYER_REGEN_ENABLED")
|
|
410
|
+
listener:SetScript(
|
|
411
|
+
"OnEvent",
|
|
412
|
+
function()
|
|
413
|
+
if tree.pendingUnmount then
|
|
414
|
+
self:Unmount(root)
|
|
415
|
+
else
|
|
416
|
+
for ____, refresh in ipairs(tree.visibility) do
|
|
417
|
+
refresh(nil)
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
)
|
|
422
|
+
end
|
|
423
|
+
return true
|
|
424
|
+
end
|
|
425
|
+
return ____exports
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { DataSource } from "./DataSource";
|
|
2
|
+
export type EditModeLayoutsStatus = "ready" | "unavailable" | "restricted";
|
|
3
|
+
export interface EditModeLayout {
|
|
4
|
+
/** Native one-based index. Deleting another layout can change this number. */
|
|
5
|
+
readonly index: number;
|
|
6
|
+
readonly name: string;
|
|
7
|
+
readonly type: number;
|
|
8
|
+
readonly interfaceStyle?: number;
|
|
9
|
+
/** Derived from native type, interface style and name; changes on rename. */
|
|
10
|
+
readonly key: string;
|
|
11
|
+
}
|
|
12
|
+
export interface EditModeLayoutSnapshot {
|
|
13
|
+
readonly layouts: readonly EditModeLayout[];
|
|
14
|
+
readonly active?: EditModeLayout;
|
|
15
|
+
}
|
|
16
|
+
/** Read-only native Edit Mode layouts, refreshed by events without polling. */
|
|
17
|
+
export declare class EditModeLayouts extends DataSource<EditModeLayoutSnapshot> {
|
|
18
|
+
private snapshot;
|
|
19
|
+
private status;
|
|
20
|
+
private readonly listeners;
|
|
21
|
+
private readonly frame;
|
|
22
|
+
private disposed;
|
|
23
|
+
constructor();
|
|
24
|
+
get Status(): EditModeLayoutsStatus;
|
|
25
|
+
get Layouts(): readonly EditModeLayout[];
|
|
26
|
+
get Active(): EditModeLayout | undefined;
|
|
27
|
+
protected HasSecretFields(): boolean;
|
|
28
|
+
protected GetValue(): EditModeLayoutSnapshot;
|
|
29
|
+
/** No initial emission. Availability changes also notify observers. */
|
|
30
|
+
onChange(listener: (value: EditModeLayoutSnapshot) => void): () => void;
|
|
31
|
+
private Refresh;
|
|
32
|
+
Dispose(): void;
|
|
33
|
+
}
|