-- Compiled with roblox-ts v3.0.0 local TS = _G[script] -- Packages local _vide = TS.import(script, TS.getModule(script, "@rbxts", "vide").src) local batch = _vide.batch local source = _vide.source -- Internal local attachHotkeys = TS.import(script, script, "hotkeys").default local boot = TS.import(script, script, "boot").default -- Everything is assigned as closures in the constructor so handles and methods -- pass directly as callbacks without self. local ForgeImpl do ForgeImpl = setmetatable({}, { __tostring = function() return "ForgeImpl" end, }) ForgeImpl.__index = ForgeImpl function ForgeImpl.new(...) local self = setmetatable({}, ForgeImpl) return self:constructor(...) or self end function ForgeImpl:constructor(config) local rules = config.windows local lanes = {} for lane, def in pairs(config.exclusive or {}) do local members = if def.members ~= nil then def.members else def local mode = if def.mode ~= nil then (def.mode or "displace") else "displace" local _arg1 = { mode = mode, members = members, } lanes[lane] = _arg1 end local _binding = boot(rules, lanes) local children = _binding.children local windowLanes = _binding.windowLanes local sources = {} for name, def in pairs(rules) do local _result = def.defaults if _result ~= nil then _result = _result.open end local _condition = _result if _condition == nil then _condition = false end local _arg1 = source(_condition) sources[name] = _arg1 end local src = function(name) local _name = name return sources[_name] end local queues = {} local occupant = function(lane, except) local _lane = lane for _, member in lanes[_lane].members do if member ~= except and src(member)() then return member end end return nil end local function closeInternal(name, closed) if not src(name)() then return nil end src(name)(false) local _closed = closed local _name = name table.insert(_closed, _name) local _name_1 = name local _condition = children[_name_1] if _condition == nil then _condition = {} end for _, child in _condition do closeInternal(child, closed) end end local fireClosed = function(closed) for _, name in closed do local _result = rules[name].onClose if _result ~= nil then _result() end end end -- Admits waiting windows into queue lanes that just freed up. local pumping = false local open local function pump() if pumping then return nil end pumping = true for lane, queue in queues do while #queue > 0 and occupant(lane, "") == nil do local upNext = table.remove(queue, 1) if not src(upNext)() then open(upNext) end end end pumping = false end local function close(name) local closed = {} batch(function() return closeInternal(name, closed) end) fireClosed(closed) pump() end function open(name, force) if src(name)() then return true end local def = rules[name] local _name = name local _condition = windowLanes[_name] if _condition == nil then _condition = {} end local memberLanes = _condition if not force then for _, blocker in def.blockedBy or {} do if src(blocker)() then return false end end for _, lane in memberLanes do if lanes[lane].mode == "block" and occupant(lane, name) ~= nil then return false end end local queued = false for _, lane in memberLanes do if lanes[lane].mode ~= "queue" or occupant(lane, name) == nil then continue end local queue = queues[lane] or {} local _name_1 = name if not (table.find(queue, _name_1) ~= nil) then local _name_2 = name table.insert(queue, _name_2) end queues[lane] = queue queued = true end if queued then return false end end local closed = {} batch(function() for _, lane in memberLanes do if not force and lanes[lane].mode ~= "displace" then continue end for _1, member in lanes[lane].members do if member ~= name then closeInternal(member, closed) end end end for _, other in def.closes or {} do closeInternal(other, closed) end src(name)(true) end) fireClosed(closed) local _result = def.onOpen if _result ~= nil then _result() end pump() return true end local api = self api.closeAll = function() table.clear(queues) local closed = {} batch(function() for name, def in pairs(rules) do if not def.persistent then closeInternal(name, closed) end end end) fireClosed(closed) end api.reset = function() table.clear(queues) local wentClosed = {} local wentOpen = {} batch(function() for name, def in pairs(rules) do local _result = def.defaults if _result ~= nil then _result = _result.open end local _condition = _result if _condition == nil then _condition = false end local target = _condition if src(name)() == target then continue end src(name)(target) local _exp = (if target then wentOpen else wentClosed) table.insert(_exp, name) end end) fireClosed(wentClosed) for _, name in wentOpen do local _result = rules[name].onOpen if _result ~= nil then _result() end end end api.attachHotkeys = function(parent) return attachHotkeys(rules, { isOpen = function(name) return src(name)() end, open = open, close = close, }, parent) end for name in pairs(rules) do api[name] = { open = function(force) return open(name, force) end, close = function() return close(name) end, toggle = function() if src(name)() then close(name) else open(name) end end, state = function() return src(name)() end, } end end end --[[ * * Forge — a window manager, nothing more. It governs when windows may be open * (exclusivity lanes, parent cascades, blockers, queues, hotkeys); it owns * nothing visual. Each window is a `Vide.source` your components * bind to however they like. * * ```ts * const forge = new Forge({ * windows: { * hud: { defaults: { open: true }, persistent: true }, * shop: { hotkey: Enum.KeyCode.B }, * buy: { parent: "shop" }, * }, * exclusive: { main: ["shop"] }, * }); * * forge.shop.open(); * Visible={forge.shop.state} * ``` ]] -- Keep the constraint a plain Record — a per-key mapped constraint breaks -- editor completions inside the config (verified against tsserver). local ForgeConstructor = ForgeImpl local default = ForgeConstructor return { default = default, }