@rbxts/app-forge 0.0.3 → 0.0.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/README.md +318 -0
- package/out/container.d.ts +2 -2
- package/out/container.luau +43 -2
- package/out/decorator.d.ts +5 -2
- package/out/decorator.luau +3 -1
- package/out/helpers.d.ts +2 -2
- package/out/index.d.ts +3 -6
- package/out/init.luau +30 -63
- package/out/types.d.ts +2 -1
- package/package.json +56 -57
package/README.md
CHANGED
|
@@ -0,0 +1,318 @@
|
|
|
1
|
+
# AppForge — React App & Window Manager for roblox-ts
|
|
2
|
+
|
|
3
|
+
AppForge is a UI/app orchestration system for React in Roblox, enabling:
|
|
4
|
+
|
|
5
|
+
✔ App registration
|
|
6
|
+
✔ Visibility & state control
|
|
7
|
+
✔ App grouping
|
|
8
|
+
✔ Exclusive UI modes
|
|
9
|
+
✔ Rule-based interactions
|
|
10
|
+
✔ Priority & layering
|
|
11
|
+
✔ React-friendly state bindings
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
# 📦 Installation
|
|
16
|
+
|
|
17
|
+
```bash
|
|
18
|
+
npm i @rbxts/app-forge
|
|
19
|
+
# or
|
|
20
|
+
bun i @rbxts/app-forge
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
---
|
|
24
|
+
|
|
25
|
+
# 🧩 Setup — REQUIRED
|
|
26
|
+
|
|
27
|
+
### Create `global.d.ts`
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
declare global {
|
|
31
|
+
// All registered Apps by name
|
|
32
|
+
type AppNames = readonly ["HUD", "Inventory", "Shop", "SideButtons", "Pause"];
|
|
33
|
+
|
|
34
|
+
// Logical groupings of apps
|
|
35
|
+
type AppGroups = readonly ["HUD", "Panel", "Overlay"];
|
|
36
|
+
|
|
37
|
+
// Props that are injected into each App
|
|
38
|
+
interface AppProps {
|
|
39
|
+
player: Player;
|
|
40
|
+
target: GuiObject | Camera;
|
|
41
|
+
playerData: any;
|
|
42
|
+
events: any;
|
|
43
|
+
appManager: import("@rbxts/app-forge").default;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export {};
|
|
47
|
+
}
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
> AppForge will now use your AppNames & AppProps as typed globals.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
# 🚀 Initializing AppForge
|
|
55
|
+
|
|
56
|
+
```ts
|
|
57
|
+
import AppManager, { Render } from "@rbxts/app-forge";
|
|
58
|
+
import { createPortal, createRoot } from "@rbxts/react-roblox";
|
|
59
|
+
import React from "@rbxts/react";
|
|
60
|
+
|
|
61
|
+
const manager = new AppManager();
|
|
62
|
+
const root = createRoot(new Instance("Folder"));
|
|
63
|
+
|
|
64
|
+
const props: AppProps = {
|
|
65
|
+
player: Players.LocalPlayer!,
|
|
66
|
+
target: new Instance("Folder"),
|
|
67
|
+
playerData: {},
|
|
68
|
+
events: {},
|
|
69
|
+
appManager: manager,
|
|
70
|
+
};
|
|
71
|
+
|
|
72
|
+
root.render(
|
|
73
|
+
createPortal(
|
|
74
|
+
<screengui ResetOnSpawn={false} ZIndexBehavior="Sibling">
|
|
75
|
+
<Render props={props} manager={manager} />
|
|
76
|
+
</screengui>,
|
|
77
|
+
Players.LocalPlayer!.WaitForChild("PlayerGui"),
|
|
78
|
+
),
|
|
79
|
+
);
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
> `Render` will automatically render ALL registered apps.
|
|
83
|
+
|
|
84
|
+
---
|
|
85
|
+
|
|
86
|
+
# 🧱 Creating an App
|
|
87
|
+
|
|
88
|
+
```ts
|
|
89
|
+
import { App, Args } from "@rbxts/app-forge";
|
|
90
|
+
import React from "@rbxts/react";
|
|
91
|
+
|
|
92
|
+
@App({
|
|
93
|
+
name: "SideButtons",
|
|
94
|
+
visible: true,
|
|
95
|
+
})
|
|
96
|
+
export default class SideButtons extends Args {
|
|
97
|
+
render() {
|
|
98
|
+
return (
|
|
99
|
+
<frame Size={UDim2.fromScale(1, 1)}>Side Buttons UI</frame>
|
|
100
|
+
);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### ❗ Note
|
|
106
|
+
|
|
107
|
+
`Args` automatically injects AppProps and more into `this`, such as:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
this.Forge // This is the AppForge Manager Created
|
|
111
|
+
this.name // The Name given on Element Creation
|
|
112
|
+
this.props // Props passed through Render
|
|
113
|
+
```
|
|
114
|
+
|
|
115
|
+
You never manually `new` apps — AppForge constructs them automatically.
|
|
116
|
+
|
|
117
|
+
---
|
|
118
|
+
|
|
119
|
+
# 🕹 App Manager API
|
|
120
|
+
|
|
121
|
+
```ts
|
|
122
|
+
appManager.toggle("Inventory");
|
|
123
|
+
appManager.set("Shop", true);
|
|
124
|
+
appManager.set("HUD", false);
|
|
125
|
+
const isShown = appManager.getState("Pause");
|
|
126
|
+
const bind = appManager.getBind("Inventory");
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
---
|
|
130
|
+
|
|
131
|
+
# 📐 Using `getBind()` in React
|
|
132
|
+
|
|
133
|
+
```tsx
|
|
134
|
+
return (
|
|
135
|
+
<frame Visible={props.appManager.getBind("Inventory")}>
|
|
136
|
+
Items…
|
|
137
|
+
</frame>
|
|
138
|
+
);
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Binds re-render automatically on visibility change.
|
|
142
|
+
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
# ⌨️ Hotkey Toggle Example
|
|
146
|
+
|
|
147
|
+
```ts
|
|
148
|
+
UserInputService.InputBegan.Connect((input) => {
|
|
149
|
+
if (input.KeyCode === Enum.KeyCode.I)
|
|
150
|
+
appManager.toggle("Inventory");
|
|
151
|
+
});
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
# ⚖️ APP RULES SYSTEM
|
|
157
|
+
|
|
158
|
+
Rules control UI interaction & visibility behavior.
|
|
159
|
+
|
|
160
|
+
| Rule | Effect |
|
|
161
|
+
|---|---|
|
|
162
|
+
| blockedBy | Prevents opening if another app is active |
|
|
163
|
+
| blocks | Auto-closes another app when opened |
|
|
164
|
+
| exclusive | Closes ALL other apps except same group |
|
|
165
|
+
| groups | Logical grouping categories |
|
|
166
|
+
| layer | (Coming soon — currently not functional) |
|
|
167
|
+
|
|
168
|
+
---
|
|
169
|
+
|
|
170
|
+
## `blockedBy`
|
|
171
|
+
|
|
172
|
+
App cannot open if the listed apps are open.
|
|
173
|
+
|
|
174
|
+
```ts
|
|
175
|
+
@App({ name: "Inventory", rules: { blockedBy: "Shop" } })
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
Multiple:
|
|
179
|
+
|
|
180
|
+
```ts
|
|
181
|
+
@App({ name: "Inventory", rules: { blockedBy: ["Shop", "Trade"] } })
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
---
|
|
185
|
+
|
|
186
|
+
## `blocks`
|
|
187
|
+
|
|
188
|
+
Opening the app will hide other apps.
|
|
189
|
+
|
|
190
|
+
```ts
|
|
191
|
+
@App({ name: "Shop", rules: { blocks: "Inventory" } })
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
Multiple:
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
@App({ name: "Shop", rules: { blocks: ["Inventory", "TeamUI"] } })
|
|
198
|
+
```
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## `exclusive`
|
|
203
|
+
|
|
204
|
+
For fullscreen apps:
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
@App({ name: "Pause", rules: { exclusive: true } })
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
When Pause opens:
|
|
211
|
+
|
|
212
|
+
✔ Inventory closes
|
|
213
|
+
✔ HUD closes
|
|
214
|
+
✔ SideButtons closes
|
|
215
|
+
✔ Everything except Core
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## `groups`
|
|
220
|
+
|
|
221
|
+
Apps inside the same group DO NOT block each other.
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
@App({ name: "HUD", rules: { groups: ["HUD"] } })
|
|
225
|
+
@App({ name: "Crosshair", rules: { groups: ["HUD"] } })
|
|
226
|
+
```
|
|
227
|
+
|
|
228
|
+
These can both be open at the same time.
|
|
229
|
+
|
|
230
|
+
---
|
|
231
|
+
|
|
232
|
+
## `Core` Group
|
|
233
|
+
|
|
234
|
+
Core apps are ALWAYS allowed and never auto-hidden.
|
|
235
|
+
|
|
236
|
+
```ts
|
|
237
|
+
@App({ name: "FPSCounter", rules: { groups: "Core" } })
|
|
238
|
+
```
|
|
239
|
+
|
|
240
|
+
This app will NEVER be closed by rules.
|
|
241
|
+
|
|
242
|
+
---
|
|
243
|
+
|
|
244
|
+
## `layer` *(not implemented yet)*
|
|
245
|
+
|
|
246
|
+
> The `layer` property is part of the upcoming UI priority system.
|
|
247
|
+
> Setting it currently does not affect rendering order.
|
|
248
|
+
|
|
249
|
+
Example (for future readiness):
|
|
250
|
+
|
|
251
|
+
```ts
|
|
252
|
+
@App({ name: "DebugUI", rules: { layer: 999 } })
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
---
|
|
256
|
+
|
|
257
|
+
# 🧪 Full Rules Example
|
|
258
|
+
|
|
259
|
+
```ts
|
|
260
|
+
@App({ name: "HUD", rules: { groups: ["HUD"] } })
|
|
261
|
+
@App({ name: "Inventory", rules: { blockedBy: "Shop", groups: ["Panel"] } })
|
|
262
|
+
@App({ name: "Shop", rules: { blocks: "Inventory", groups: ["Panel"] } })
|
|
263
|
+
@App({ name: "Pause", rules: { exclusive: true } })
|
|
264
|
+
@App({ name: "FPSCounter", rules: { groups: "Core" } })
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Behavior:
|
|
268
|
+
|
|
269
|
+
| Action | Result |
|
|
270
|
+
| -------------- | -------------------------------- |
|
|
271
|
+
| Open Inventory | HUD + FPS stay |
|
|
272
|
+
| Open Shop | Inventory closes |
|
|
273
|
+
| Open Pause | ALL apps close except Core |
|
|
274
|
+
| Open HUD | Never conflicts with SideButtons |
|
|
275
|
+
| FPSCounter | Always visible |
|
|
276
|
+
|
|
277
|
+
---
|
|
278
|
+
|
|
279
|
+
# 🧠 Using AppForge in UI Components
|
|
280
|
+
|
|
281
|
+
```tsx
|
|
282
|
+
function MenuUI(props: AppProps) {
|
|
283
|
+
return (
|
|
284
|
+
<frame Visible={props.appManager.getBind("Shop")}>
|
|
285
|
+
Shop UI…
|
|
286
|
+
</frame>
|
|
287
|
+
);
|
|
288
|
+
}
|
|
289
|
+
```
|
|
290
|
+
|
|
291
|
+
---
|
|
292
|
+
|
|
293
|
+
# ❗ Best Practices
|
|
294
|
+
|
|
295
|
+
✔ Use `groups` for UI coexistence
|
|
296
|
+
✔ Use `exclusive` for fullscreen menus
|
|
297
|
+
✔ Use `blockedBy` for preventing conflicts
|
|
298
|
+
✔ Use `blocks` for auto-closing logic
|
|
299
|
+
✔ Use `Core` for never-closed apps
|
|
300
|
+
✔ Use `layer` for future-proofing (not active yet)
|
|
301
|
+
|
|
302
|
+
---
|
|
303
|
+
|
|
304
|
+
# 🛠 Future Roadmap
|
|
305
|
+
|
|
306
|
+
- [ ] layer / priority rendering
|
|
307
|
+
|
|
308
|
+
---
|
|
309
|
+
|
|
310
|
+
# ❤️ Contributing
|
|
311
|
+
|
|
312
|
+
Feel free to submit PRs, suggestions, or feature requests.
|
|
313
|
+
|
|
314
|
+
---
|
|
315
|
+
|
|
316
|
+
# 📄 License
|
|
317
|
+
|
|
318
|
+
MIT
|
package/out/container.d.ts
CHANGED
package/out/container.luau
CHANGED
|
@@ -8,13 +8,54 @@ local useBindingListener = _loners_pretty_react_hooks.useBindingListener
|
|
|
8
8
|
local useSpring = _loners_pretty_react_hooks.useSpring
|
|
9
9
|
local _react = TS.import(script, TS.getModule(script, "@rbxts", "react"))
|
|
10
10
|
local React = _react
|
|
11
|
+
local cloneElement = _react.cloneElement
|
|
12
|
+
local useBinding = _react.useBinding
|
|
11
13
|
local useState = _react.useState
|
|
12
14
|
-- Types
|
|
15
|
+
-- Components
|
|
16
|
+
local AppRegistry = TS.import(script, script.Parent, "decorator").AppRegistry
|
|
17
|
+
local function createBinding(name, manager)
|
|
18
|
+
local _name = name
|
|
19
|
+
local app = AppRegistry[_name]
|
|
20
|
+
if not app then
|
|
21
|
+
error(`App "{name}" not registered`)
|
|
22
|
+
end
|
|
23
|
+
local _condition = app.visible
|
|
24
|
+
if _condition == nil then
|
|
25
|
+
_condition = false
|
|
26
|
+
end
|
|
27
|
+
local binding = { useBinding(_condition) }
|
|
28
|
+
local _binds = manager.binds
|
|
29
|
+
local _name_1 = name
|
|
30
|
+
_binds[_name_1] = binding
|
|
31
|
+
return unpack(binding)
|
|
32
|
+
end
|
|
33
|
+
local function createInstance(props, name, manager)
|
|
34
|
+
local _name = name
|
|
35
|
+
local appClass = AppRegistry[_name]
|
|
36
|
+
if not appClass then
|
|
37
|
+
error(`App "{name}" not registered`)
|
|
38
|
+
end
|
|
39
|
+
local _loaded = manager.loaded
|
|
40
|
+
local _name_1 = name
|
|
41
|
+
if not (_loaded[_name_1] ~= nil) then
|
|
42
|
+
local instance = appClass.constructor.new(props, manager, name)
|
|
43
|
+
local element = cloneElement(instance:render(), {
|
|
44
|
+
key = "Main",
|
|
45
|
+
})
|
|
46
|
+
local _loaded_1 = manager.loaded
|
|
47
|
+
local _name_2 = name
|
|
48
|
+
_loaded_1[_name_2] = element
|
|
49
|
+
end
|
|
50
|
+
local _loaded_1 = manager.loaded
|
|
51
|
+
local _name_2 = name
|
|
52
|
+
return _loaded_1[_name_2]
|
|
53
|
+
end
|
|
13
54
|
local function AppContainer(props)
|
|
14
55
|
local _binding = props
|
|
15
56
|
local name = _binding.name
|
|
16
57
|
local manager = _binding.manager
|
|
17
|
-
local binding, _ =
|
|
58
|
+
local binding, _ = createBinding(name, manager)
|
|
18
59
|
local spring = useSpring(binding:map(function(v)
|
|
19
60
|
return if v then 0 else 1
|
|
20
61
|
end), {
|
|
@@ -22,7 +63,7 @@ local function AppContainer(props)
|
|
|
22
63
|
damping = 0.8,
|
|
23
64
|
})
|
|
24
65
|
local _isVisible, setisVisible = useState(binding:getValue())
|
|
25
|
-
local element =
|
|
66
|
+
local element = createInstance(props, name, manager)
|
|
26
67
|
if not element then
|
|
27
68
|
error(`Failed to create instance for app "{name}"`)
|
|
28
69
|
end
|
package/out/decorator.d.ts
CHANGED
|
@@ -1,9 +1,12 @@
|
|
|
1
1
|
import React from "@rbxts/react";
|
|
2
2
|
import type Types from "./types";
|
|
3
|
+
import type AppForge from ".";
|
|
3
4
|
export declare const AppRegistry: Map<string, Types.AppRegistry>;
|
|
4
|
-
export declare function App(props: Types.AppRegistryProps): <T extends new (props: AppProps) => Args>(constructor: T) => T;
|
|
5
|
+
export declare function App(props: Types.AppRegistryProps): <T extends new (props: AppProps, forge: AppForge, name: string) => Args>(constructor: T) => T;
|
|
5
6
|
export declare abstract class Args {
|
|
7
|
+
readonly Forge: AppForge;
|
|
6
8
|
readonly props: AppProps;
|
|
7
|
-
|
|
9
|
+
readonly name: AppNames[number];
|
|
10
|
+
constructor(props: AppProps, forge: AppForge, name: AppNames[number]);
|
|
8
11
|
abstract render(): React.Element;
|
|
9
12
|
}
|
package/out/decorator.luau
CHANGED
package/out/helpers.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import type AppForge from ".";
|
|
2
2
|
export declare function Render({ props, manager, names, }: {
|
|
3
3
|
props: AppProps;
|
|
4
|
-
manager:
|
|
4
|
+
manager: AppForge;
|
|
5
5
|
names?: AppNames[number] | AppNames[number][];
|
|
6
6
|
}): JSX.Element | JSX.Element[];
|
package/out/index.d.ts
CHANGED
|
@@ -1,12 +1,9 @@
|
|
|
1
1
|
import React from "@rbxts/react";
|
|
2
2
|
import { Args, App } from "./decorator";
|
|
3
|
-
export default class
|
|
4
|
-
|
|
5
|
-
|
|
3
|
+
export default class AppForge {
|
|
4
|
+
binds: Map<string, [React.Binding<boolean>, (T: boolean) => void]>;
|
|
5
|
+
loaded: Map<string, React.Element<any, string | React.JSXElementConstructor<any>>>;
|
|
6
6
|
private rulesManager;
|
|
7
|
-
private getAllNames;
|
|
8
|
-
createBinding(name: AppNames[number]): LuaTuple<[React.Binding<boolean>, (newValue: boolean) => void]>;
|
|
9
|
-
createInstance(props: AppProps, name: AppNames[number]): React.Element<any, string | React.JSXElementConstructor<any>>;
|
|
10
7
|
getBind(name: AppNames[number]): React.Binding<boolean>;
|
|
11
8
|
getState(name: AppNames[number]): boolean;
|
|
12
9
|
set(name: AppNames[number], value: boolean): void;
|
package/out/init.luau
CHANGED
|
@@ -2,76 +2,33 @@
|
|
|
2
2
|
local TS = _G[script]
|
|
3
3
|
local exports = {}
|
|
4
4
|
-- Packages
|
|
5
|
-
local
|
|
6
|
-
local React = _react
|
|
7
|
-
local cloneElement = _react.cloneElement
|
|
8
|
-
local useBinding = _react.useBinding
|
|
9
|
-
local Object = TS.import(script, TS.getModule(script, "@rbxts", "object-utils"))
|
|
5
|
+
local React = TS.import(script, TS.getModule(script, "@rbxts", "react"))
|
|
10
6
|
-- Components
|
|
11
7
|
local _decorator = TS.import(script, script, "decorator")
|
|
12
8
|
local AppRegistry = _decorator.AppRegistry
|
|
13
9
|
local Args = _decorator.Args
|
|
14
10
|
local App = _decorator.App
|
|
15
11
|
local AppContainer = TS.import(script, script, "container").AppContainer
|
|
12
|
+
-- Classes
|
|
16
13
|
local RulesManager = TS.import(script, script, "rules").default
|
|
17
|
-
local
|
|
14
|
+
local AppForge
|
|
18
15
|
do
|
|
19
|
-
|
|
16
|
+
AppForge = setmetatable({}, {
|
|
20
17
|
__tostring = function()
|
|
21
|
-
return "
|
|
18
|
+
return "AppForge"
|
|
22
19
|
end,
|
|
23
20
|
})
|
|
24
|
-
|
|
25
|
-
function
|
|
26
|
-
local self = setmetatable({},
|
|
21
|
+
AppForge.__index = AppForge
|
|
22
|
+
function AppForge.new(...)
|
|
23
|
+
local self = setmetatable({}, AppForge)
|
|
27
24
|
return self:constructor(...) or self
|
|
28
25
|
end
|
|
29
|
-
function
|
|
26
|
+
function AppForge:constructor()
|
|
30
27
|
self.binds = {}
|
|
31
28
|
self.loaded = {}
|
|
32
29
|
self.rulesManager = RulesManager.new(self)
|
|
33
30
|
end
|
|
34
|
-
function
|
|
35
|
-
return Object.keys(AppRegistry)
|
|
36
|
-
end
|
|
37
|
-
function AppManager:createBinding(name)
|
|
38
|
-
local _name = name
|
|
39
|
-
local app = AppRegistry[_name]
|
|
40
|
-
if not app then
|
|
41
|
-
error(`App "{name}" not registered`)
|
|
42
|
-
end
|
|
43
|
-
local _condition = app.visible
|
|
44
|
-
if _condition == nil then
|
|
45
|
-
_condition = false
|
|
46
|
-
end
|
|
47
|
-
local binding = { useBinding(_condition) }
|
|
48
|
-
local _binds = self.binds
|
|
49
|
-
local _name_1 = name
|
|
50
|
-
_binds[_name_1] = binding
|
|
51
|
-
return unpack(binding)
|
|
52
|
-
end
|
|
53
|
-
function AppManager:createInstance(props, name)
|
|
54
|
-
local _name = name
|
|
55
|
-
local appClass = AppRegistry[_name]
|
|
56
|
-
if not appClass then
|
|
57
|
-
error(`App "{name}" not registered`)
|
|
58
|
-
end
|
|
59
|
-
local _loaded = self.loaded
|
|
60
|
-
local _name_1 = name
|
|
61
|
-
if not (_loaded[_name_1] ~= nil) then
|
|
62
|
-
local instance = appClass.constructor.new(props)
|
|
63
|
-
local element = cloneElement(instance:render(), {
|
|
64
|
-
key = "Main",
|
|
65
|
-
})
|
|
66
|
-
local _loaded_1 = self.loaded
|
|
67
|
-
local _name_2 = name
|
|
68
|
-
_loaded_1[_name_2] = element
|
|
69
|
-
end
|
|
70
|
-
local _loaded_1 = self.loaded
|
|
71
|
-
local _name_2 = name
|
|
72
|
-
return _loaded_1[_name_2]
|
|
73
|
-
end
|
|
74
|
-
function AppManager:getBind(name)
|
|
31
|
+
function AppForge:getBind(name)
|
|
75
32
|
local _binds = self.binds
|
|
76
33
|
local _name = name
|
|
77
34
|
if not (_binds[_name] ~= nil) then
|
|
@@ -81,10 +38,10 @@ do
|
|
|
81
38
|
local _name_1 = name
|
|
82
39
|
return _binds_1[_name_1][1]
|
|
83
40
|
end
|
|
84
|
-
function
|
|
41
|
+
function AppForge:getState(name)
|
|
85
42
|
return self:getBind(name):getValue()
|
|
86
43
|
end
|
|
87
|
-
function
|
|
44
|
+
function AppForge:set(name, value)
|
|
88
45
|
if not self.rulesManager:applyRules(name, value) then
|
|
89
46
|
return nil
|
|
90
47
|
end
|
|
@@ -95,16 +52,16 @@ do
|
|
|
95
52
|
local setBinding = _binding[2]
|
|
96
53
|
setBinding(value)
|
|
97
54
|
end
|
|
98
|
-
function
|
|
55
|
+
function AppForge:open(name)
|
|
99
56
|
self:set(name, true)
|
|
100
57
|
end
|
|
101
|
-
function
|
|
58
|
+
function AppForge:close(name)
|
|
102
59
|
self:set(name, false)
|
|
103
60
|
end
|
|
104
|
-
function
|
|
61
|
+
function AppForge:toggle(name)
|
|
105
62
|
self:set(name, not self:getState(name))
|
|
106
63
|
end
|
|
107
|
-
function
|
|
64
|
+
function AppForge:renderApp(props, name)
|
|
108
65
|
local _attributes = {
|
|
109
66
|
key = `{name}_Container`,
|
|
110
67
|
name = name,
|
|
@@ -115,7 +72,7 @@ do
|
|
|
115
72
|
end
|
|
116
73
|
return React.createElement(AppContainer, _attributes)
|
|
117
74
|
end
|
|
118
|
-
function
|
|
75
|
+
function AppForge:renderApps(props, names)
|
|
119
76
|
-- ▼ ReadonlyArray.map ▼
|
|
120
77
|
local _newValue = table.create(#names)
|
|
121
78
|
local _callback = function(n)
|
|
@@ -127,12 +84,22 @@ do
|
|
|
127
84
|
-- ▲ ReadonlyArray.map ▲
|
|
128
85
|
return _newValue
|
|
129
86
|
end
|
|
130
|
-
function
|
|
131
|
-
|
|
87
|
+
function AppForge:renderAll(props)
|
|
88
|
+
local keys = {}
|
|
89
|
+
-- ▼ ReadonlyMap.forEach ▼
|
|
90
|
+
local _callback = function(_, name)
|
|
91
|
+
local _name = name
|
|
92
|
+
table.insert(keys, _name)
|
|
93
|
+
end
|
|
94
|
+
for _k, _v in AppRegistry do
|
|
95
|
+
_callback(_v, _k, AppRegistry)
|
|
96
|
+
end
|
|
97
|
+
-- ▲ ReadonlyMap.forEach ▲
|
|
98
|
+
return self:renderApps(props, keys)
|
|
132
99
|
end
|
|
133
100
|
end
|
|
134
101
|
exports.Render = TS.import(script, script, "helpers").Render
|
|
135
|
-
exports.default =
|
|
102
|
+
exports.default = AppForge
|
|
136
103
|
exports.App = App
|
|
137
104
|
exports.Args = Args
|
|
138
105
|
return exports
|
package/out/types.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
// Types
|
|
2
2
|
import type { Args } from "./decorator";
|
|
3
|
+
import type AppForge from ".";
|
|
3
4
|
|
|
4
5
|
declare namespace Types {
|
|
5
6
|
type AppRegistryProps = {
|
|
@@ -9,7 +10,7 @@ declare namespace Types {
|
|
|
9
10
|
};
|
|
10
11
|
|
|
11
12
|
type AppRegistry = {
|
|
12
|
-
constructor: new (props: AppProps) => Args;
|
|
13
|
+
constructor: new (props: AppProps, forge: AppForge, name: string) => Args;
|
|
13
14
|
visible?: boolean;
|
|
14
15
|
rules?: Rules.All;
|
|
15
16
|
};
|
package/package.json
CHANGED
|
@@ -1,59 +1,58 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
2
|
+
"name": "@rbxts/app-forge",
|
|
3
|
+
"version": "0.0.6",
|
|
4
|
+
"description": "An App Manager for react",
|
|
5
|
+
"main": "out/init.lua",
|
|
6
|
+
"packageManager": "bun@1.3.1",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"build": "rbxtsc",
|
|
9
|
+
"dev": "rbxtsc -w --type game --rojo test.project.json",
|
|
10
|
+
"login": "bunx npm login --auth-type=legacy"
|
|
11
|
+
},
|
|
12
|
+
"keywords": [
|
|
13
|
+
"roblox-ts",
|
|
14
|
+
"react"
|
|
15
|
+
],
|
|
16
|
+
"author": "loner1536",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "https://github.com/Loner1536/AppForge"
|
|
21
|
+
},
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/Loner1536/AppForge/issues"
|
|
24
|
+
},
|
|
25
|
+
"types": "out/index.d.ts",
|
|
26
|
+
"files": [
|
|
27
|
+
"out",
|
|
28
|
+
"!**/*.tsbuildinfo",
|
|
29
|
+
"!**/*.spec.lua",
|
|
30
|
+
"!**/*.spec.d.ts"
|
|
31
|
+
],
|
|
32
|
+
"publishConfig": {
|
|
33
|
+
"access": "public"
|
|
34
|
+
},
|
|
35
|
+
"devDependencies": {
|
|
36
|
+
"@biomejs/biome": "^2.3.7",
|
|
37
|
+
"@rbxts/compiler-types": "3.0.0-types.0",
|
|
38
|
+
"@rbxts/react": "17.3.0-alpha.1",
|
|
39
|
+
"@rbxts/react-roblox": "17.3.0-alpha.1",
|
|
40
|
+
"@rbxts/types": "^1.0.891",
|
|
41
|
+
"@typescript-eslint/eslint-plugin": "^8.46.4",
|
|
42
|
+
"@typescript-eslint/parser": "^8.46.4",
|
|
43
|
+
"roblox-ts": "3.0.0",
|
|
44
|
+
"typescript": "^5.9.3"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"@rbxts/charm": "^0.10.0",
|
|
48
|
+
"@rbxts/loners-pretty-react-hooks": "^0.0.3",
|
|
49
|
+
"@rbxts/react-charm": "^0.3.0",
|
|
50
|
+
"@rbxts/ripple": "^0.9.3",
|
|
51
|
+
"@rbxts/services": "^1.6.0",
|
|
52
|
+
"@rbxts/set-timeout": "^1.1.2"
|
|
53
|
+
},
|
|
54
|
+
"peerDependencies": {
|
|
55
|
+
"@rbxts/react-roblox": "*",
|
|
56
|
+
"@rbxts/react": "*"
|
|
57
|
+
}
|
|
59
58
|
}
|