@rbxts/app-forge 0.0.1

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/LICENSE.md ADDED
@@ -0,0 +1,9 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2024 Littensy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
6
+
7
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
8
+
9
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
package/README.md ADDED
File without changes
@@ -0,0 +1,5 @@
1
+ import type AppManager from ".";
2
+ export declare function AppContainer(props: AppProps & {
3
+ name: AppNames[number];
4
+ manager: AppManager;
5
+ }): JSX.Element;
@@ -0,0 +1,48 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ -- Services
4
+ local RunService = TS.import(script, TS.getModule(script, "@rbxts", "services")).RunService
5
+ -- Packages
6
+ local _loners_pretty_react_hooks = TS.import(script, TS.getModule(script, "@rbxts", "loners-pretty-react-hooks").out)
7
+ local useBindingListener = _loners_pretty_react_hooks.useBindingListener
8
+ local useSpring = _loners_pretty_react_hooks.useSpring
9
+ local _react = TS.import(script, TS.getModule(script, "@rbxts", "react"))
10
+ local React = _react
11
+ local useState = _react.useState
12
+ -- Types
13
+ local function AppContainer(props)
14
+ local _binding = props
15
+ local name = _binding.name
16
+ local manager = _binding.manager
17
+ local binding, _ = manager:createBinding(name)
18
+ local spring = useSpring(binding:map(function(v)
19
+ return if v then 0 else 1
20
+ end), {
21
+ frequency = 0.4,
22
+ damping = 0.8,
23
+ })
24
+ local _isVisible, setisVisible = useState(binding:getValue())
25
+ local element = manager:createInstance(props, name)
26
+ if not element then
27
+ error(`Failed to create instance for app "{name}"`)
28
+ end
29
+ useBindingListener(spring, function(v)
30
+ setisVisible(v == 0)
31
+ end)
32
+ if RunService:IsRunning() then
33
+ return React.createElement("screengui", {
34
+ key = name,
35
+ ZIndexBehavior = "Sibling",
36
+ ResetOnSpawn = false,
37
+ }, element)
38
+ else
39
+ return React.createElement("frame", {
40
+ key = name,
41
+ BackgroundTransparency = 1,
42
+ Size = UDim2.fromScale(1, 1),
43
+ }, element)
44
+ end
45
+ end
46
+ return {
47
+ AppContainer = AppContainer,
48
+ }
@@ -0,0 +1,9 @@
1
+ import React from "@rbxts/react";
2
+ import type Types from "./types";
3
+ 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 abstract class Args {
6
+ readonly props: AppProps;
7
+ constructor(props: AppProps);
8
+ abstract render(): React.Element;
9
+ }
@@ -0,0 +1,32 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ -- Packages
3
+ -- Types
4
+ local AppRegistry = {}
5
+ local function App(props)
6
+ return function(constructor)
7
+ local _name = props.name
8
+ if AppRegistry[_name] ~= nil then
9
+ error(`Duplicate registered App name "{props.name}"`)
10
+ end
11
+ local _name_1 = props.name
12
+ local _arg1 = {
13
+ constructor = constructor,
14
+ visible = props.visible,
15
+ rules = props.rules,
16
+ }
17
+ AppRegistry[_name_1] = _arg1
18
+ return constructor
19
+ end
20
+ end
21
+ local Args
22
+ do
23
+ Args = {}
24
+ function Args:constructor(props)
25
+ self.props = props
26
+ end
27
+ end
28
+ return {
29
+ App = App,
30
+ AppRegistry = AppRegistry,
31
+ Args = Args,
32
+ }
@@ -0,0 +1,9 @@
1
+ declare global {
2
+ // These will be overridden by the user
3
+ // They are only placeholders for your build
4
+
5
+ type AppGroups = readonly string[];
6
+ type AppNames = readonly string[];
7
+ type AppProps = {}
8
+ }
9
+ export {};
@@ -0,0 +1,6 @@
1
+ import type AppManager from ".";
2
+ export declare function Render({ props, manager, names, }: {
3
+ props: AppProps;
4
+ manager: AppManager;
5
+ names?: AppNames[number] | AppNames[number][];
6
+ }): JSX.Element | JSX.Element[];
@@ -0,0 +1,18 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ -- Types
3
+ local function Render(_param)
4
+ local props = _param.props
5
+ local manager = _param.manager
6
+ local names = _param.names
7
+ if names ~= "" and names then
8
+ if type(names) == "table" then
9
+ return manager:renderApps(props, names)
10
+ else
11
+ return manager:renderApp(props, names)
12
+ end
13
+ end
14
+ return manager:renderAll(props)
15
+ end
16
+ return {
17
+ Render = Render,
18
+ }
package/out/index.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ import React from "@rbxts/react";
2
+ import { Args, App } from "./decorator";
3
+ export default class AppManager {
4
+ private binds;
5
+ private loaded;
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
+ getBind(name: AppNames[number]): React.Binding<boolean>;
11
+ getState(name: AppNames[number]): boolean;
12
+ set(name: AppNames[number], value: boolean): void;
13
+ open(name: AppNames[number]): void;
14
+ close(name: AppNames[number]): void;
15
+ toggle(name: AppNames[number]): void;
16
+ renderApp(props: AppProps, name: AppNames[number]): JSX.Element;
17
+ renderApps(props: AppProps, names: AppNames[number][]): JSX.Element[];
18
+ renderAll(props: AppProps): JSX.Element[];
19
+ }
20
+ export { App, Args };
21
+ export { Render } from "./helpers";
package/out/init.luau ADDED
@@ -0,0 +1,138 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local exports = {}
4
+ -- Packages
5
+ local _react = TS.import(script, TS.getModule(script, "@rbxts", "react"))
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"))
10
+ -- Components
11
+ local _decorator = TS.import(script, script, "decorator")
12
+ local AppRegistry = _decorator.AppRegistry
13
+ local Args = _decorator.Args
14
+ local App = _decorator.App
15
+ local AppContainer = TS.import(script, script, "container").AppContainer
16
+ local RulesManager = TS.import(script, script, "rules").default
17
+ local AppManager
18
+ do
19
+ AppManager = setmetatable({}, {
20
+ __tostring = function()
21
+ return "AppManager"
22
+ end,
23
+ })
24
+ AppManager.__index = AppManager
25
+ function AppManager.new(...)
26
+ local self = setmetatable({}, AppManager)
27
+ return self:constructor(...) or self
28
+ end
29
+ function AppManager:constructor()
30
+ self.binds = {}
31
+ self.loaded = {}
32
+ self.rulesManager = RulesManager.new(self)
33
+ end
34
+ function AppManager:getAllNames()
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)
75
+ local _binds = self.binds
76
+ local _name = name
77
+ if not (_binds[_name] ~= nil) then
78
+ error(`App "{name}" has no binding`)
79
+ end
80
+ local _binds_1 = self.binds
81
+ local _name_1 = name
82
+ return _binds_1[_name_1][1]
83
+ end
84
+ function AppManager:getState(name)
85
+ return self:getBind(name):getValue()
86
+ end
87
+ function AppManager:set(name, value)
88
+ if not self.rulesManager:applyRules(name, value) then
89
+ return nil
90
+ end
91
+ local _binds = self.binds
92
+ local _name = name
93
+ local _binding = _binds[_name]
94
+ local _ = _binding[1]
95
+ local setBinding = _binding[2]
96
+ setBinding(value)
97
+ end
98
+ function AppManager:open(name)
99
+ self:set(name, true)
100
+ end
101
+ function AppManager:close(name)
102
+ self:set(name, false)
103
+ end
104
+ function AppManager:toggle(name)
105
+ self:set(name, not self:getState(name))
106
+ end
107
+ function AppManager:renderApp(props, name)
108
+ local _attributes = {
109
+ key = `{name}_Container`,
110
+ name = name,
111
+ manager = self,
112
+ }
113
+ for _k, _v in props do
114
+ _attributes[_k] = _v
115
+ end
116
+ return React.createElement(AppContainer, _attributes)
117
+ end
118
+ function AppManager:renderApps(props, names)
119
+ -- ▼ ReadonlyArray.map ▼
120
+ local _newValue = table.create(#names)
121
+ local _callback = function(n)
122
+ return self:renderApp(props, n)
123
+ end
124
+ for _k, _v in names do
125
+ _newValue[_k] = _callback(_v, _k - 1, names)
126
+ end
127
+ -- ▲ ReadonlyArray.map ▲
128
+ return _newValue
129
+ end
130
+ function AppManager:renderAll(props)
131
+ return self:renderApps(props, self:getAllNames())
132
+ end
133
+ end
134
+ exports.Render = TS.import(script, script, "helpers").Render
135
+ exports.default = AppManager
136
+ exports.App = App
137
+ exports.Args = Args
138
+ return exports
package/out/rules.d.ts ADDED
@@ -0,0 +1,11 @@
1
+ import AppManager from ".";
2
+ export default class RulesManager {
3
+ private appManager;
4
+ constructor(appManager: AppManager);
5
+ applyRules(name: AppNames[number], value: boolean): boolean;
6
+ private inSameGroup;
7
+ private blockedBy;
8
+ private blocks;
9
+ private exclusive;
10
+ private layer;
11
+ }
package/out/rules.luau ADDED
@@ -0,0 +1,195 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ -- Packages
4
+ local Object = TS.import(script, TS.getModule(script, "@rbxts", "object-utils"))
5
+ -- Components
6
+ local AppRegistry = TS.import(script, script.Parent, "decorator").AppRegistry
7
+ -- Types
8
+ local function asTable(value)
9
+ local _value = value
10
+ if type(_value) == "table" then
11
+ return value
12
+ else
13
+ local t = {}
14
+ t[2] = value
15
+ return t
16
+ end
17
+ end
18
+ local RulesManager
19
+ do
20
+ RulesManager = setmetatable({}, {
21
+ __tostring = function()
22
+ return "RulesManager"
23
+ end,
24
+ })
25
+ RulesManager.__index = RulesManager
26
+ function RulesManager.new(...)
27
+ local self = setmetatable({}, RulesManager)
28
+ return self:constructor(...) or self
29
+ end
30
+ function RulesManager:constructor(appManager)
31
+ self.appManager = appManager
32
+ end
33
+ function RulesManager:applyRules(name, value)
34
+ local _name = name
35
+ local appData = AppRegistry[_name]
36
+ local _rules = appData
37
+ if _rules ~= nil then
38
+ _rules = _rules.rules
39
+ end
40
+ local rules = _rules
41
+ local _result = rules
42
+ if _result ~= nil then
43
+ _result = _result.groups
44
+ end
45
+ if _result == "Core" then
46
+ return true
47
+ end
48
+ if value then
49
+ local allNames = Object.keys(AppRegistry)
50
+ -- ▼ ReadonlyArray.forEach ▼
51
+ local _callback = function(n)
52
+ if not (n ~= "" and n) or n == name then
53
+ return nil
54
+ end
55
+ local _n = n
56
+ local otherApp = AppRegistry[_n]
57
+ local _result_1 = otherApp
58
+ if _result_1 ~= nil then
59
+ _result_1 = _result_1.rules
60
+ if _result_1 ~= nil then
61
+ _result_1 = _result_1.groups
62
+ end
63
+ end
64
+ local groups = if _result_1 ~= "" and _result_1 then asTable(otherApp.rules.groups) else {}
65
+ -- ▼ ReadonlyArray.find ▼
66
+ local _callback_1 = function(g)
67
+ return g == "Core"
68
+ end
69
+ local _result_2
70
+ for _i, _v in groups do
71
+ if _callback_1(_v, _i - 1, groups) == true then
72
+ _result_2 = _v
73
+ break
74
+ end
75
+ end
76
+ -- ▲ ReadonlyArray.find ▲
77
+ if _result_2 then
78
+ return nil
79
+ end
80
+ if self.appManager:getState(n) then
81
+ self.appManager:set(n, false)
82
+ end
83
+ end
84
+ for _k, _v in allNames do
85
+ _callback(_v, _k - 1, allNames)
86
+ end
87
+ -- ▲ ReadonlyArray.forEach ▲
88
+ end
89
+ if not rules then
90
+ return true
91
+ end
92
+ local _condition = value
93
+ if _condition then
94
+ _condition = rules.blockedBy
95
+ if _condition ~= "" and _condition then
96
+ _condition = not self:blockedBy(name, rules.blockedBy)
97
+ end
98
+ end
99
+ if _condition ~= "" and _condition then
100
+ return false
101
+ end
102
+ local _value = value and rules.blocks
103
+ if _value ~= "" and _value then
104
+ self:blocks(name, rules.blocks)
105
+ end
106
+ if value and rules.layer ~= nil then
107
+ self:layer(name, rules.layer)
108
+ end
109
+ if value and rules.exclusive then
110
+ self:exclusive(name)
111
+ end
112
+ return true
113
+ end
114
+ function RulesManager:inSameGroup(a, b)
115
+ local _a = a
116
+ local appA = AppRegistry[_a]
117
+ local _b = b
118
+ local appB = AppRegistry[_b]
119
+ if not appA or not appB then
120
+ return false
121
+ end
122
+ local _result = appA.rules
123
+ if _result ~= nil then
124
+ _result = _result.groups
125
+ end
126
+ local _condition = _result
127
+ if _condition == nil then
128
+ _condition = {}
129
+ end
130
+ local groupsA = asTable(_condition)
131
+ local _result_1 = appB.rules
132
+ if _result_1 ~= nil then
133
+ _result_1 = _result_1.groups
134
+ end
135
+ local _condition_1 = _result_1
136
+ if _condition_1 == nil then
137
+ _condition_1 = {}
138
+ end
139
+ local groupsB = asTable(_condition_1)
140
+ for i = 1, #groupsA do
141
+ for j = 1, #groupsB do
142
+ if groupsA[i + 1] == groupsB[j + 1] then
143
+ return true
144
+ end
145
+ end
146
+ end
147
+ return false
148
+ end
149
+ function RulesManager:blockedBy(name, rule)
150
+ local blockers = asTable(rule)
151
+ for i = 1, #blockers do
152
+ local blocker = blockers[i + 1]
153
+ if self:inSameGroup(name, blocker) or not (blocker ~= "" and blocker) then
154
+ continue
155
+ end
156
+ if self.appManager:getState(blocker) then
157
+ return false
158
+ end
159
+ end
160
+ return true
161
+ end
162
+ function RulesManager:blocks(name, rule)
163
+ local blocked = asTable(rule)
164
+ for i = 1, #blocked do
165
+ local b = blocked[i + 1]
166
+ if self:inSameGroup(name, b) or not (b ~= "" and b) then
167
+ continue
168
+ end
169
+ if self.appManager:getState(b) then
170
+ self.appManager:set(b, false)
171
+ end
172
+ end
173
+ end
174
+ function RulesManager:exclusive(name)
175
+ local names = Object.keys(AppRegistry)
176
+ for i = 1, #names do
177
+ local other = names[i + 1]
178
+ if other == name or not (other ~= "" and other) then
179
+ continue
180
+ end
181
+ if self:inSameGroup(name, other) then
182
+ continue
183
+ end
184
+ if self.appManager:getState(other) then
185
+ self.appManager:set(other, false)
186
+ end
187
+ end
188
+ end
189
+ function RulesManager:layer(_name, _layer)
190
+ -- TODO: implement priority / layering
191
+ end
192
+ end
193
+ return {
194
+ default = RulesManager,
195
+ }
package/out/types.d.ts ADDED
@@ -0,0 +1,34 @@
1
+ // Types
2
+ import type { Args } from "./decorator";
3
+
4
+ declare namespace Types {
5
+ type AppRegistryProps = {
6
+ name: AppNames[number];
7
+ visible?: boolean;
8
+ rules?: Rules.All;
9
+ };
10
+
11
+ type AppRegistry = {
12
+ constructor: new (props: AppProps) => Args;
13
+ visible?: boolean;
14
+ rules?: Rules.All;
15
+ };
16
+
17
+ namespace Rules {
18
+ type Groups = AppGroups[number] | "Core" | "Core"[] | AppGroups[number][];
19
+ type BlockedBy = AppNames[number] | AppNames[number][];
20
+ type Blocks = AppNames[number] | AppNames[number][];
21
+ type Exclusive = boolean;
22
+ type Layer = number;
23
+
24
+ type All = {
25
+ blockedBy?: BlockedBy;
26
+ exclusive?: Exclusive;
27
+ groups?: Groups;
28
+ blocks?: Blocks;
29
+ layer?: Layer;
30
+ };
31
+ }
32
+ }
33
+
34
+ export default Types;
package/package.json ADDED
@@ -0,0 +1,60 @@
1
+ {
2
+ "name": "@rbxts/app-forge",
3
+ "version": "0.0.1",
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
+ },
13
+ "keywords": [
14
+ "roact",
15
+ "react",
16
+ "roblox-ts"
17
+ ],
18
+ "author": "Add your name here",
19
+ "license": "Add your license here etc. MIT",
20
+ "repository": {
21
+ "type": "git",
22
+ "url": "Add your repository url here"
23
+ },
24
+ "bugs": {
25
+ "url": "add your issues url here"
26
+ },
27
+ "types": "out/index.d.ts",
28
+ "files": [
29
+ "out",
30
+ "!**/*.tsbuildinfo",
31
+ "!**/*.spec.lua",
32
+ "!**/*.spec.d.ts"
33
+ ],
34
+ "publishConfig": {
35
+ "access": "public"
36
+ },
37
+ "devDependencies": {
38
+ "@rbxts/compiler-types": "3.0.0-types.0",
39
+ "@rbxts/react": "17.3.0-alpha.1",
40
+ "@rbxts/react-roblox": "17.3.0-alpha.1",
41
+ "@rbxts/types": "^1.0.891",
42
+ "@typescript-eslint/eslint-plugin": "^8.46.4",
43
+ "@typescript-eslint/parser": "^8.46.4",
44
+ "roblox-ts": "3.0.0",
45
+ "typescript": "^5.9.3"
46
+ },
47
+ "dependencies": {
48
+ "@rbxts/charm": "^0.10.0",
49
+ "@rbxts/loners-pretty-react-hooks": "^0.0.3",
50
+ "@rbxts/react-charm": "^0.3.0",
51
+ "@rbxts/ripple": "^0.9.3",
52
+ "@rbxts/services": "^1.6.0",
53
+ "@rbxts/set-timeout": "^1.1.2"
54
+ },
55
+ "peerDependencies": {
56
+ "@rbxts/object-utils": "*",
57
+ "@rbxts/react-roblox": "*",
58
+ "@rbxts/react": "*"
59
+ }
60
+ }