@rbxts/app-forge 0.7.1 → 0.7.2-alpha.10

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.
@@ -0,0 +1,8 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local Debugger = TS.import(script, script, "debugger").default
4
+ local Logger = TS.import(script, script, "logger").default
5
+ return {
6
+ Debugger = Debugger,
7
+ Logger = Logger,
8
+ }
@@ -0,0 +1,5 @@
1
+ export default class Logger {
2
+ private readonly scope;
3
+ constructor(scope: string);
4
+ log(level: "DEBUG" | "PERF" | "INFO" | "WARN" | "ERROR", message: string, data?: unknown, traceback?: string): void;
5
+ }
@@ -0,0 +1,37 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ -- debug/logger.ts
4
+ local RunService = TS.import(script, TS.getModule(script, "@rbxts", "services")).RunService
5
+ local Logger
6
+ do
7
+ Logger = setmetatable({}, {
8
+ __tostring = function()
9
+ return "Logger"
10
+ end,
11
+ })
12
+ Logger.__index = Logger
13
+ function Logger.new(...)
14
+ local self = setmetatable({}, Logger)
15
+ return self:constructor(...) or self
16
+ end
17
+ function Logger:constructor(scope)
18
+ self.scope = scope
19
+ end
20
+ function Logger:log(level, message, data, traceback)
21
+ if not RunService:IsStudio() then
22
+ return nil
23
+ end
24
+ local prefix = `[{self.scope}][{level}]`
25
+ if data ~= nil then
26
+ print(prefix, message, data)
27
+ else
28
+ print(prefix, message)
29
+ end
30
+ if traceback ~= "" and traceback then
31
+ print(traceback)
32
+ end
33
+ end
34
+ end
35
+ return {
36
+ default = Logger,
37
+ }
@@ -2,7 +2,15 @@ import Vide from "@rbxts/vide";
2
2
  import type Types from "./types";
3
3
  import type AppForge from ".";
4
4
  export declare const AppRegistry: Map<string, Types.AppRegistry.Static>;
5
+ /**
6
+ * Registers a Vide App with AppForge.
7
+ *
8
+ * This runs at definition time and validates static configuration.
9
+ */
5
10
  export declare function App<N extends AppNames>(props: Types.AppRegistry.Props<N>): <T extends new (props: Types.Props.Main, name: AppNames) => Args>(constructor: T) => T;
11
+ /**
12
+ * Base class for all AppForge Apps.
13
+ */
6
14
  export declare abstract class Args {
7
15
  readonly forge: AppForge;
8
16
  readonly props: Types.Props.Class;
@@ -1,14 +1,33 @@
1
1
  -- Compiled with roblox-ts v3.0.0
2
2
  local TS = _G[script]
3
3
  -- Packages
4
- local px = TS.import(script, TS.getModule(script, "@rbxts", "loners-pretty-vide-utils").out).px
5
4
  -- Types
5
+ -- Hooks
6
+ local px = TS.import(script, script.Parent, "hooks", "usePx").px
7
+ -- Debug
8
+ local Logger = TS.import(script, script.Parent, "debug", "logger").default
9
+ local logger = Logger.new("AppRegistry")
6
10
  local AppRegistry = {}
11
+ --[[
12
+ *
13
+ * Registers a Vide App with AppForge.
14
+ *
15
+ * This runs at definition time and validates static configuration.
16
+
17
+ ]]
7
18
  local function App(props)
8
19
  return function(constructor)
9
20
  local _name = props.name
10
21
  if AppRegistry[_name] ~= nil then
11
- error(`Duplicate registered App name "{props.name}"`)
22
+ logger:log("ERROR", "Duplicate App name detected", {
23
+ name = props.name,
24
+ })
25
+ error(`Duplicate registered App name "{props.name}". ` .. `App names must be globally unique.`, 2)
26
+ end
27
+ local _value = props.name
28
+ if not (_value ~= "" and _value) then
29
+ logger:log("ERROR", "Attempted to register App without a name", props)
30
+ error("App registration failed: missing app name", 2)
12
31
  end
13
32
  local _name_1 = props.name
14
33
  local _arg1 = {
@@ -21,6 +40,11 @@ local function App(props)
21
40
  return constructor
22
41
  end
23
42
  end
43
+ --[[
44
+ *
45
+ * Base class for all AppForge Apps.
46
+
47
+ ]]
24
48
  local Args
25
49
  do
26
50
  Args = {}
@@ -28,13 +52,20 @@ do
28
52
  local _binding = props
29
53
  local forge = _binding.forge
30
54
  self.forge = forge
55
+ self.name = name
31
56
  local _object = table.clone(props.props)
32
57
  setmetatable(_object, nil)
33
58
  _object.px = px
34
59
  _object.forge = forge
35
60
  self.props = _object
36
- self.name = name
37
- self.source = forge:getSource(name)
61
+ local src = forge:getSource(name)
62
+ if not src then
63
+ logger:log("ERROR", "Missing visibility source for App", {
64
+ name = name,
65
+ })
66
+ error(`Failed to retrieve visibility source for app "{name}"`, 2)
67
+ end
68
+ self.source = src
38
69
  end
39
70
  end
40
71
  return {
@@ -1,5 +1,5 @@
1
1
  declare const _default: () => {
2
2
  forge: import("..").default;
3
- px: typeof import("@rbxts/loners-pretty-vide-utils").px;
3
+ px: typeof import("./usePx").px;
4
4
  };
5
5
  export default _default;
@@ -2,10 +2,14 @@
2
2
  local TS = _G[script]
3
3
  -- Components
4
4
  local Contexts = TS.import(script, script.Parent.Parent, "context").default
5
+ -- Debug
6
+ local Logger = TS.import(script, script.Parent.Parent, "debug", "logger").default
7
+ local logger = Logger.new("useAppContext")
5
8
  local default = function()
6
9
  local context = Contexts.App()
7
10
  if not context then
8
- error(`Failed to retrieve App Props for Vide {debug.traceback()}`)
11
+ logger:log("ERROR", "Failed to retrieve App context")
12
+ error(`Failed to retrieve App Props for Vide\n{debug.traceback()}`, 2)
9
13
  end
10
14
  return context
11
15
  end
@@ -0,0 +1,17 @@
1
+ type EventLike<T extends Callback = Callback> = {
2
+ Connect(callback: T): ConnectionLike;
3
+ } | {
4
+ connect(callback: T): ConnectionLike;
5
+ } | {
6
+ subscribe(callback: T): ConnectionLike;
7
+ };
8
+ type ConnectionLike = {
9
+ Disconnect(): void;
10
+ } | {
11
+ disconnect(): void;
12
+ } | (() => void);
13
+ /**
14
+ * Subscribes to an event-like object and auto-cleans up.
15
+ */
16
+ export declare function useEventListener<T extends EventLike>(event: T, listener: T extends EventLike<infer U> ? U : never): ReturnType<T>;
17
+ export {};
@@ -0,0 +1,61 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ local cleanup = TS.import(script, TS.getModule(script, "@rbxts", "vide").src).cleanup
4
+ -- Debug
5
+ local Logger = TS.import(script, script.Parent.Parent, "debug", "logger").default
6
+ local logger = Logger.new("useEventListener")
7
+ local connect = function(event, callback)
8
+ local _event = event
9
+ if typeof(_event) == "RBXScriptSignal" then
10
+ local connection
11
+ connection = event:Connect(function(...)
12
+ local args = { ... }
13
+ if connection.Connected then
14
+ return callback(unpack(args))
15
+ end
16
+ end)
17
+ return connection
18
+ elseif event.Connect ~= nil then
19
+ return event:Connect(callback)
20
+ elseif event.connect ~= nil then
21
+ return event:connect(callback)
22
+ elseif event.subscribe ~= nil then
23
+ return event:subscribe(callback)
24
+ end
25
+ logger:log("ERROR", "Unsupported event-like object", event)
26
+ error("Event-like object does not have a supported connect method.", 2)
27
+ end
28
+ local disconnect = function(connection)
29
+ local _connection = connection
30
+ if type(_connection) == "function" then
31
+ connection()
32
+ else
33
+ local _connection_1 = connection
34
+ local _condition = typeof(_connection_1) == "RBXScriptConnection"
35
+ if not _condition then
36
+ _condition = connection.Disconnect ~= nil
37
+ end
38
+ if _condition then
39
+ connection:Disconnect()
40
+ elseif connection.disconnect ~= nil then
41
+ connection:disconnect()
42
+ else
43
+ logger:log("WARN", "Unsupported connection-like object during cleanup", connection)
44
+ end
45
+ end
46
+ end
47
+ --[[
48
+ *
49
+ * Subscribes to an event-like object and auto-cleans up.
50
+
51
+ ]]
52
+ local function useEventListener(event, listener)
53
+ local connection = connect(event, listener)
54
+ cleanup(function()
55
+ return disconnect(connection)
56
+ end)
57
+ return connection
58
+ end
59
+ return {
60
+ useEventListener = useEventListener,
61
+ }
@@ -0,0 +1,11 @@
1
+ export declare const px: ((value: number) => number) & {
2
+ scale: (value: number) => number;
3
+ even: (value: number) => number;
4
+ floor: (value: number) => number;
5
+ ceil: (value: number) => number;
6
+ };
7
+ /**
8
+ * Initializes global px scaling.
9
+ * Must be called exactly once.
10
+ */
11
+ export declare function usePx(target?: GuiObject | Camera, baseResolution?: Vector2, minScale?: number): void;
@@ -0,0 +1,98 @@
1
+ -- Compiled with roblox-ts v3.0.0
2
+ local TS = _G[script]
3
+ -- Services
4
+ local Workspace = TS.import(script, TS.getModule(script, "@rbxts", "services")).Workspace
5
+ -- Packages
6
+ local source = TS.import(script, TS.getModule(script, "@rbxts", "vide").src).source
7
+ -- Helpers
8
+ local useEventListener = TS.import(script, script.Parent, "useEventListener").useEventListener
9
+ -- Debug
10
+ local Logger = TS.import(script, script.Parent.Parent, "debug", "logger").default
11
+ local logger = Logger.new("usePx")
12
+ --* Default reference resolution for px calculations
13
+ local BASE_RESOLUTION = source(Vector2.new(1920, 1080))
14
+ --* Minimum allowed scale to prevent unreadable UI
15
+ local MIN_SCALE = source(0.5)
16
+ --* 0 = width-based, 1 = height-based
17
+ local DOMINANT_AXIS = 0.5
18
+ local TARGET = source(Workspace.CurrentCamera)
19
+ local SCALE = source(1)
20
+ local INITIALIZED = false
21
+ local function callable(callback, object)
22
+ return setmetatable(object, {
23
+ __call = function(_, ...)
24
+ local args = { ... }
25
+ return callback(unpack(args))
26
+ end,
27
+ })
28
+ end
29
+ local px = callable(function(value)
30
+ return math.round(value * SCALE())
31
+ end, {
32
+ scale = function(value)
33
+ return value * SCALE()
34
+ end,
35
+ even = function(value)
36
+ return math.round(value * SCALE() * 0.5) * 2
37
+ end,
38
+ floor = function(value)
39
+ return math.floor(value * SCALE())
40
+ end,
41
+ ceil = function(value)
42
+ return math.ceil(value * SCALE())
43
+ end,
44
+ })
45
+ local function calculateScale()
46
+ local target = TARGET()
47
+ if not target then
48
+ return nil
49
+ end
50
+ local size = if target:IsA("Camera") then target.ViewportSize elseif target:IsA("GuiObject") then target.AbsoluteSize else nil
51
+ if not size then
52
+ return nil
53
+ end
54
+ local res = BASE_RESOLUTION()
55
+ if res.X <= 0 or res.Y <= 0 then
56
+ return nil
57
+ end
58
+ local min = MIN_SCALE()
59
+ local width = math.log(size.X / res.X, 2)
60
+ local height = math.log(size.Y / res.Y, 2)
61
+ local centered = width + (height - width) * DOMINANT_AXIS
62
+ local scale = 2 ^ centered
63
+ SCALE(math.max(scale, min))
64
+ end
65
+ --[[
66
+ *
67
+ * Initializes global px scaling.
68
+ * Must be called exactly once.
69
+
70
+ ]]
71
+ local function usePx(target, baseResolution, minScale)
72
+ if INITIALIZED then
73
+ logger:log("WARN", "usePx() called more than once")
74
+ return nil
75
+ end
76
+ INITIALIZED = true
77
+ if baseResolution then
78
+ BASE_RESOLUTION(baseResolution)
79
+ end
80
+ if minScale ~= nil then
81
+ MIN_SCALE(minScale)
82
+ end
83
+ if target then
84
+ TARGET(target)
85
+ end
86
+ local resolvedTarget = TARGET()
87
+ if not resolvedTarget then
88
+ logger:log("WARN", "usePx(): no valid target to observe")
89
+ return nil
90
+ end
91
+ local signal = if resolvedTarget:IsA("Camera") then resolvedTarget:GetPropertyChangedSignal("ViewportSize") else resolvedTarget:GetPropertyChangedSignal("AbsoluteSize")
92
+ useEventListener(signal, calculateScale)
93
+ calculateScale()
94
+ end
95
+ return {
96
+ usePx = usePx,
97
+ px = px,
98
+ }
@@ -1,6 +1,7 @@
1
1
  import Vide from "@rbxts/vide";
2
2
  import Renders from "./classes/renders";
3
3
  import Types from "./types";
4
+ import { Logger, Debugger } from "./debug";
4
5
  type Destructor = () => void;
5
6
  type Loaded = {
6
7
  container: Vide.Node;
@@ -8,17 +9,19 @@ type Loaded = {
8
9
  anchor?: Vide.Node;
9
10
  };
10
11
  export default class AppForge extends Renders {
12
+ readonly logger: Logger;
13
+ readonly debug: Debugger;
11
14
  protected sources: Map<string, Vide.Source<boolean>>;
12
15
  protected loaded: Map<string, Loaded>;
13
16
  protected innerMount?: Destructor;
14
17
  protected __px: boolean;
15
18
  constructor();
16
- protected createSource(name: AppNames): typeof Vide.source | undefined;
19
+ protected createSource(name: AppNames): void;
20
+ getSource(name: AppNames): Vide.Source<boolean>;
17
21
  isLoaded(name: AppNames): boolean;
18
22
  bind(name: AppNames, value: Vide.Source<boolean>): void;
19
23
  anchor(name: AppNames, anchorName: AppNames, props: Types.Props.Main): void;
20
24
  index(name: AppNames, index: number): void;
21
- getSource(name: AppNames): Vide.Source<boolean>;
22
25
  set(name: AppNames, value: boolean, rules?: boolean): void;
23
26
  open(name: AppNames, rules?: boolean): void;
24
27
  close(name: AppNames, rules?: boolean): void;
@@ -4,6 +4,7 @@ local TS = _G[script]
4
4
  local RunService = TS.import(script, TS.getModule(script, "@rbxts", "services")).RunService
5
5
  -- Packages
6
6
  local _vide = TS.import(script, TS.getModule(script, "@rbxts", "vide").src)
7
+ local Vide = _vide
7
8
  local apply = _vide.apply
8
9
  local create = _vide.create
9
10
  local effect = _vide.effect
@@ -14,6 +15,10 @@ local untrack = _vide.untrack
14
15
  local Renders = TS.import(script, script, "classes", "renders").default
15
16
  -- Helpers
16
17
  local AppRegistry = TS.import(script, script, "decorator").AppRegistry
18
+ -- Debug
19
+ local _debug = TS.import(script, script, "debug")
20
+ local Logger = _debug.Logger
21
+ local Debugger = _debug.Debugger
17
22
  local AppForge
18
23
  do
19
24
  local super = Renders
@@ -30,6 +35,10 @@ do
30
35
  end
31
36
  function AppForge:constructor()
32
37
  super.constructor(self)
38
+ self.logger = Logger.new("AppForge")
39
+ self.debug = Debugger.new(function(level, msg, data, trace)
40
+ return self.logger:log(level, msg, data, trace)
41
+ end)
33
42
  self.sources = {}
34
43
  self.loaded = {}
35
44
  self.__px = false
@@ -46,22 +55,48 @@ do
46
55
  local _name = name
47
56
  local app = AppRegistry[_name]
48
57
  if not app then
49
- error(`App "{name}" not registered`)
58
+ self.logger:log("ERROR", "App not registered while creating source", {
59
+ name = name,
60
+ })
61
+ return nil
50
62
  end
51
63
  local _sources = self.sources
52
64
  local _name_1 = name
53
65
  if _sources[_name_1] ~= nil then
54
66
  return nil
55
67
  end
56
- local _sources_1 = self.sources
68
+ local _debug_1 = self.debug
57
69
  local _exp = name
70
+ local _object = {}
71
+ local _left = "default"
58
72
  local _condition = app.visible
59
73
  if _condition == nil then
60
74
  _condition = false
61
75
  end
62
- local _arg1 = source(_condition)
63
- _sources_1[_exp] = _arg1
64
- return source
76
+ _object[_left] = _condition
77
+ _debug_1:logTag("state", _exp, "Creating visibility source", _object)
78
+ local _sources_1 = self.sources
79
+ local _exp_1 = name
80
+ local _condition_1 = app.visible
81
+ if _condition_1 == nil then
82
+ _condition_1 = false
83
+ end
84
+ local _arg1 = source(_condition_1)
85
+ _sources_1[_exp_1] = _arg1
86
+ end
87
+ function AppForge:getSource(name)
88
+ local _sources = self.sources
89
+ local _name = name
90
+ if not (_sources[_name] ~= nil) then
91
+ self:createSource(name)
92
+ end
93
+ local _sources_1 = self.sources
94
+ local _name_1 = name
95
+ local src = _sources_1[_name_1]
96
+ if not src then
97
+ error(`AppForge invariant broken: missing visibility source for {name}`, 2)
98
+ end
99
+ return src
65
100
  end
66
101
  function AppForge:isLoaded(name)
67
102
  local _loaded = self.loaded
@@ -70,28 +105,53 @@ do
70
105
  end
71
106
  function AppForge:bind(name, value)
72
107
  if not RunService:IsRunning() then
108
+ self.debug:logTag("state", name, "Binding external visibility source")
73
109
  local _sources = self.sources
74
110
  local _name = name
75
111
  local _value = value
76
112
  _sources[_name] = _value
113
+ local prev
114
+ local log = function()
115
+ return self.debug:logTag("state", name, "Visibility changed", {
116
+ from = prev,
117
+ to = value,
118
+ })
119
+ end
120
+ local count = 0
77
121
  effect(function()
78
- value()
122
+ count += 1
123
+ prev = value
79
124
  untrack(function()
80
125
  return self:checkRules(name)
81
126
  end)
127
+ if Vide.strict and count == 1 then
128
+ log()
129
+ count = 0
130
+ else
131
+ log()
132
+ end
82
133
  end)
83
134
  else
84
- warn("forge.bind is used for studio when game isnt running")
135
+ self.logger:log("WARN", "forge.bind called while game is running", {
136
+ name = name,
137
+ })
85
138
  end
86
139
  end
87
140
  function AppForge:anchor(name, anchorName, props)
88
141
  if name == anchorName then
89
- error(`Tried to anchor an App to itself`)
142
+ self.logger:log("ERROR", "Attempted to anchor app to itself", {
143
+ name = name,
144
+ })
145
+ return nil
90
146
  end
91
147
  local _anchorName = anchorName
92
148
  local anchorApp = AppRegistry[_anchorName]
93
149
  if not anchorApp then
94
- error(`Failed to get class for {anchorName} from AppRegistry for anchor`)
150
+ self.logger:log("ERROR", "Anchor parent not registered", {
151
+ child = name,
152
+ parent = anchorName,
153
+ })
154
+ return nil
95
155
  end
96
156
  local _loaded = self.loaded
97
157
  local _name = name
@@ -101,11 +161,17 @@ do
101
161
  end
102
162
  local render = _render
103
163
  if not render then
104
- error(`Failed to get {name} from this.loaded for anchor to {anchorName}`)
164
+ self.debug:logTag("rules", name, "Anchor skipped (child not rendered yet)", {
165
+ parent = anchorName,
166
+ })
167
+ return nil
105
168
  end
169
+ self.debug:logTag("rules", name, "Anchoring to parent", {
170
+ parent = anchorName,
171
+ })
106
172
  local anchor = anchorApp.constructor.new(props, anchorName):render()
107
- for _, children in anchor:GetDescendants() do
108
- children:Destroy()
173
+ for _, child in anchor:GetDescendants() do
174
+ child:Destroy()
109
175
  end
110
176
  apply(anchor)({
111
177
  Name = "Anchor",
@@ -116,7 +182,7 @@ do
116
182
  local _name_1 = name
117
183
  local prev = _loaded_1[_name_1]
118
184
  if not prev then
119
- error(`Failed to retreive prev loaded data for {name}`)
185
+ error(`AppForge invariant broken: missing loaded app for {name}`, 2)
120
186
  end
121
187
  apply(prev.container)({
122
188
  [0] = anchor,
@@ -133,22 +199,19 @@ do
133
199
  local _name = name
134
200
  local loaded = _loaded[_name]
135
201
  if not loaded then
136
- error(`Failed to retreive loaded data for app: {name}`)
202
+ self.logger:log("WARN", "ZIndex skipped (app not loaded)", {
203
+ name = name,
204
+ index = index,
205
+ })
206
+ return nil
137
207
  end
208
+ self.debug:logTag("rules", name, "Applying ZIndex", {
209
+ index = index,
210
+ })
138
211
  apply(loaded.container)({
139
212
  ZIndex = index,
140
213
  })
141
214
  end
142
- function AppForge:getSource(name)
143
- local _sources = self.sources
144
- local _name = name
145
- if not (_sources[_name] ~= nil) then
146
- self:createSource(name)
147
- end
148
- local _sources_1 = self.sources
149
- local _name_1 = name
150
- return _sources_1[_name_1]
151
- end
152
215
  function AppForge:set(name, value, rules)
153
216
  if rules == nil then
154
217
  rules = true
@@ -162,10 +225,21 @@ do
162
225
  local _name_1 = name
163
226
  src = _sources_1[_name_1]
164
227
  end
165
- if src() == value then
228
+ if not src then
229
+ self.logger:log("ERROR", "Failed to set visibility (missing source)", {
230
+ name = name,
231
+ })
232
+ return nil
233
+ end
234
+ local prev = src()
235
+ if prev == value then
166
236
  return nil
167
237
  end
168
238
  src(value)
239
+ self.debug:logTag("state", name, "Visibility changed", {
240
+ from = prev,
241
+ to = value,
242
+ })
169
243
  if rules then
170
244
  self:checkRules(name)
171
245
  end
@@ -189,6 +263,7 @@ do
189
263
  self:set(name, not self:getSource(name)(), rules)
190
264
  end
191
265
  function AppForge:story(props)
266
+ self.debug:logTag("lifecycle", "story", "Creating story mount")
192
267
  local Container = create("Frame")({
193
268
  Name = "Story Container",
194
269
  BackgroundTransparency = 1,
@@ -202,6 +277,7 @@ do
202
277
  return Container
203
278
  end
204
279
  function AppForge:mount(callback, props, target)
280
+ self.debug:logTag("lifecycle", "mount", "Mounting AppForge")
205
281
  local Container = callback()
206
282
  self.innerMount = mount(function()
207
283
  apply(Container)({
@@ -212,6 +288,7 @@ do
212
288
  return self.innerMount
213
289
  end
214
290
  function AppForge:unMount()
291
+ self.debug:logTag("lifecycle", "unmount", "Unmounting AppForge")
215
292
  local _result = self.innerMount
216
293
  if _result ~= nil then
217
294
  _result()
@@ -26,7 +26,7 @@ declare namespace Types {
26
26
 
27
27
  type Class = AppProps & {
28
28
  forge: AppForge;
29
- px: typeof import("@rbxts/loners-pretty-vide-utils").px;
29
+ px: typeof import("./hooks/usePx").px;
30
30
  };
31
31
  }
32
32
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rbxts/app-forge",
3
- "version": "0.7.1",
3
+ "version": "0.7.2-alpha.10",
4
4
  "description": "An App Manager for Vide",
5
5
  "main": "out/init.lua",
6
6
  "types": "out/index.d.ts",
@@ -38,11 +38,17 @@
38
38
  "@rbxts/set-timeout": "^1.1.2"
39
39
  },
40
40
  "peerDependencies": {
41
- "@rbxts/loners-pretty-react-hooks": "^0.2.9",
42
- "@rbxts/loners-pretty-vide-utils": "^0.1.7",
43
41
  "@rbxts/react": "^17.3.7-ts.1",
44
42
  "@rbxts/vide": "^0.5.7"
45
43
  },
44
+ "peerDependenciesMeta": {
45
+ "@rbxts/react": {
46
+ "optional": true
47
+ },
48
+ "@rbxts/vide": {
49
+ "optional": true
50
+ }
51
+ },
46
52
  "devDependencies": {
47
53
  "@biomejs/biome": "^2.3.7",
48
54
  "@rbxts/compiler-types": "3.0.0-types.0",