--!strict
--!nolint LocalUnused
--!nolint LocalShadow

--[[
	Roblox implementation for Fusion's abstract provider layer.
]]

local RunService = game:GetService("RunService")
local HttpService = game:GetService("HttpService")
local External = require("./External")

local RobloxExternal = {}

RobloxExternal.policies = {
	allowWebLinks = RunService:IsStudio()
}

--[[
   Sends an immediate task to the external provider. Throws if none is set.
]]
function RobloxExternal.doTaskImmediate(
	resume: () -> ()
)
   task.spawn(resume)
end

--[[
	Sends a deferred task to the external provider. Throws if none is set.
]]
function RobloxExternal.doTaskDeferred(
	resume: () -> ()
)
	task.defer(resume)
end

--[[
	Errors in a different thread to preserve the flow of execution.
]]
function RobloxExternal.logErrorNonFatal(
	errorString: string
)
	task.spawn(error, errorString, 0)
end

--[[
	Shows a warning message in the output.
]]
RobloxExternal.logWarn = warn

--[[
	Sends an update step to Fusion using the Roblox clock time.
]]
local function performUpdateStep()
	External.performUpdateStep(os.clock())
end

--[[
	Binds Fusion's update step to RunService step events.
]]
local stopSchedulerFunc = nil :: (() -> ())?
function RobloxExternal.startScheduler()
	if stopSchedulerFunc ~= nil then
		return
	end
	if RunService:IsClient() then
		-- In cases where multiple Fusion modules are running simultaneously,
		-- this prevents collisions.
		local id = "FusionUpdateStep_" .. HttpService:GenerateGUID()
		RunService:BindToRenderStep(
			id,
			Enum.RenderPriority.First.Value,
			performUpdateStep
		)
		stopSchedulerFunc = function()
			RunService:UnbindFromRenderStep(id)
		end
	else
		local connection = RunService.Heartbeat:Connect(performUpdateStep)
		stopSchedulerFunc = function()
			connection:Disconnect()
		end
	end
end

--[[
	Unbinds Fusion's update step from RunService step events.
]]
function RobloxExternal.stopScheduler()
	if stopSchedulerFunc ~= nil then
		stopSchedulerFunc()
		stopSchedulerFunc = nil
	end
end

return RobloxExternal


--!strict
--!nolint LocalUnused
--!nolint LocalShadow
local task = nil -- Disable usage of Roblox's task scheduler

--[[
	A specialised state object for tracking single values computed from a
	user-defined computation.

	https://elttob.uk/Fusion/0.3/api-reference/state/types/computed/
]]
local Types = require("../Types")
local External = require("../External")
-- Logging
local parseError = require("../Logging/parseError")
-- Utility
local isSimilar = require("../Utility/isSimilar")
local never = require("../Utility/never")
-- Graph
local depend = require("../Graph/depend")
-- State
local castToState = require("../State/castToState")
local peek = require("../State/peek")
-- Memory
local doCleanup = require("../Memory/doCleanup")
local deriveScope = require("../Memory/deriveScope")
local checkLifetime = require("../Memory/checkLifetime")
local scopePool = require("../Memory/scopePool")
-- Utility
local nicknames = require("../Utility/nicknames")

type Self<T, S> = Types.Computed<T> & {
	_innerScope: Types.Scope<S>?,
	_processor: (Types.Use, Types.Scope<S>) -> T
}

local class = {}
class.type = "State"
class.kind = "Computed"
class.timeliness = "lazy"

local METATABLE = table.freeze {__index = class}

local function Computed<T, S>(
	scope: S & Types.Scope<unknown>,
	processor: (Types.Use, S) -> T,
	destructor: unknown?
): Types.Computed<T>
	local createdAt = os.clock()
	if typeof(scope) == "function" then
		External.logError("scopeMissing", nil, "Computeds", "myScope:Computed(function(use, scope) ... end)")
	elseif destructor ~= nil then
		External.logWarn("destructorRedundant", "Computed")
	end
	local self: Self<T, S> = setmetatable(
		{
			createdAt = createdAt,
			dependencySet = {},
			dependentSet = {},
			lastChange = nil,
			scope = scope,
			validity = "invalid",
			_EXTREMELY_DANGEROUS_usedAsValue = nil,
			_innerScope = nil,
			_processor = processor
		},
		METATABLE
	) :: any
	local destroy = function()
		self.scope = nil
		for dependency in pairs(self.dependencySet) do
			dependency.dependentSet[self] = nil
		end
		if self._innerScope ~= nil then
			doCleanup(self._innerScope)
		end
	end
	self.oldestTask = destroy
	nicknames[self.oldestTask] = "Computed"
	table.insert(scope, destroy)
	return self
end

function class.get<T, S>(
	_self: Self<T, S>
): never
	External.logError("stateGetWasRemoved")
	return never()
end

function class._evaluate<T, S>(
	self: Self<T, S>
): boolean
	if self.scope == nil then
		return false
	end
	local outerScope = self.scope :: S & Types.Scope<unknown>
	local innerScope = deriveScope(outerScope)
	local function use<T>(target: Types.UsedAs<T>): T
		local targetState = castToState(target)
		if targetState ~= nil then
			checkLifetime.bOutlivesA(
				outerScope, self.oldestTask,
				targetState.scope, targetState.oldestTask,
				checkLifetime.formatters.useFunction
			)
			depend(self, targetState)
		end
		return peek(target)
	end
	local ok, newValue = xpcall(self._processor, parseError, use, innerScope)
	local innerScope = scopePool.giveIfEmpty(innerScope)
	if ok then
		local similar = isSimilar(self._EXTREMELY_DANGEROUS_usedAsValue, newValue)
		if self._innerScope ~= nil then
			doCleanup(self._innerScope)
		end
		self._innerScope = innerScope

		self._EXTREMELY_DANGEROUS_usedAsValue = newValue
		return not similar
	else
		local errorObj = (newValue :: any) :: Types.Error
		if innerScope ~= nil then
			doCleanup(innerScope)
		end
		innerScope = nil

		-- this needs to be non-fatal, because otherwise it'd disrupt the
		-- update process
		External.logErrorNonFatal("callbackError", errorObj)
		return false
	end
end

table.freeze(class)
return Computed :: Types.ComputedConstructor


--!strict
--!nolint LocalUnused
--!nolint LocalShadow
local task = nil -- Disable usage of Roblox's task scheduler

--[[
	Breaks down an input table into reactive sub-objects for each pair.
]]
local Types = require("../../Types")
local External = require("../../External")
-- Graph
local depend = require("../../Graph/depend")
-- State
local peek = require("../../State/peek")
local castToState = require("../../State/castToState")
local ForTypes = require("../../State/For/ForTypes")
-- Memory
local doCleanup = require("../../Memory/doCleanup")
local deriveScope = require("../../Memory/deriveScope")
local scopePool = require("../../Memory/scopePool")
-- Utility
local nameOf = require("../../Utility/nameOf")
local nicknames = require("../../Utility/nicknames")

type Self<S, KI, KO, VI, VO> = ForTypes.Disassembly<S, KI, KO, VI, KO> & {
	scope: (S & Types.Scope<unknown>)?,
	_inputTable: Types.UsedAs<{[KI]: VI}>,
	_constructor: (
		Types.Scope<S>,
		initialKey: KI,
		initialValue: VI
	) -> ForTypes.SubObject<S, KI, KO, VI, VO>,
	_subObjects: {[ForTypes.SubObject<S, KI, KO, VI, VO>]: true}
}

local class = {}
class.type = "Graph"
class.kind = "For.Disassembly"
class.timeliness = "lazy"

local METATABLE = table.freeze {__index = class}

local function Disassembly<S, KI, KO, VI, VO>(
	scope: S & Types.Scope<unknown>,
	inputTable: Types.UsedAs<{[KI]: VI}>,
	constructor: (
		Types.Scope<S>,
		initialKey: KI,
		initialValue: VI
	) -> ForTypes.SubObject<S, KI, KO, VI, VO>
): ForTypes.Disassembly<S, KI, KO, VI, KO>
	local createdAt = os.clock()
	local self = setmetatable(
		{
			createdAt = createdAt,
			dependencySet = {},
			dependentSet = {},
			scope = scope,
			validity = "invalid",
			_inputTable = inputTable,
			_constructor = constructor,
			_subObjects = {}
		},
		METATABLE
	) :: any

	local destroy = function()
		self.scope = nil
		for dependency in pairs(self.dependencySet) do
			dependency.dependentSet[self] = nil
		end
		for subObject in self._subObjects do
			if subObject.maybeScope ~= nil then
				doCleanup(subObject.maybeScope)
				subObject.maybeScope = nil
			end
		end
	end
	self.oldestTask = destroy
	nicknames[self.oldestTask] = "For (internal disassembler)"
	table.insert(scope, destroy)

	return self
end

function class.populate<S, KI, KO, VI, VO>(
	self: Self<S, KI, KO, VI, VO>,
	use: Types.Use,
	output: {[KO]: VO}
): ()
	local minArrayIndex = math.huge
	local maxArrayIndex = -math.huge
	local hasHoles = false
	for subObject in self._subObjects do
		local outputKey, outputValue = subObject:useOutputPair(use)
		if outputKey == nil or outputValue == nil then
			hasHoles = true
			continue
		elseif output[outputKey] ~= nil then
			External.logErrorNonFatal("forKeyCollision", nil, tostring(outputKey))
			continue
		end
		output[outputKey] = outputValue
		if typeof(outputKey) == "number" then
			minArrayIndex = math.min(minArrayIndex, outputKey)
			maxArrayIndex = math.max(maxArrayIndex, outputKey)
		end
	end
	-- Be careful of NaN here
	if hasHoles and maxArrayIndex > minArrayIndex then
		local output: {[number]: VO} = output :: any
		local moveToIndex = minArrayIndex
		for moveFromIndex = minArrayIndex, maxArrayIndex do
			local outputValue = output[moveFromIndex]
			if outputValue == nil then
				continue
			end
			-- The ordering is important in case the indices are the same
			output[moveFromIndex] = nil
			output[moveToIndex] = outputValue
			moveToIndex += 1
		end
	end
end

function class._evaluate<S, KI, KO, VI, VO>(
	self: Self<S, KI, KO, VI, VO>
): boolean
	local outerScope = self.scope :: S & Types.Scope<unknown>
	local inputState = castToState(self._inputTable)
	if inputState ~= nil then
		if inputState.scope == nil then
			External.logError(
				"useAfterDestroy",
				nil,
				`The input {nameOf(inputState, "table")}`,
				`the For object that is watching it`
			)
		end
		depend(self, inputState)
	end

	local pendingPairs = {} :: {[KI]: VI}
	for key, value in peek(self._inputTable) do
		pendingPairs[key] = value
	end

	local newSubObjects = {} :: typeof(self._subObjects)

	for subObject in self._subObjects do
		local reused = false
		local oldInputKey = subObject.inputKey
		local oldInputValue = subObject.inputValue
		local newInputKey: KI
		-- Reuse when the keys are identical.
		if not subObject.roamKeys and pendingPairs[oldInputKey] ~= nil then
			reused = true
			newInputKey = oldInputKey
		else -- Try and reuse some other pair instead.
			for pendingKey, pendingValue in pendingPairs do
				reused = true
				newInputKey = pendingKey
				if subObject.roamValues then
					break
				end
				if pendingValue == oldInputValue then
					-- If the values are the same, then no need to update those,
					-- so prefer this choice to any other.
					break
				end
			end
		end
		if reused then
			local newInputValue = pendingPairs[newInputKey]
			newSubObjects[subObject] = true
			if newInputKey ~= oldInputKey then
				subObject.inputKey = newInputKey
				subObject:invalidateInputKey()
			end
			if newInputValue ~= oldInputValue then
				subObject.inputValue = newInputValue
				subObject:invalidateInputValue()
			end
			pendingPairs[newInputKey] = nil
		else -- Too many sub objects for the number of pairs.
			if subObject.maybeScope ~= nil then
				doCleanup(subObject.maybeScope)
				subObject.maybeScope = nil
			end
		end
	end

	-- Generate new objects if needed to cover the remaining pending pairs.
	for pendingKey, pendingValue in pendingPairs do
		local subObject = self._constructor(deriveScope(outerScope), pendingKey, pendingValue)
		if subObject.maybeScope ~= nil then
			subObject.maybeScope = scopePool.giveIfEmpty(subObject.maybeScope)
		end
		newSubObjects[subObject] = true
	end

	self._subObjects = newSubObjects

	return true
end

table.freeze(class)
return Disassembly


--!strict
--!nolint LocalUnused
--!nolint LocalShadow
local task = nil -- Disable usage of Roblox's task scheduler

--[[
	Stores types that are commonly used between For objects.
]]
local Types = require("../../Types")

export type SubObject<S, KI, KO, VI, VO> = {
	-- Not all sub objects need to store a scope, for example if the scope
	-- remains empty, it'll be given back to the scope pool.
	maybeScope: Types.Scope<S>?,
	inputKey: KI,
	inputValue: VI,
	roamKeys: boolean,
	roamValues: boolean,
	invalidateInputKey: (SubObject<S, KI, KO, VI, VO>) -> (),
	invalidateInputValue: (SubObject<S, KI, KO, VI, VO>) -> (),
	useOutputPair: (SubObject<S, KI, KO, VI, VO>, Types.Use) -> (KO?, VO?)
}

export type Disassembly<S, KI, KO, VI, VO> = Types.GraphObject & {
	populate: (Disassembly<S, KI, KO, VI, VO>, Types.Use, output: {[KO]: VO}) -> ()
}

return nil


--!strict
--!nolint LocalUnused
--!nolint LocalShadow
local task = nil -- Disable usage of Roblox's task scheduler

--[[
	The generic implementation for all `For` objects.
]]
local Types = require("../../Types")
local External = require("../../External")
-- Graph
local depend = require("../../Graph/depend")
-- State
local peek = require("../../State/peek")
local castToState = require("../../State/castToState")
local ForTypes = require("../../State/For/ForTypes")
-- Utility
local never = require("../../Utility/never")
local nicknames = require("../../Utility/nicknames")

local Disassembly = require("../../State/For/Disassembly")

type Self<S, KI, KO, VI, VO> = Types.For<KO, VO> & {
	_disassembly: ForTypes.Disassembly<S, KI, KO, VI, VO>
}

local class = {}
class.type = "State"
class.kind = "For"
class.timeliness = "lazy"

local METATABLE = table.freeze {__index = class}

local function For<S, KI, KO, VI, VO>(
	scope: Types.Scope<S>,
	inputTable: Types.UsedAs<{[KI]: VI}>,
	constructor: (
		Types.Scope<S>,
		initialKey: KI,
		initialValue: VI
	) -> ForTypes.SubObject<S, KI, KO, VI, VO>
): Types.For<KO, VO>
	local createdAt = os.clock()
	local self: Self<S, KI, KO, VI, VO> = setmetatable(
		{
			createdAt = createdAt,
			dependencySet = {},
			dependentSet = {},
			scope = scope,
			validity = "invalid",
			_EXTREMELY_DANGEROUS_usedAsValue = {},
			_disassembly = Disassembly(
				scope,
				inputTable,
				constructor
			)
		},
		METATABLE
	) :: any

	local destroy = function()
		self.scope = nil
		for dependency in pairs(self.dependencySet) do
			dependency.dependentSet[self] = nil
		end
	end
	self.oldestTask = destroy
	nicknames[self.oldestTask] = "For"
	table.insert(scope, destroy)

	return self
end

function class.get<S, KI, KO, VI, VO>(
	_self: Self<S, KI, KO, VI, VO>
): never
	External.logError("stateGetWasRemoved")
	return never()
end

function class._evaluate<S, KI, KO, VI, VO>(
	self: Self<S, KI, KO, VI, VO>
): boolean
	if self.scope == nil then
		return false
	end
	local outerScope = self.scope :: S & Types.Scope<unknown>

	depend(self, self._disassembly)
	table.clear(self._EXTREMELY_DANGEROUS_usedAsValue)
	self._disassembly:populate(
		function<T>(
			maybeState: Types.UsedAs<T>
		): T
			local state = castToState(maybeState)
			if state ~= nil then
				depend(self, state)
			end
			return peek(maybeState)
		end,
		self._EXTREMELY_DANGEROUS_usedAsValue
	)

	return true
end

table.freeze(class)
return For


--!strict
--!nolint LocalUnused
--!nolint LocalShadow
local task = nil -- Disable usage of Roblox's task scheduler

--[[
	Constructs and returns a new For state object which processes keys and
	preserves values.

	https://elttob.uk/Fusion/0.3/api-reference/state/members/forkeys/

	TODO: the sub objects constructed here can be more efficiently implemented
	as a dedicated state object.
]]
local Types = require("../Types")
local External = require("../External")
-- Memory
local doCleanup = require("../Memory/doCleanup")
-- State
local For = require("../State/For")
local Value = require("../State/Value")
local Computed = require("../State/Computed")
local ForTypes = require("../State/For/ForTypes")
-- Logging
local parseError = require("../Logging/parseError")

local SUB_OBJECT_META = {
	__index = {
		roamKeys = false,
		roamValues = true,
		invalidateInputKey = function(self): ()
			self._inputKeyState:set(self.inputKey)
		end,
		invalidateInputValue = function(self): ()
			-- do nothing
		end,
		useOutputPair = function(self, use)
			return use(self._outputKeyState), self.inputValue
		end
	}
}

local function SubObject<KI, KO, V, S>(
	scope: Types.Scope<S>,
	initialKey: KI,
	initialValue: V,
	processor: (Types.Use, Types.Scope<S>, KI) -> KO
): ForTypes.SubObject<S, KI, KO, V, V>
	local self = {}
	self.maybeScope = scope
	self.inputKey = initialKey
	self.inputValue = initialValue
	self._inputKeyState = Value(scope, initialKey)
	self._processor = processor
	self._outputKeyState = Computed(scope, function(use, scope): KO?
		local inputKey = use(self._inputKeyState)
		local ok, outputKey = xpcall(self._processor, parseError, use, scope, inputKey)
		if ok then
			return outputKey
		else
			local error: Types.Error = outputKey :: any
			error.context = `while processing key {tostring(inputKey)}`
			External.logErrorNonFatal("callbackError", error)
			doCleanup(scope)
			table.clear(scope)
			return nil
		end
	end)
	return setmetatable(self, SUB_OBJECT_META) :: any
end

local function ForKeys<KI, KO, V, S>(
	scope: Types.Scope<S>,
	inputTable: Types.UsedAs<{[KI]: V}>,
	processor: (Types.Use, Types.Scope<S>, KI) -> KO,
	destructor: unknown?
): Types.For<KO, V>
	if typeof(inputTable) == "function" then
		External.logError("scopeMissing", nil, "ForKeys", "myScope:ForKeys(inputTable, function(scope, use, key) ... end)")
	elseif destructor ~= nil then
		External.logWarn("destructorRedundant", "ForKeys")
	end
	return For(
		scope,
		inputTable,
		function(scope, initialKey, initialValue)
			return SubObject(scope, initialKey, initialValue, processor)
		end
	)
end

return ForKeys :: Types.ForKeysConstructor


--!strict
--!nolint LocalUnused
--!nolint LocalShadow
local task = nil -- Disable usage of Roblox's task scheduler

--[[
	Constructs and returns a new For state object which processes keys and
	values in pairs.

	https://elttob.uk/Fusion/0.3/api-reference/state/members/forpairs/

	TODO: the sub objects constructed here can be more efficiently implemented
	as a dedicated state object.
]]
local Types = require("../Types")
local External = require("../External")
-- State
local For = require("../State/For")
local Value = require("../State/Value")
local Computed = require("../State/Computed")
local ForTypes = require("../State/For/ForTypes")
-- Logging
local parseError = require("../Logging/parseError")
-- Memory
local doCleanup = require("../Memory/doCleanup")

local SUB_OBJECT_META = {
	__index = {
		roamKeys = false,
		roamValues = false,
		invalidateInputKey = function(self): ()
			self._inputKeyState:set(self.inputKey)
		end,
		invalidateInputValue = function(self): ()
			self._inputValueState:set(self.inputValue)
		end,
		useOutputPair = function(self, use)
			local pair = use(self._outputPairState)
			return pair.key, pair.value
		end
	}
}

local function SubObject<KI, KO, VI, VO, S>(
	scope: Types.Scope<S>,
	initialKey: KI,
	initialValue: VI,
	processor: (Types.Use, Types.Scope<S>, KI, VI) -> (KO, VO)
): ForTypes.SubObject<S, KI, KO, VI, VO>
	local self = {}
	self.maybeScope = scope
	self.inputKey = initialKey
	self.inputValue = initialValue
	self._inputKeyState = Value(scope, initialKey)
	self._inputValueState = Value(scope, initialValue)
	self._processor = processor
	self._outputPairState = Computed(scope, function(use, scope): {key: KO?, value: VO?}
		local inputKey = use(self._inputKeyState)
		local inputValue = use(self._inputValueState)
		local ok, outputKey, outputValue = xpcall(self._processor, parseError, use, scope, inputKey, inputValue)
		if ok then
			return {key = outputKey, value = outputValue}
		else
			local error: Types.Error = outputKey :: any
			error.context = `while processing key {tostring(inputValue)} and value {tostring(inputValue)}`
			External.logErrorNonFatal("callbackError", error)
			doCleanup(scope)
			table.clear(scope)
			return {key = nil, value = nil}
		end
	end)
	return setmetatable(self, SUB_OBJECT_META) :: any
end

local function ForPairs<KI, KO, VI, VO, S>(
	scope: Types.Scope<S>,
	inputTable: Types.UsedAs<{[KI]: VI}>,
	processor: (Types.Use, Types.Scope<S>, KI, VI) -> (KO, VO),
	destructor: unknown?
): Types.For<KO, VO>
	if typeof(inputTable) == "function" then
		External.logError("scopeMissing", nil, "ForPairs", "myScope:ForPairs(inputTable, function(scope, use, key, value) ... end)")
	elseif destructor ~= nil then
		External.logWarn("destructorRedundant", "ForPairs")
	end
	return For(
		scope,
		inputTable,
		function(scope, initialKey, initialValue)
			return SubObject(scope, initialKey, initialValue, processor)
		end
	)
end

return ForPairs :: Types.ForPairsConstructor


--!strict
--!nolint LocalUnused
--!nolint LocalShadow
local task = nil -- Disable usage of Roblox's task scheduler

--[[
	Constructs and returns a new For state object which processes values and
	preserves keys.

	https://elttob.uk/Fusion/0.3/api-reference/state/members/forvalues/

	TODO: the sub objects constructed here can be more efficiently implemented
	as a dedicated state object.
]]
local Types = require("../Types")
local External = require("../External")
-- State
local For = require("../State/For")
local Value = require("../State/Value")
local Computed = require("../State/Computed")
local ForTypes = require("../State/For/ForTypes")
-- Logging
local parseError = require("../Logging/parseError")
-- Memory
local doCleanup = require("../Memory/doCleanup")

local SUB_OBJECT_META = {
	__index = {
		roamKeys = true,
		roamValues = false,
		invalidateInputKey = function(self): ()
			-- do nothing
		end,
		invalidateInputValue = function(self): ()
			self._inputValueState:set(self.inputValue)
		end,
		useOutputPair = function(self, use)
			return self.inputKey, use(self._outputValueState)
		end
	}
}

local function SubObject<K, VI, VO, S>(
	scope: Types.Scope<S>,
	initialKey: K,
	initialValue: VI,
	processor: (Types.Use, Types.Scope<S>, VI) -> VO
): ForTypes.SubObject<S, K, K, VI, VO>
	local self = {}
	self.maybeScope = scope
	self.inputKey = initialKey
	self.inputValue = initialValue
	self._inputValueState = Value(scope, initialValue)
	self._processor = processor
	self._outputValueState = Computed(scope, function(use, scope): VO?
		local inputValue = use(self._inputValueState)
		local ok, outputValue = xpcall(self._processor, parseError, use, scope, inputValue)
		if ok then
			return outputValue
		else
			local error: Types.Error = outputValue :: any
			error.context = `while processing value {tostring(inputValue)}`
			External.logErrorNonFatal("callbackError", error)
			doCleanup(scope)
			table.clear(scope)
			return nil
		end
	end)
	return setmetatable(self, SUB_OBJECT_META) :: any
end

local function ForValues<K, VI, VO, S>(
	scope: Types.Scope<S>,
	inputTable: Types.UsedAs<{[K]: VI}>,
	processor: (Types.Use, Types.Scope<S>, VI) -> VO,
	destructor: unknown?
): Types.For<K, VO>
	if typeof(inputTable) == "function" then
		External.logError("scopeMissing", nil, "ForValues", "myScope:ForValues(inputTable, function(scope, use, value) ... end)")
	elseif destructor ~= nil then
		External.logWarn("destructorRedundant", "ForValues")
	end
	return For(
		scope,
		inputTable,
		function(scope, initialKey, initialValue)
			return SubObject(scope, initialKey, initialValue, processor)
		end
	)
end

return ForValues :: Types.ForValuesConstructor


--!strict
--!nolint LocalUnused
--!nolint LocalShadow
local task = nil -- Disable usage of Roblox's task scheduler

--[[
	A state object which allows regular Luau code to control its value.

	https://elttob.uk/Fusion/0.3/api-reference/state/types/value/
]]
local Types = require("../Types")
local External = require("../External")
-- Graph
local change = require("../Graph/change")
-- Utility
local isSimilar = require("../Utility/isSimilar")
local never = require("../Utility/never")
local nicknames = require("../Utility/nicknames")

type Self<T, S> = Types.Value<T, S>

local class = {}
class.type = "State"
class.kind = "Value"
class.timeliness = "lazy"
class.dependencySet = table.freeze {}

local METATABLE = table.freeze {__index = class}

local function Value<T>(
	scope: Types.Scope<unknown>,
	initialValue: T
): Types.Value<T, any>
	local createdAt = os.clock()
	if initialValue == nil and (typeof(scope) ~= "table" or (scope[1] == nil and next(scope) ~= nil)) then
		External.logError("scopeMissing", nil, "Value", "myScope:Value(initialValue)")
	end
	local self: Self<T, any> = setmetatable(
		{
			createdAt = createdAt,
			dependentSet = {},
			lastChange = os.clock(),
			scope = scope,
			validity = "valid",
			_EXTREMELY_DANGEROUS_usedAsValue = initialValue
		},
		METATABLE
	) :: any
	local destroy = function()
		self.scope = nil
	end
	self.oldestTask = destroy
	nicknames[self.oldestTask] = "Value"
	table.insert(scope, destroy)
	return self
end

function class:get<T, S>(
	_self: Self<T, S>
): never
	External.logError("stateGetWasRemoved")
	return never()
end

function class.set<T, S>(
	self: Self<T, S>,
	newValue: S
): S
	local oldValue = self._EXTREMELY_DANGEROUS_usedAsValue
	if not isSimilar(oldValue, newValue) then
		self._EXTREMELY_DANGEROUS_usedAsValue = newValue :: any
		change(self)
	end
	return newValue
end

function class._evaluate<T, S>(
	_self: Self<T, S>
): boolean
	-- The similarity test is done in advance when the value is set, so this
	-- should be fine.
	return true
end

table.freeze(class)
return Value :: Types.ValueConstructor


--!strict
--!nolint LocalUnused
--!nolint LocalShadow
local task = nil -- Disable usage of Roblox's task scheduler

--[[
	Returns the input *only* if it is a state object.
]]
local Types = require("../Types")

local function castToState<T>(
	target: Types.UsedAs<T>
): Types.StateObject<T>?
	if
		typeof(target) == "table" and
		target.type == "State"
	then
		return target
	else
		return nil
	end
end

return castToState


--!strict
--!nolint LocalUnused
--!nolint LocalShadow
local task = nil -- Disable usage of Roblox's task scheduler

--[[
	Extracts a value of type T from its input.

	https://elttob.uk/Fusion/0.3/api-reference/state/members/peek/
]]
local Types = require("../Types")
-- State
local castToState = require("../State/castToState")
-- Graph
local evaluate = require("../Graph/evaluate")

local function peek<T>(
	target: Types.UsedAs<T>
): T
	local targetState = castToState(target)
	if targetState ~= nil then
		evaluate(targetState, false)
		return targetState._EXTREMELY_DANGEROUS_usedAsValue :: T
	else
		return target :: T
	end
end

return peek


--!strict
--!nolint LocalUnused
--!nolint LocalShadow
local task = nil -- Disable usage of Roblox's task scheduler

--[[
	Stores common public-facing type information for Fusion APIs.
]]

export type Error = {
	type: "Error",
	raw: string,
	message: string,
	trace: string,
	context: string?
}

-- Types that can be expressed as vectors of numbers, and so can be animated.
export type Animatable =
	number |
	CFrame |
	Color3 |
	ColorSequenceKeypoint |
	DateTime |
	NumberRange |
	NumberSequenceKeypoint |
	PhysicalProperties |
	Ray |
	Rect |
	Region3 |
	Region3int16 |
	UDim |
	UDim2 |
	Vector2 |
	Vector2int16 |
	Vector3 |
	Vector3int16

-- A task which can be accepted for cleanup.
export type Task =
	Instance |
	RBXScriptConnection |
	() -> () |
	{destroy: (unknown) -> ()} |
	{Destroy: (unknown) -> ()} |
	{Task}

-- A scope of tasks to clean up.
export type Scope<Constructors = any> = {Task} & Constructors

-- An object which uses a scope to dictate how long it lives.
export type ScopedObject = {
	scope: Scope<unknown>?,
	oldestTask: unknown
}

-- Script-readable version information.
export type Version = {
	major: number,
	minor: number,
	isRelease: boolean
}

-- An object which stores a value scoped in time.
export type Contextual<T> = {
	type: "Contextual",
	now: (Contextual<T>) -> T,
	is: (Contextual<T>, T) -> ContextualIsMethods
}

type ContextualIsMethods = {
	during: <R, A...>(ContextualIsMethods, (A...) -> R, A...) -> R
}

-- A graph object which can have dependencies and dependencies.
export type GraphObject = ScopedObject & {
	createdAt: number,
	dependencySet: {[GraphObject]: unknown},
	dependentSet: {[GraphObject]: unknown},
	lastChange: number?,
	timeliness: "lazy" | "eager",
	validity: "valid" | "invalid" | "busy",
	_evaluate: (GraphObject) -> boolean
}

-- An object which stores a piece of reactive state.
export type StateObject<T> = GraphObject & {
	type: "State",
	kind: string,
	_EXTREMELY_DANGEROUS_usedAsValue: T
}

-- Passing values of this type to `Use` returns `T`.
export type UsedAs<T> = StateObject<T> | T

-- Function signature for use callbacks.
export type Use = <T>(target: UsedAs<T>) -> T

-- A state object whose value can be set at any time by the user.
export type Value<T, S = T> = StateObject<T> & {
	kind: "State",
	timeliness: "lazy",
 	set: (Value<T, S>, newValue: S, force: boolean?) -> S,
	____phantom_setType: (never) -> S -- phantom data so this contains S
}
export type ValueConstructor = <T>(
	scope: Scope<unknown>,
	initialValue: T
) -> Value<T, any>

-- A state object whose value is derived from other objects using a callback.
export type Computed<T> = StateObject<T> & {
	kind: "Computed",
	timeliness: "lazy"
}
export type ComputedConstructor = <T, S>(
	scope: S & Scope<unknown>,
	callback: (Use, S) -> T
) -> Computed<T>

-- A state object which maps over keys and/or values in another table.
export type For<KO, VO> = StateObject<{[KO]: VO}>  & {
	kind: "For"
}
export type ForPairsConstructor =  <KI, KO, VI, VO, S>(
	scope: S & Scope<unknown>,
	inputTable: UsedAs<{[KI]: VI}>,
	processor: (Use, S, key: KI, value: VI) -> (KO, VO)
) -> For<KO, VO>
export type ForKeysConstructor =  <KI, KO, V, S>(
	scope: S & Scope<unknown>,
	inputTable: UsedAs<{[KI]: V}>,
	processor: (Use, S, key: KI) -> KO
) -> For<KO, V>
export type ForValuesConstructor =  <K, VI, VO, S>(
	scope: S & Scope<unknown>,
	inputTable: UsedAs<{[K]: VI}>,
	processor: (Use, S, value: VI) -> VO
) -> For<K, VO>

-- An object which can listen for updates on another state object.
export type Observer = GraphObject & {
	type: "Observer",
	timeliness: "eager",
	onChange: (Observer, callback: () -> ()) -> (() -> ()),
	onBind: (Observer, callback: () -> ()) -> (() -> ())
}
export type ObserverConstructor = (
	scope: Scope<unknown>,
	watching: unknown
) -> Observer

-- A state object which follows another state object using tweens.
export type Tween<T> = StateObject<T> & {
	kind: "Tween"
}
export type TweenConstructor = <T>(
	scope: Scope<unknown>,
	goalState: UsedAs<T>,
	tweenInfo: UsedAs<TweenInfo>?
) -> Tween<T>

-- A state object which follows another state object using spring simulation.
export type Spring<T> = StateObject<T>  & {
	kind: "Spring",
	setPosition: (Spring<T>, newPosition: T) -> (),
	setVelocity: (Spring<T>, newVelocity: T) -> (),
	addVelocity: (Spring<T>, deltaVelocity: T) -> ()
}
export type SpringConstructor = <T>(
	scope: Scope<unknown>,
	goalState: UsedAs<T>,
	speed: UsedAs<number>?,
	damping: UsedAs<number>?
) -> Spring<T>

-- Denotes children instances in an instance or component's property table.
export type SpecialKey = {
	type: "SpecialKey",
	kind: string,
	stage: "self" | "descendants" | "ancestor" | "observer",
	apply: (
		self: SpecialKey,
		scope: Scope<unknown>,
		value: unknown,
		applyTo: Instance
	) -> ()
}

-- A collection of instances that may be parented to another instance.
export type Child = Instance | StateObject<Child> | {[unknown]: Child}

-- A table that defines an instance's properties, handlers and children.
export type PropertyTable = {[string | SpecialKey]: unknown}

export type NewConstructor = (
	scope: Scope<unknown>,
	className: string
) -> (propertyTable: PropertyTable) -> Instance

export type HydrateConstructor = (
	scope: Scope<unknown>,
	target: Instance
) -> (propertyTable: PropertyTable) -> Instance

-- Is there a sane way to write out this type?
-- ... I sure hope so.

export type DeriveScopeConstructor = (<S>(Scope<S>) -> Scope<S>)
	& (<S, A>(Scope<S>, A & {}) -> Scope<S & A>)
	& (<S, A, B>(Scope<S>, A & {}, B & {}) -> Scope<S & A & B>)
	& (<S, A, B, C>(Scope<S>, A & {}, B & {}, C & {}) -> Scope<S & A & B & C>)
	& (<S, A, B, C, D>(Scope<S>, A & {}, B & {}, C & {}, D & {}) -> Scope<S & A & B & C & D>)
	& (<S, A, B, C, D, E>(Scope<S>, A & {}, B & {}, C & {}, D & {}, E & {}) -> Scope<S & A & B & C & D & E>)
	& (<S, A, B, C, D, E, F>(Scope<S>, A & {}, B & {}, C & {}, D & {}, E & {}, F & {}) -> Scope<S & A & B & C & D & E & F>)
	& (<S, A, B, C, D, E, F, G>(Scope<S>, A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}) -> Scope<S & A & B & C & D & E & F & G>)
	& (<S, A, B, C, D, E, F, G, H>(Scope<S>, A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}, H & {}) -> Scope<S & A & B & C & D & E & F & G & H>)
	& (<S, A, B, C, D, E, F, G, H, I>(Scope<S>, A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}, H & {}, I & {}) -> Scope<S & A & B & C & D & E & F & G & H & I>)
	& (<S, A, B, C, D, E, F, G, H, I, J>(Scope<S>, A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}, H & {}, I & {}, J & {}) -> Scope<S & A & B & C & D & E & F & G & H & I & J>)
	& (<S, A, B, C, D, E, F, G, H, I, J, K>(Scope<S>, A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}, H & {}, I & {}, J & {}, K & {}) -> Scope<S & A & B & C & D & E & F & G & H & I & J & K>)
	& (<S, A, B, C, D, E, F, G, H, I, J, K, L>(Scope<S>, A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}, H & {}, I & {}, J & {}, K & {}, L & {}) -> Scope<S & A & B & C & D & E & F & G & H & I & J & K & L>)

export type ScopedConstructor = (() -> Scope<{}>)
	& (<A>(A & {}) -> Scope<A>)
	& (<A, B>(A & {}, B & {}) -> Scope<A & B>)
	& (<A, B, C>(A & {}, B & {}, C & {}) -> Scope<A & B & C>)
	& (<A, B, C, D>(A & {}, B & {}, C & {}, D & {}) -> Scope<A & B & C & D>)
	& (<A, B, C, D, E>(A & {}, B & {}, C & {}, D & {}, E & {}) -> Scope<A & B & C & D & E>)
	& (<A, B, C, D, E, F>(A & {}, B & {}, C & {}, D & {}, E & {}, F & {}) -> Scope<A & B & C & D & E & F>)
	& (<A, B, C, D, E, F, G>(A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}) -> Scope<A & B & C & D & E & F & G>)
	& (<A, B, C, D, E, F, G, H>(A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}, H & {}) -> Scope<A & B & C & D & E & F & G & H>)
	& (<A, B, C, D, E, F, G, H, I>(A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}, H & {}, I & {}) -> Scope<A & B & C & D & E & F & G & H & I>)
	& (<A, B, C, D, E, F, G, H, I, J>(A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}, H & {}, I & {}, J & {}) -> Scope<A & B & C & D & E & F & G & H & I & J>)
	& (<A, B, C, D, E, F, G, H, I, J, K>(A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}, H & {}, I & {}, J & {}, K & {}) -> Scope<A & B & C & D & E & F & G & H & I & J & K>)
	& (<A, B, C, D, E, F, G, H, I, J, K, L>(A & {}, B & {}, C & {}, D & {}, E & {}, F & {}, G & {}, H & {}, I & {}, J & {}, K & {}, L & {}) -> Scope<A & B & C & D & E & F & G & H & I & J & K & L>)

export type ContextualConstructor = <T>(defaultValue: T) -> Contextual<T>

export type Safe = <Success, Fail>(
	callbacks: {
		try: () -> Success,
		fallback: (err: unknown) -> Fail
	}
) -> Success | Fail

export type Fusion = {
	version: Version,
	Contextual: ContextualConstructor,
	Safe: Safe,

	doCleanup: (Task) -> (),
	scoped: ScopedConstructor,
	deriveScope: DeriveScopeConstructor,
	innerScope: DeriveScopeConstructor,

	peek: Use,
	Value: ValueConstructor,
	Computed: ComputedConstructor,
	ForPairs: ForPairsConstructor,
	ForKeys: ForKeysConstructor,
	ForValues: ForValuesConstructor,
	Observer: ObserverConstructor,

	Tween: TweenConstructor,
	Spring: SpringConstructor,

	New: NewConstructor,
	Hydrate: HydrateConstructor,

	Child: ({Child}) -> Child,
	Children: SpecialKey,
	Out: (propertyName: string) -> SpecialKey,
	OnEvent: (eventName: string) -> SpecialKey,
	OnChange: (propertyName: string) -> SpecialKey,
	Attribute: (attributeName: string) -> SpecialKey,
	AttributeChange: (attributeName: string) -> SpecialKey,
	AttributeOut: (attributeName: string) -> SpecialKey,
}

export type ExternalProvider = {
	policies: {
		allowWebLinks: boolean
	},

	logErrorNonFatal: (
		errorString: string
	) -> (),
	logWarn: (
		errorString: string
	) -> (),

	doTaskImmediate: (
		resume: () -> ()
	) -> (),
	doTaskDeferred: (
		resume: () -> ()
	) -> (),
	startScheduler: () -> (),
	stopScheduler: () -> ()
}

export type ExternalDebugger = {
	startDebugging: () -> (),
	stopDebugging: () -> (),

	trackScope: (
		scope: Scope<unknown>
	) -> (),
	untrackScope: (
		scope: Scope<unknown>
	) -> ()
}

return nil


--!strict
--!nolint LocalUnused
--!nolint LocalShadow
local task = nil -- Disable usage of Roblox's task scheduler

--[[
    Time-based contextual values, to allow for transparently passing values down
	the call stack.
]]
local Types = require("../Types")
local External = require("../External")
-- Logging
local parseError = require("../Logging/parseError")

export type Self<T> = Types.Contextual<T> & {
	_valuesNow: {[thread]: {value: T}},
	_defaultValue: T
}

local class = {}
class.type = "Contextual"

local METATABLE = table.freeze {__index = class}
local WEAK_KEYS_METATABLE = table.freeze {__mode = "k"}

local function Contextual<T>(
	defaultValue: T
): Types.Contextual<T>
	local self: Self<T> = setmetatable(
		{
			-- if we held strong references to threads here, then if a thread was
			-- killed before this contextual had a chance to finish executing its
			-- callback, it would be held strongly in this table forever
			_valuesNow = setmetatable({}, WEAK_KEYS_METATABLE),
			_defaultValue = defaultValue
		},
		METATABLE
	) :: any

	return self
end

--[[
	Returns the current value of this contextual.
]]
function class.now<T>(
	self: Self<T>
): T
	local thread = coroutine.running()
	local value = self._valuesNow[thread]
	if typeof(value) ~= "table" then
		return self._defaultValue
	else
		return value.value
	end
end

--[[
	Temporarily assigns a value to this contextual.
]]
function class.is<T>(
	self: Self<T>,
	newValue: T
)
	local methods = {}

	function methods.during<T, A...>(
		_: any, -- during is called with colon syntax but we don't care
		callback: (A...) -> T,
		...: A...
	): T
		local thread = coroutine.running()
		local prevValue = self._valuesNow[thread]
		-- Storing the value in this format allows us to distinguish storing
		-- `nil` from not calling `:during()` at all.
		self._valuesNow[thread] = { value = newValue }
		local ok, value = xpcall(callback, parseError, ...)
		self._valuesNow[thread] = prevValue
		if not ok then
			External.logError("callbackError", value :: any)
		end
		return value
	end

	return methods
end

table.freeze(class)
return Contextual


--!strict
--!nolint LocalUnused
--!nolint LocalShadow
local task = nil -- Disable usage of Roblox's task scheduler

--[[
    A variant of xpcall() designed for inline usage, letting you define fallback
	values based on caught errors.
]]

local function Safe<Success, Fail>(
	callbacks: {
		try: () -> Success,
		fallback: (err: unknown) -> Fail
	}
): Success | Fail
	local _, value = xpcall(callbacks.try, callbacks.fallback)
	return value
end

return Safe


--!strict
--!nolint LocalUnused
--!nolint LocalShadow
local task = nil -- Disable usage of Roblox's task scheduler

--[[
	Attempts to merge a variadic number of tables together.
]]
local External = require("../External")

local function merge(
	overwrite: boolean,
	into: {[unknown]: unknown},
	...: {[unknown]: unknown}
): {[unknown]: unknown}
	local fromTables = {...}
	if #fromTables < 1 then
		return into
	else
		for _, fromTable in fromTables do
			for key, value in fromTable do
				if into[key] == nil then
					into[key] = value
				elseif not overwrite then
					External.logError("mergeConflict", nil, tostring(key))
				end
			end
		end
		return into
	end
end

return merge


--!strict
--!nolint LocalUnused
--!nolint LocalShadow
local task = nil -- Disable usage of Roblox's task scheduler

--[[
	Returns the most specific custom name for the given object.
]]
-- Utility
local nicknames = require("../Utility/nicknames")

local function nameOf(
	x: unknown,
	defaultName: string
): string
	local nickname = nicknames[x]
	if typeof(nickname) == "string" then
		return nickname
	end
	if typeof(x) == "table" then
		local x = x :: {[any]: any}
		if typeof(x.name) == "string" then
			return x.name
		elseif typeof(x.kind) == "string" then
			return x.kind
		elseif typeof(x.type) == "string" then
			return x.type
		end
	end
	return defaultName
end

return nameOf


--!strict
--!nolint LocalUnused
--!nolint LocalShadow
local task = nil -- Disable usage of Roblox's task scheduler
--[[
	The entry point for the Fusion library.
]]

local Types = require("@self/Types")
local External = require("@self/External")

type Fusion = Types.Fusion

export type Animatable = Types.Animatable
export type UsedAs<T> = Types.UsedAs<T>
export type Child = Types.Child
export type Computed<T> = Types.Computed<T>
export type Contextual<T> = Types.Contextual<T>
export type GraphObject = Types.GraphObject
export type For<KO, VO> = Types.For<KO, VO>
export type Observer = Types.Observer
export type PropertyTable = Types.PropertyTable
export type Scope<Constructors = Fusion> = Types.Scope<Constructors>
export type ScopedObject = Types.ScopedObject
export type SpecialKey = Types.SpecialKey
export type Spring<T> = Types.Spring<T>
export type StateObject<T> = Types.StateObject<T>
export type Task = Types.Task
export type Tween<T> = Types.Tween<T>
export type Use = Types.Use
export type Value<T, S = T> = Types.Value<T, S>
export type Version = Types.Version

-- Down the line, this will be conditional based on whether Fusion is being
-- compiled for Roblox.
do
	local RobloxExternal = require("@self/RobloxExternal")
	External.setExternalProvider(RobloxExternal)
end

local Fusion: Fusion = table.freeze {
	-- General
	version = {major = 0, minor = 3, isRelease = true},
	Contextual = require("@self/Utility/Contextual"),
	Safe = require("@self/Utility/Safe"),

	-- Memory
	cleanup = require("@self/Memory/legacyCleanup"),
	deriveScope = require("@self/Memory/deriveScope"),
	doCleanup = require("@self/Memory/doCleanup"),
	innerScope = require("@self/Memory/innerScope"),
	scoped = require("@self/Memory/scoped"),

	-- Graph
	Observer = require("@self/Graph/Observer"),

	-- State
	Computed = require("@self/State/Computed"),
	ForKeys = require("@self/State/ForKeys") :: Types.ForKeysConstructor,
	ForPairs = require("@self/State/ForPairs") :: Types.ForPairsConstructor,
	ForValues = require("@self/State/ForValues") :: Types.ForValuesConstructor,
	peek = require("@self/State/peek"),
	Value = require("@self/State/Value"),

	-- Roblox API
	Attribute = require("@self/Instances/Attribute"),
	AttributeChange = require("@self/Instances/AttributeChange"),
	AttributeOut = require("@self/Instances/AttributeOut"),
	Child = require("@self/Instances/Child"),
	Children = require("@self/Instances/Children"),
	Hydrate = require("@self/Instances/Hydrate"),
	New = require("@self/Instances/New"),
	OnChange = require("@self/Instances/OnChange"),
	OnEvent = require("@self/Instances/OnEvent"),
	Out = require("@self/Instances/Out"),

	-- Animation
	Tween = require("@self/Animation/Tween"),
	Spring = require("@self/Animation/Spring"),
} :: Fusion

return Fusion


--!nolint
--!nocheck
--!optimize 2

--[[
    @author biggaboy212
    @name Cascade
    @description A Luau UI library based on macOS Sequoia.
    @license MIT License

    @buildDate __COMPOSER.Insert(__COMPOSER.genDate)
    @buildCfg __COMPOSER.Insert(__COMPOSER.cfg)
    @buildVers __COMPOSER.Insert(__COMPOSER.vers)

    This file was automatically generated with darklua, it is not intended for manual editing.
--]]

__COMPOSER.Insert(__COMPOSER.build)


local types = require("@types")

return function(self, properties: types.ButtonProperties): types.Button
	--// Imports
	local creator = require("@modules/creator")
	local binder = require("@modules/binder")
	local services = require("@modules/services")

	--// References
	local create = creator.Create

	local tweenService = services.TweenService

	--// Variables
	local parent = self.__container or self.__instance or self
	local theme = self.Theme.Controls.Button
	local structures = {}

	--// UI
	properties = properties or {}
	properties.State = properties.State or "Primary"
	properties.Label = properties.Label or "Label"

	structures.Body = binder.Apply(
		properties,
		create("TextButton")({
			Name = "Button",
			AutoButtonColor = false,
			AutomaticSize = Enum.AutomaticSize.XY,
			BackgroundColor3 = Color3.fromRGB(255, 255, 255),
			BorderColor3 = Color3.fromRGB(0, 0, 0),
			BorderSizePixel = 0,
			Text = "",
			Parent = parent,

			create("UICorner")({
				Name = "UICorner",
				CornerRadius = UDim.new(0, 5),
			}),

			create("Folder")({
				Name = "ShadowLayers",

				create("Frame")({
					Name = "Layer1",
					BackgroundColor3 = Color3.fromRGB(255, 255, 255),
					BackgroundTransparency = 1,
					BorderColor3 = Color3.fromRGB(0, 0, 0),
					BorderSizePixel = 0,
					Size = UDim2.fromScale(1, 1),
					ZIndex = 0,

					create("UICorner")({
						Name = "UICorner",
						CornerRadius = UDim.new(0, 5),
					}),

					create("UIStroke")({
						Name = "UIStroke",
						ApplyStrokeMode = Enum.ApplyStrokeMode.Border,
						Transparency = 0.95,

						__dynamicKeys = {
							Color = theme.Shadow,
						},
					}),
				}),

				create("Frame")({
					Name = "Layer2",
					BackgroundColor3 = Color3.fromRGB(255, 255, 255),
					BackgroundTransparency = 1,
					BorderColor3 = Color3.fromRGB(0, 0, 0),
					BorderSizePixel = 0,
					Size = UDim2.fromScale(1, 1),
					ZIndex = -1,

					create("UICorner")({
						Name = "UICorner",
						CornerRadius = UDim.new(0, 5),
					}),

					create("UIStroke")({
						Name = "UIStroke",
						ApplyStrokeMode = Enum.ApplyStrokeMode.Border,
						Thickness = 2,
						Transparency = 0.98,

						__dynamicKeys = {
							Color = theme.Shadow,
						},
					}),
				}),
			}),

			create("Folder")({
				Name = "PressOverlay",

				create("Frame")({
					Name = "Overlay",
					BackgroundColor3 = Color3.fromRGB(0, 0, 0),
					BackgroundTransparency = 1,
					BorderSizePixel = 0,
					Size = UDim2.fromScale(1, 1),
					ZIndex = 0,

					create("UICorner")({
						Name = "UICorner",
						CornerRadius = UDim.new(0, 5),
					}),
				}),
			}),
		})
	) :: TextButton

	--// Initialize
	structures.PressOverlay = structures.Body:FindFirstChild("PressOverlay"):FindFirstChild("Overlay")
	structures.Shadows = structures.Body:FindFirstChild("ShadowLayers")
	structures.Shadow1 = structures.Shadows:FindFirstChild("Layer1"):FindFirstChild("UIStroke")
	structures.Shadow2 = structures.Shadows:FindFirstChild("Layer2"):FindFirstChild("UIStroke")

	local labelContext = {
		TextColor3 = function()
			local state = properties.State

			return state == "Primary" and self.Theme.Text.SelectionPrimary[1].Value
				or state == "Secondary" and self.Theme.Text.Primary[1].Value
				or state == "Destructive" and self.Theme.Accents.Red[1].Value
		end,
		TextTransparency = function()
			local state = properties.State

			return state == "Primary" and self.Theme.Text.SelectionPrimary[2].Value
				or state == "Secondary" and self.Theme.Text.Primary[2].Value
				or state == "Destructive" and self.Theme.Accents.Red[2].Value
		end,
	}
	local fillContext = {
		Color = function()
			local state = properties.State

			return state == "Primary" and theme.FillPrimary.Value
				or (state == "Secondary" or state == "Destructive") and theme.FillSecondary.Value
		end,
	}

	structures.Label = create("TextLabel")({
		Size = UDim2.fromScale(1, 1),
		Name = "Label",
		AutomaticSize = Enum.AutomaticSize.XY,
		BackgroundColor3 = Color3.fromRGB(255, 255, 255),
		BackgroundTransparency = 1,
		BorderColor3 = Color3.fromRGB(0, 0, 0),
		BorderSizePixel = 0,
		FontFace = Font.new("rbxassetid://12187365364"),
		RichText = true,
		TextSize = 14,
		TextWrapped = true,
		TextXAlignment = Enum.TextXAlignment.Center,
		TextYAlignment = Enum.TextYAlignment.Center,
		Parent = structures.Body.__instance,

		__dynamicKeys = {
			TextColor3 = self.Theme.Text.SelectionPrimary[1],
			TextTransparency = self.Theme.Text.SelectionPrimary[2],
		},
		__contextKeys = labelContext,

		create("UIPadding")({
			Name = "UIPadding",
			PaddingBottom = UDim.new(0, 3),
			PaddingLeft = UDim.new(0, 7),
			PaddingRight = UDim.new(0, 7),
			PaddingTop = UDim.new(0, 3),
		}),
	}) :: TextLabel
	structures.Fill = create("UIGradient")({
		Name = "UIGradient",
		Rotation = 90,
		Parent = structures.Body.__instance,

		__dynamicKeys = {
			Color = theme.FillPrimary,
		},
		__contextKeys = fillContext,
	}) :: UIGradient

	local object
	local bindings = {
		State = function()
			task.defer(function()
				structures.Label.TextColor3 = labelContext.TextColor3()
				structures.Label.TextTransparency = labelContext.TextTransparency()
				structures.Fill.Color = fillContext.Color()
			end)
		end,
		Label = function(value: string)
			structures.Label.Text = value
		end,
	}

	object = binder.Wrap(properties, bindings, structures.Body)

	object.Type = "Button"
	object.Theme = self.Theme
	object.Structures = structures

	structures.Body.MouseButton1Click:Connect(function()
		if properties.Pushed then
			task.spawn(properties.Pushed, object)
		end
	end)

	local function animateRelease()
		local tweenInfo = TweenInfo.new(0.12, Enum.EasingStyle.Sine, Enum.EasingDirection.Out)

		tweenService
			:Create(structures.PressOverlay, tweenInfo, {
				BackgroundTransparency = 1,
			})
			:Play()
	end

	structures.Body.MouseButton1Down:Connect(function()
		local tweenInfo = TweenInfo.new(0.08, Enum.EasingStyle.Cubic, Enum.EasingDirection.Out)

		tweenService
			:Create(structures.PressOverlay, tweenInfo, {
				BackgroundTransparency = 0.8,
			})
			:Play()
	end)

	structures.Body.MouseButton1Up:Connect(animateRelease)
	structures.Body.MouseLeave:Connect(animateRelease)

	binder.Apply(properties, object)

	return object
end


local types = require("@types")

return function(self, properties: types.Frame): types.Form
	--// Imports
	local creator = require("@modules/creator")
	local binder = require("@modules/binder")

	--// References
	local create = creator.Create

	--// Variables
	local parent = self.__container or self.__instance or self
	local structures = {}
	local queue = {}
	local entries = {}

	--// UI
	properties = properties or {}

	structures.Body = binder.Apply(
		properties,
		create("Frame")({
			Name = "Form",
			AutomaticSize = Enum.AutomaticSize.Y,
			BorderColor3 = Color3.fromRGB(0, 0, 0),
			BorderSizePixel = 0,
			Size = UDim2.fromScale(1, 0),
			Parent = parent,

			__dynamicKeys = {
				BackgroundColor3 = self.Theme.Controls.View[1],
				BackgroundTransparency = self.Theme.Controls.View[2],
			},

			create("UIListLayout")({
				Name = "UIListLayout",
				SortOrder = Enum.SortOrder.LayoutOrder,
			}),

			create("UIPadding")({
				Name = "Margins",
				PaddingLeft = UDim.new(0, 10),
				PaddingRight = UDim.new(0, 10),
			}),

			create("UICorner")({
				Name = "UICorner",
				CornerRadius = UDim.new(0, 6),
			}),

			create("UIStroke")({
				Name = "UIStroke",
				ApplyStrokeMode = Enum.ApplyStrokeMode.Border,

				__dynamicKeys = {
					Color = self.Theme.Controls.ViewBorder[1],
					Transparency = self.Theme.Controls.ViewBorder[2],
				},
			}),
		})
	) :: Frame

	--// Initialize
	local object = binder.Wrap(properties, {}, structures.Body)

	object.Type = "Form"
	object.Theme = self.Theme
	object.Structures = structures

	local function updateDivs()
		for i, entry in ipairs(entries) do
			local currentVisible = entry.section.Visible
			local nextEntry = entries[i + 1]
			local nextVisible = nextEntry and nextEntry.section.Visible

			entry.divider.Visible = currentVisible and nextVisible == true
		end
	end

	structures.Body.ChildAdded:Connect(function(child)
		if child:IsA("Frame") and child:FindFirstChild("LayoutIgnore") then
			local divider = child.LayoutIgnore:FindFirstChild("Divider")

			if divider then
				table.insert(queue, divider)
				table.insert(entries, { section = child, divider = divider })

				child:GetPropertyChangedSignal("Visible"):Connect(function()
					updateDivs()
				end)

				updateDivs()
			end
		end
	end)

	binder.Apply(properties, object)

	return object
end


local types = require("@types")

return function(self, properties: types.StackProperties): types.Stack
	--// Imports
	local creator = require("@modules/creator")
	local binder = require("@modules/binder")

	--// References
	local create = creator.Create

	--// Variables
	local parent = self.__container or self.__instance or self
	local structures = {}

	--// UI
	properties = properties or {}
	properties.Padding = properties.Padding or UDim.new(0, 10)
    properties.VerticalAlignment = properties.VerticalAlignment or Enum.VerticalAlignment.Center
    properties.HorizontalAlignment = properties.HorizontalAlignment or Enum.HorizontalAlignment.Right

	structures.Body = binder.Apply(
		properties,
		create("Frame")({
			Name = "HStack",
			BackgroundTransparency = 1,
			AutomaticSize = Enum.AutomaticSize.XY,
			Parent = parent,

			create("UIListLayout")({
				Name = "UIListLayout",
				FillDirection = Enum.FillDirection.Horizontal,
				SortOrder = Enum.SortOrder.LayoutOrder,
				Wraps = true,
			}),
		})
	) :: Frame

	--// Initialize
	structures.Layout = structures.Body:FindFirstChild("UIListLayout") :: UIListLayout

	local object = binder.Wrap(properties, {
		Padding = function(value: UDim)
			structures.Layout.Padding = value
		end,
		HorizontalAlignment = function(value: Enum.HorizontalAlignment)
			structures.Layout.HorizontalAlignment = value
		end,
		VerticalAlignment = function(value: Enum.VerticalAlignment)
			structures.Layout.VerticalAlignment = value
		end,
	}, structures.Body)

	object.Type = "HStack"
	object.Theme = self.Theme
	object.Structures = structures

	binder.Apply(properties, object)

	return object
end


local types = require("@types")

return function(self, properties: types.KeybindFieldProperties): types.KeybindFieldProperties
	--// Imports
	local binder = require("@modules/binder")
	local services = require("@modules/services")

	--// References
	local userInputService = services.UserInputService

	--// Variables
	local structures = require("@structures/TextField")(self)

	--// UI
	properties = properties or {}
	properties.Placeholder = properties.Placeholder or "Press a key"

	--// Initialize
	structures.Field.TextXAlignment = Enum.TextXAlignment.Right
	structures.Field.TextEditable = false
	structures.Body.Parent = self.__container or self.__instance or self
	structures.Body.AutomaticSize = Enum.AutomaticSize.XY
	structures.Body.Size = UDim2.fromOffset(0, 23)
	structures.Field.Size = UDim2.fromOffset(0, 23)
	structures.Corner.CornerRadius = UDim.new(0, 6)

	local object
	object = binder.Wrap(properties, {
		Placeholder = function(value: string)
			structures.Field.PlaceholderText = value
		end,
		Value = function(value: Enum.KeyCode)
			structures.Field.Text = value.Name

			if properties.ValueChanged then
				properties.Value = value
				task.spawn(properties.ValueChanged, object, value)
			end
		end,
	}, structures.Body)

	userInputService.InputBegan:Connect(function(input, gameProcessedEvent)
		if input.UserInputType ~= Enum.UserInputType.Keyboard then
			return
		end

		if input.KeyCode == properties.Value and properties.BindPressed then
			properties.BindPressed(object, input.KeyCode, false, gameProcessedEvent)
		end
	end)

	userInputService.InputEnded:Connect(function(input, gameProcessedEvent)
		if input.UserInputType ~= Enum.UserInputType.Keyboard then
			return
		end

		if structures.Field:IsFocused() then
			object.Value = input.KeyCode
			structures.Field:ReleaseFocus()
		elseif input.KeyCode == properties.Value and properties.BindPressed then
			properties.BindPressed(object, input.KeyCode, true, gameProcessedEvent)
		end
	end)

	object.Type = "KeybindField"
	object.Theme = self.Theme
	object.Structures = structures

	binder.Apply(properties, object)

	return object
end


local types = require("@types")

return function(self, properties: types.LabelProperties): types.Label
	--// Imports
	local creator = require("@modules/creator")
	local binder = require("@modules/binder")

	--// References
	local create = creator.Create

	--// Variables
	local parent = self.__container or self.__instance or self
	local structures = {}

	--// UI
	properties = properties or {}
	properties.Text = properties.Text or "Label"

	structures.Body = create("TextLabel")({
		Name = "Label",
		AutomaticSize = Enum.AutomaticSize.XY,
		BackgroundColor3 = Color3.fromRGB(255, 255, 255),
		BackgroundTransparency = 1,
		BorderColor3 = Color3.fromRGB(0, 0, 0),
		BorderSizePixel = 0,
		FontFace = Font.new("rbxassetid://12187365364"),
		RichText = true,
		TextSize = 15,
		TextTruncate = Enum.TextTruncate.AtEnd,
		TextWrapped = true,
		Parent = parent,

		__dynamicKeys = {
			TextColor3 = self.Theme.Text.Secondary[1],
			TextTransparency = self.Theme.Text.Secondary[2],
		},
	}) :: TextLabel

	--// Initialize
	local object = binder.Wrap(properties, {}, structures.Body)

	object.Type = "Label"
	object.Theme = self.Theme
	object.Structures = structures

	binder.Apply(properties, object)

	return object
end


local types = require("@types")

return function(self, properties: types.NotificationProperties): types.Notification
	local services = require("@modules/services")
	local binder = require("@modules/binder")
	local notificationList = require("@modules/notificationList")
	local ui = require("@self/ui")

	local tweenService = services.TweenService

	properties = properties or {}
	properties.Title = properties.Title or "Notification"
	properties.Subtitle = properties.Subtitle or ""
	properties.Duration = properties.Duration or 6

	if properties.App then
		properties.App = string.upper(properties.App)
	end

	local closed = false
	local MAX_NOTIFICATIONS = 4
	local state = { Age = 0 }

	local body, exitBtn, canvas, content, topbar = ui(self, properties, state, MAX_NOTIFICATIONS)

	local bindings = {
		Title = function(value: string)
			content.TitleContainer.Title.Text = value
		end,
		Subtitle = function(value: string)
			content.Subtitle.Text = value
			content.Subtitle.Visible = value ~= ""
		end,
		App = function(value: string)
			local upperValue = string.upper(value or "")
			topbar.App.Text = upperValue
			topbar.App.Visible = value ~= nil
			topbar.Visible = (value ~= nil) or (properties.AppIcon ~= nil)

			if properties.App ~= upperValue then
				properties.App = upperValue
			end
		end,
		AppIcon = function(value: string)
			topbar.Icon.Image = value or ""
			topbar.Icon.Visible = value ~= nil
			topbar.Visible = (properties.App ~= nil) or (value ~= nil)
		end,
		Icon = function(value: string)
			if value then
				content.TitleContainer.Icon.Image = value
			end
			content.TitleContainer.Icon.Visible = value ~= nil
		end,
	}

	local object = binder.Wrap(properties, bindings, body, { "App", "Icon" })

	object.Type = "Notification"
	object.Theme = self.Theme

	binder.Apply(properties, object)

	local function closeNotification(fromUserInput: boolean?)
		if closed then
			return
		end
		closed = true

		if not body.Parent then
			return
		end

		if properties.Closed then
			task.spawn(properties.Closed, object, fromUserInput)
		end

		local fadeTween = tweenService:Create(
			object.__instance,
			TweenInfo.new(0.4, Enum.EasingStyle.Exponential, Enum.EasingDirection.Out),
			{
				Position = object.__instance.Position + UDim2.fromOffset(350, 0),
			}
		)

		object:UpdateState(MAX_NOTIFICATIONS, false)

		local scale = object.__instance:FindFirstChild("UIScale")
		if scale then
			tweenService
				:Create(scale, TweenInfo.new(0.4, Enum.EasingStyle.Exponential, Enum.EasingDirection.Out), {
					Scale = 0.85,
				})
				:Play()
		end

		fadeTween:Play()
		fadeTween.Completed:Connect(function()
			if body.Parent then
				notificationList.RemoveNotification(object)
				body:Destroy()
			end
		end)
	end

	exitBtn.MouseButton1Click:Connect(function()
		closeNotification(true)
	end)

	function object:Close(fromUserInput: boolean?)
		closeNotification(fromUserInput)
	end

	function object:UpdateState(age: number, instant: boolean?)
		state.Age = age

		local isFaded = age >= (MAX_NOTIFICATIONS - 1)
		local isPrimary = age == 0

		local exitBgFade = isPrimary and 0.1 or 1
		local exitStrokeFade = isPrimary and 0.96 or 1
		local exitShadowFade = isPrimary and 0.9 or 1
		local exitIconFade = isPrimary and 0.5 or 1

		if isFaded then
			exitBgFade = 1
			exitStrokeFade = 1
			exitShadowFade = 1
			exitIconFade = 1
		end

		local targetBgTransparency = isFaded and 1 or 0.1

		local function apply(inst, props)
			if instant then
				for k, v in pairs(props) do
					inst[k] = v
				end
			else
				tweenService
					:Create(inst, TweenInfo.new(0.4, Enum.EasingStyle.Exponential, Enum.EasingDirection.Out), props)
					:Play()
			end
		end

		apply(canvas, { BackgroundTransparency = targetBgTransparency })

		for _, descendant in ipairs(canvas:GetDescendants()) do
			if descendant:IsA("TextLabel") then
				local targetTextTransparency = 1
				if not isFaded then
					if descendant.Name == "Title" then
						targetTextTransparency = self.Theme.Text.Primary[2].Value
					elseif descendant.Name == "Subtitle" then
						targetTextTransparency = self.Theme.Text.Secondary[2].Value
					elseif descendant.Name == "App" then
						targetTextTransparency = 0.5
					end
				end
				apply(descendant, { TextTransparency = targetTextTransparency })
			elseif descendant:IsA("ImageLabel") and descendant.Name ~= "Icon" then
				apply(descendant, { ImageTransparency = isFaded and 1 or 0 })
			end
		end

		if content:FindFirstChild("TitleContainer") and content.TitleContainer:FindFirstChild("Icon") then
			apply(content.TitleContainer.Icon, { ImageTransparency = isFaded and 1 or 0 })
		end
		if topbar:FindFirstChild("Icon") then
			apply(topbar.Icon, { ImageTransparency = isFaded and 1 or 0 })
		end

		apply(exitBtn, { BackgroundTransparency = exitBgFade })
		apply(exitBtn.Icon, { ImageTransparency = exitIconFade })
		apply(exitBtn.UIStroke, { Transparency = exitStrokeFade })

		local shadow = exitBtn:FindFirstChild("Shadow")
		if shadow and shadow:FindFirstChild("UIStroke") then
			apply(shadow.UIStroke, { Transparency = exitShadowFade })
		end
	end

	body.Position = UDim2.new(1, 187.5, 1, 0)

	object:UpdateState(0, true)

	notificationList.AddNotification(object, body)

	if body:FindFirstChild("UIScale") then
		body.UIScale.Scale = 0.85
		tweenService
			:Create(body.UIScale, TweenInfo.new(0.4, Enum.EasingStyle.Exponential, Enum.EasingDirection.Out), {
				Scale = 1,
			})
			:Play()
	end

	tweenService
		:Create(body.__instance, TweenInfo.new(0.4, Enum.EasingStyle.Exponential, Enum.EasingDirection.Out), {
			Position = UDim2.new(1, -162.5, 1, 0),
		})
		:Play()

	if properties.Duration > 0 then
		task.delay(properties.Duration, function()
			closeNotification()
		end)
	end

	return object
end


local types = require("@types")

return function(self: any, properties: types.NotificationProperties, state: { Age: number }, MAX_NOTIFICATIONS: number)
	local creator = require("@modules/creator")

	local create = creator.Create

	local notificationsContainer = self.__instance:FindFirstChild("Notifications")
	if not notificationsContainer then
		notificationsContainer = create("Frame")({
			Name = "Notifications",
			BackgroundColor3 = Color3.fromRGB(255, 255, 255),
			BackgroundTransparency = 1,
			BorderColor3 = Color3.fromRGB(0, 0, 0),
			BorderSizePixel = 0,
			Size = UDim2.fromScale(1, 1),
			ZIndex = 200,
			Parent = self.__instance,

			create("UIPadding")({
				Name = "UIPadding",
				PaddingBottom = UDim.new(0, 15),
				PaddingRight = UDim.new(0, 15),
			}),
		}).__instance
	end

	local body = create("Frame")({
		Name = "Notification",
		AnchorPoint = Vector2.new(0.5, 1),
		AutomaticSize = Enum.AutomaticSize.Y,
		BackgroundTransparency = 1,
		BorderColor3 = Color3.fromRGB(0, 0, 0),
		BorderSizePixel = 0,
		Position = UDim2.new(1, -162.5, 1, 0),
		Size = UDim2.fromOffset(325, 0),
		Parent = notificationsContainer,

		create("Frame")({
			Name = "Canvas",
			AnchorPoint = Vector2.new(0, 0),
			AutomaticSize = Enum.AutomaticSize.Y,
			BackgroundColor3 = self.Theme.Controls.Sidebar[1].Value,
			BackgroundTransparency = 0.1,
			BorderColor3 = Color3.fromRGB(0, 0, 0),
			BorderSizePixel = 0,
			Position = UDim2.fromScale(0, 0),
			Size = UDim2.fromScale(1, 0),

			__dynamicKeys = {
				BackgroundColor3 = self.Theme.Controls.Sidebar[1],
			},

			__contextKeys = {
				BackgroundTransparency = function()
					return state.Age >= (MAX_NOTIFICATIONS - 1) and 1 or 0.1
				end,
			},

			create("UICorner")({
				Name = "UICorner",
				CornerRadius = UDim.new(0, 12),
			}),

			create("UIListLayout")({
				Name = "UIListLayout",
				Padding = UDim.new(0, 5),
				SortOrder = Enum.SortOrder.LayoutOrder,
				VerticalAlignment = Enum.VerticalAlignment.Center,
			}),

			create("Frame")({
				Name = "Content",
				AutomaticSize = Enum.AutomaticSize.Y,
				BackgroundColor3 = Color3.fromRGB(255, 0, 68),
				BackgroundTransparency = 1,
				BorderColor3 = Color3.fromRGB(0, 0, 0),
				BorderSizePixel = 0,
				LayoutOrder = 1,
				Size = UDim2.fromScale(1, 0),

				create("Frame")({
					Name = "TitleContainer",
					AutomaticSize = Enum.AutomaticSize.XY,
					BackgroundColor3 = Color3.fromRGB(255, 255, 255),
					BackgroundTransparency = 1,
					BorderColor3 = Color3.fromRGB(0, 0, 0),
					BorderSizePixel = 0,
					LayoutOrder = 1,

					create("UIListLayout")({
						Name = "UIListLayout",
						FillDirection = Enum.FillDirection.Horizontal,
						Padding = UDim.new(0, 5),
						SortOrder = Enum.SortOrder.LayoutOrder,
						VerticalAlignment = Enum.VerticalAlignment.Center,
					}),

					create("ImageLabel")({
						Name = "Icon",
						BackgroundTransparency = 1,
						LayoutOrder = 1,
						Size = UDim2.fromOffset(13, 13),
						Visible = false,

						__dynamicKeys = {
							ImageColor3 = self.Theme.Text.Primary[1],
						},
						__contextKeys = {
							ImageTransparency = function()
								return state.Age >= (MAX_NOTIFICATIONS - 1) and 1 or self.Theme.Text.Primary[2].Value
							end,
						},
					}),

					create("TextLabel")({
						Name = "Title",
						AutomaticSize = Enum.AutomaticSize.Y,
						BackgroundColor3 = Color3.fromRGB(255, 255, 255),
						BackgroundTransparency = 1,
						BorderColor3 = Color3.fromRGB(0, 0, 0),
						BorderSizePixel = 0,
						LayoutOrder = 2,
						FontFace = Font.new("rbxassetid://12187365364", Enum.FontWeight.Bold, Enum.FontStyle.Normal),
						LineHeight = 0,
						Size = UDim2.new(1, 0, 0, 20),
						Text = properties.Title,
						TextColor3 = self.Theme.Text.Primary[1].Value,
						TextSize = 13,
						TextTransparency = self.Theme.Text.Primary[2].Value,
						TextWrapped = true,
						RichText = true,
						TextXAlignment = Enum.TextXAlignment.Left,

						__dynamicKeys = {
							TextColor3 = self.Theme.Text.Primary[1],
							TextTransparency = self.Theme.Text.Primary[2],
						},

						__contextKeys = {
							TextTransparency = function()
								return state.Age >= (MAX_NOTIFICATIONS - 1) and 1 or self.Theme.Text.Primary[2].Value
							end,
						},
					}),
				}),

				create("UIListLayout")({
					Name = "UIListLayout",
					SortOrder = Enum.SortOrder.LayoutOrder,
				}),

				create("TextLabel")({
					Name = "Subtitle",
					AutomaticSize = Enum.AutomaticSize.Y,
					BackgroundColor3 = Color3.fromRGB(255, 255, 255),
					BackgroundTransparency = 1,
					BorderColor3 = Color3.fromRGB(0, 0, 0),
					BorderSizePixel = 0,
					FontFace = Font.new("rbxassetid://12187365364"),
					LayoutOrder = 1,
					Position = UDim2.fromScale(0, 0.147),
					RichText = true,
					Size = UDim2.fromScale(1, 0),
					Text = properties.Subtitle,
					TextColor3 = self.Theme.Text.Secondary[1].Value,
					TextSize = 13,
					TextTransparency = self.Theme.Text.Secondary[2].Value,
					TextWrapped = true,
					TextXAlignment = Enum.TextXAlignment.Left,
					Visible = properties.Subtitle ~= "",

					__dynamicKeys = {
						TextColor3 = self.Theme.Text.Secondary[1],
						TextTransparency = self.Theme.Text.Secondary[2],
					},

					__contextKeys = {
						TextTransparency = function()
							return state.Age >= (MAX_NOTIFICATIONS - 1) and 1 or self.Theme.Text.Secondary[2].Value
						end,
					},
				}),

				create("UIPadding")({
					Name = "UIPadding",
					PaddingBottom = UDim.new(0, 12),
					PaddingLeft = UDim.new(0, 12),
					PaddingRight = UDim.new(0, 12),
				}),
			}),

			create("Frame")({
				Name = "Topbar",
				AutomaticSize = Enum.AutomaticSize.Y,
				BackgroundColor3 = Color3.fromRGB(255, 255, 255),
				BackgroundTransparency = 1,
				BorderColor3 = Color3.fromRGB(0, 0, 0),
				BorderSizePixel = 0,
				Size = UDim2.fromScale(1, 0),
				Visible = (properties.App ~= nil) or (properties.Icon ~= nil),

				create("UIListLayout")({
					Name = "UIListLayout",
					FillDirection = Enum.FillDirection.Horizontal,
					Padding = UDim.new(0, 5),
					SortOrder = Enum.SortOrder.LayoutOrder,
					VerticalAlignment = Enum.VerticalAlignment.Center,
				}),

				create("TextLabel")({
					Name = "App",
					AutomaticSize = Enum.AutomaticSize.X,
					BackgroundColor3 = Color3.fromRGB(255, 255, 255),
					BackgroundTransparency = 1,
					BorderColor3 = Color3.fromRGB(0, 0, 0),
					BorderSizePixel = 0,
					FontFace = Font.new("rbxassetid://12187365364", Enum.FontWeight.Medium, Enum.FontStyle.Normal),
					LayoutOrder = 1,
					LineHeight = 0,
					Size = UDim2.fromOffset(0, 14),
					Text = properties.App or "",
					TextColor3 = self.Theme.Text.Primary[1].Value,
					TextSize = 13,
					TextTransparency = 0.5,
					TextXAlignment = Enum.TextXAlignment.Left,
					RichText = true,
					Visible = properties.App ~= nil,

					__dynamicKeys = {
						TextColor3 = self.Theme.Text.Primary[1],
					},
				}),

				create("ImageLabel")({
					Name = "Icon",
					BackgroundColor3 = Color3.fromRGB(255, 255, 255),
					BackgroundTransparency = 1,
					BorderColor3 = Color3.fromRGB(0, 0, 0),
					BorderSizePixel = 0,
					Image = properties.AppIcon or "",
					ImageColor3 = self.Theme.Text.Primary[1].Value,
					Size = UDim2.fromOffset(20, 20),
					Visible = properties.AppIcon ~= nil,

					__dynamicKeys = {
						ImageColor3 = self.Theme.Text.Primary[1],
					},
				}),

				create("UIPadding")({
					Name = "UIPadding",
					PaddingLeft = UDim.new(0, 12),
					PaddingRight = UDim.new(0, 12),
					PaddingTop = UDim.new(0, 12),
				}),
			}),
		}),

		create("Folder")({
			Name = "LayoutIgnore",

			create("TextButton")({
				Name = "Exit",
				AnchorPoint = Vector2.new(0.5, 0.5),
				AutoButtonColor = false,
				BackgroundColor3 = self.Theme.Controls.View[1].Value,
				BackgroundTransparency = 0.1,
				BorderColor3 = Color3.fromRGB(0, 0, 0),
				BorderSizePixel = 0,
				FontFace = Font.new("rbxassetid://12187365364"),
				Position = UDim2.fromOffset(3, 3),
				Size = UDim2.fromOffset(20, 20),
				Text = "",
				TextColor3 = self.Theme.Text.Primary[1].Value,
				TextSize = 14,
				TextTransparency = 0.5,

				__dynamicKeys = {
					BackgroundColor3 = self.Theme.Controls.View[1],
				},

				create("UICorner")({
					Name = "UICorner",
					CornerRadius = UDim.new(1, 0),
				}),

				create("ImageLabel")({
					Name = "Icon",
					AnchorPoint = Vector2.new(0.5, 0.5),
					BackgroundColor3 = Color3.fromRGB(255, 255, 255),
					BackgroundTransparency = 1,
					BorderColor3 = Color3.fromRGB(0, 0, 0),
					BorderSizePixel = 0,
					Image = "rbxassetid://72660323302468",
					ImageColor3 = self.Theme.Text.Primary[1].Value,
					ImageTransparency = 0.5,
					Position = UDim2.fromScale(0.5, 0.5),
					Size = UDim2.fromOffset(20, 20),

					__dynamicKeys = {
						ImageColor3 = self.Theme.Text.Primary[1],
					},
				}),

				create("Frame")({
					Name = "Shadow",
					BackgroundColor3 = Color3.fromRGB(255, 255, 255),
					BackgroundTransparency = 1,
					BorderColor3 = Color3.fromRGB(0, 0, 0),
					BorderSizePixel = 0,
					Size = UDim2.fromScale(1, 1),

					create("UIStroke")({
						Name = "UIStroke",
						ApplyStrokeMode = Enum.ApplyStrokeMode.Border,
						Transparency = 0.9,
					}),

					create("UICorner")({
						Name = "UICorner",
						CornerRadius = UDim.new(1, 0),
					}),
				}),

				create("UIStroke")({
					Name = "UIStroke",
					ApplyStrokeMode = Enum.ApplyStrokeMode.Border,
					Color = self.Theme.Text.Primary[1].Value,
					Thickness = 2,
					Transparency = 0.96,

					__dynamicKeys = {
						Color = self.Theme.Text.Primary[1],
					},
				}),
			}),
		}),

		create("UIScale")({
			Name = "UIScale",
			Scale = 0.85,
		}),
	}) :: Frame

	local exitBtn = body.LayoutIgnore.Exit
	local canvas = body.Canvas
	local content = canvas.Content
	local topbar = canvas.Topbar

	return body, exitBtn, canvas, content, topbar
end


local types = require("@types")

return function(self, properties: types.PageProperties)
    --// Imports
    local creator = require("@modules/creator")
    local binder = require("@modules/binder")

    --// References
    local create = creator.Create

    --// Variables
    properties = properties or {}

    local structures = {}

    structures.Page = binder.Apply(
        properties,
        create("ScrollingFrame")({
            Name = "ContentList",
            AutomaticCanvasSize = Enum.AutomaticSize.Y,
            BackgroundColor3 = Color3.fromRGB(255, 255, 255),
            BackgroundTransparency = 1,
            BorderColor3 = Color3.fromRGB(0, 0, 0),
            BorderSizePixel = 0,
            CanvasSize = UDim2.new(),
            ClipsDescendants = false,
            ScrollBarImageColor3 = Color3.fromRGB(0, 0, 0),
            ScrollBarImageTransparency = 0.6,
            ScrollBarThickness = 7,
            Size = UDim2.fromScale(1, 1),

            create("UIListLayout")({
                Name = "UIListLayout",
                Padding = UDim.new(0, 9),
                SortOrder = Enum.SortOrder.LayoutOrder,
            }),

            create("UIPadding")({
                Name = "Margins",
                PaddingBottom = UDim.new(0, 17),
                PaddingLeft = UDim.new(0, 17),
                PaddingRight = UDim.new(0, 17),
                PaddingTop = UDim.new(0, 17),
            }),
        })
    ) :: ScrollingFrame

    local object = binder.Wrap(properties, {
        Parent = function(p)
            structures.Page.Parent = p
        end,
    }, structures.Page)

    object.Type = "Page"
    object.Theme = self.Theme
    object.Structures = {
        Page = structures.Page,
    }
    if self.__window then
        object.__window = self.__window
    end
    object.__container = structures.Page.__instance or structures.Page

    return object
end


local types = require("@types")

return function(self, properties: types.PageSectionProperties): types.PageSection
	--// Imports
	local creator = require("@modules/creator")
	local binder = require("@modules/binder")

	local titleStack = require("@structures/TitleStack")

	--// References
	local create = creator.Create

	--// Variables
	local parent = self.__container or self.__instance or self
	local structures = titleStack(self)

	--// UI
	properties = properties or {}
	properties.Title = properties.Title or "Title"

	local PageSections, instance = parent:FindFirstChild("PageSections"), true

	if not PageSections then
		instance = false
		PageSections = create("Frame")({
			Name = "PageSections",
			BackgroundTransparency = 1,
			Size = UDim2.fromScale(1, 0),
			AutomaticSize = Enum.AutomaticSize.Y,
			Parent = parent,

			create("UIListLayout")({
				Name = "UIListLayout",
				Padding = UDim.new(0, 25),
				SortOrder = Enum.SortOrder.LayoutOrder,
			}),
		})
	end

	local section = create("Frame")({
		Name = "PageSection",
		BackgroundTransparency = 1,
		Size = UDim2.fromScale(1, 0),
		AutomaticSize = Enum.AutomaticSize.Y,
		Parent = instance and PageSections or PageSections.__instance,

		create("UIListLayout")({
			Name = "UIListLayout",
			Padding = UDim.new(0, 12),
			SortOrder = Enum.SortOrder.LayoutOrder,
		}),
	})

	structures.Body.Parent = section.__instance

	--// Initialize
	structures.Padding.PaddingLeft = UDim.new(0, 8)
	structures.Padding.PaddingRight = UDim.new(0, 8)

	structures.Title.FontFace = Font.new(structures.Title.FontFace.Family, Enum.FontWeight.SemiBold)
	structures.Body.LayoutOrder = -1

	local object = binder.Wrap(properties, {
		Title = function(value: string)
			structures.Title.Text = value
		end,
		Subtitle = function(value: string)
			structures.Subtitle.Visible = true
			structures.Subtitle.Text = value
		end,
	}, section)

	object.Type = "PageSection"
	object.Theme = self.Theme
	object.Structures = structures
	object.__container = section.__instance

	binder.Apply(properties, object)

	return object
end


local types = require("@types")

return function(self, properties: types.PopUpButtonProperties): types.PopUpButton
	--// Imports
	local creator = require("@modules/creator")
	local binder = require("@modules/binder")
	local services = require("@modules/services")

	--// References
	local create = creator.Create

	local userInputService = services.UserInputService
	local tweenService = services.TweenService
	local workspace = services.Workspace
	local guiService = services.GuiService

	local camera = workspace.CurrentCamera

	--// Variables
	local parent = self.__container or self.__instance or self
	local theme = self.Theme.Controls.MenuButton
	local structures = {
		Options = {},
	}

	--// Constants
	local HORIZONTAL_OFFSET = -1
	local VERTICAL_PADDING = 6
	local EDGE_BUFFER = 6

	local SIZE_CONSTRAINT_Y = 239

	--// Functions
	local function resize()
		structures.Menu.AutomaticSize = Enum.AutomaticSize.XY

		task.defer(function()
			local menuHeight = structures.Menu.AbsoluteSize.Y

			if menuHeight >= SIZE_CONSTRAINT_Y then
				structures.Menu.AutomaticSize = Enum.AutomaticSize.X
				structures.Menu.Size = UDim2.fromOffset(0, SIZE_CONSTRAINT_Y)
			else
				structures.Menu.Size = UDim2.fromOffset(0, menuHeight)
				structures.Menu.AutomaticSize = Enum.AutomaticSize.X
			end
		end)
	end

	local function anchor()
		local body = structures.Body
		local menu = structures.Menu

		if not menu or not body then
			return
		end

		local bodyPos = body.AbsolutePosition
		local bodySize = body.AbsoluteSize
		local menuSize = menu.AbsoluteSize
		local viewportSize = camera.ViewportSize

		local desiredX
		if properties.Maximum and properties.Maximum > 1 then
			local anchorElement = structures.PopUpIndicator or body
			local anchorPos = anchorElement.AbsolutePosition
			desiredX = anchorPos.X + HORIZONTAL_OFFSET
		else
			desiredX = bodyPos.X + HORIZONTAL_OFFSET
		end

		local desiredY = bodyPos.Y + bodySize.Y + VERTICAL_PADDING
		local maxX = math.max(EDGE_BUFFER, viewportSize.X - EDGE_BUFFER - menuSize.X)
		local maxY = math.max(EDGE_BUFFER, viewportSize.Y - EDGE_BUFFER - menuSize.Y)

		desiredX = math.clamp(desiredX, EDGE_BUFFER, maxX)
		desiredY = math.clamp(desiredY, EDGE_BUFFER, maxY)

		menu.Position = UDim2.new(0, desiredX, 0, desiredY)
	end

	local function option(object, name, index)
		local option = nil
		option = create("TextButton")({
			Name = "Item",
			Size = UDim2.fromScale(1, 0),
			AutoButtonColor = false,
			AutomaticSize = Enum.AutomaticSize.XY,
			BorderColor3 = Color3.fromRGB(0, 0, 0),
			BorderSizePixel = 0,
			Selectable = false,
			Text = "",
			LayoutOrder = index,
			Parent = structures.Menu,

			__dynamicKeys = {
				BackgroundColor3 = self.Theme.Controls.SelectionFocused[1],
				BackgroundTransparency = self.Theme.Controls.SelectionFocused[2],
			},
			__contextKeys = {
				BackgroundTransparency = function()
					if not option then
						return
					end
					return option.GuiState == Enum.GuiState.Hover and self.Theme.Controls.SelectionFocused[2].Value or 1
				end,
			},

			create("UIPadding")({
				Name = "UIPadding",
				PaddingBottom = UDim.new(0, 3),
				PaddingLeft = UDim.new(0, 7),
				PaddingRight = UDim.new(0, 12),
				PaddingTop = UDim.new(0, 3),
			}),

			create("UIListLayout")({
				Name = "UIListLayout",
				FillDirection = Enum.FillDirection.Horizontal,
				Padding = UDim.new(0, 2),
				SortOrder = Enum.SortOrder.LayoutOrder,
				VerticalAlignment = Enum.VerticalAlignment.Center,
			}),

			create("ImageLabel")({
				Name = "Checkmark",
				BackgroundColor3 = Color3.fromRGB(255, 255, 255),
				BackgroundTransparency = 1,
				BorderColor3 = Color3.fromRGB(0, 0, 0),
				BorderSizePixel = 0,
				Image = "rbxassetid://127464789357538",
				ImageColor3 = Color3.fromRGB(0, 0, 0),
				ImageTransparency = 1,
				Size = UDim2.fromOffset(16, 16),
				Visible = false,

				__dynamicKeys = {
					ImageColor3 = self.Theme.Text.Primary[1],
					ImageTransparency = self.Theme.Text.Primary[2],
				},
			}),

			create("Frame")({
				Name = "CheckmarkRepl",
				BackgroundColor3 = Color3.fromRGB(255, 255, 255),
				BackgroundTransparency = 1,
				BorderColor3 = Color3.fromRGB(0, 0, 0),
				BorderSizePixel = 0,
				Size = UDim2.fromOffset(16, 16),
				Visible = true,
			}),

			create("TextLabel")({
				Name = "Label",
				AutomaticSize = Enum.AutomaticSize.XY,
				BackgroundColor3 = Color3.fromRGB(255, 255, 255),
				BackgroundTransparency = 1,
				BorderColor3 = Color3.fromRGB(0, 0, 0),
				BorderSizePixel = 0,
				FontFace = Font.new("rbxassetid://12187365364"),
				LayoutOrder = 1,
				RichText = true,
				Text = name,
				TextColor3 = Color3.fromRGB(0, 0, 0),
				TextSize = 15,
				TextTransparency = 0.15,
				TextTruncate = Enum.TextTruncate.AtEnd,

				__dynamicKeys = {
					TextColor3 = self.Theme.Text.Primary[1],
					TextTransparency = self.Theme.Text.Primary[2],
				},
			}),

			create("UICorner")({
				Name = "UICorner",
				CornerRadius = UDim.new(0, 5),
			}),
		}) :: TextButton
		local label = option:FindFirstChild("Label")
		local checkmark = option:FindFirstChild("Checkmark")

		structures.Options[index] = option.__instance

		option:GetPropertyChangedSignal("GuiState"):Connect(function()
			if not object.Expanded then
				return
			end

			if option.GuiState == Enum.GuiState.Hover then
				option.BackgroundTransparency = self.Theme.Controls.SelectionFocused[2].Value

				label.TextColor3 = self.Theme.Controls.SelectionFocusedAccent[1].Value
				label.TextTransparency = self.Theme.Controls.SelectionFocusedAccent[2].Value

				checkmark.ImageColor3 = self.Theme.Controls.SelectionFocusedAccent[1].Value
				checkmark.ImageTransparency = self.Theme.Controls.SelectionFocusedAccent[2].Value
			else
				option.BackgroundTransparency = 1

				label.TextColor3 = self.Theme.Text.Primary[1].Value
				label.TextTransparency = self.Theme.Text.Primary[2].Value

				checkmark.ImageColor3 = self.Theme.Text.Primary[1].Value
				checkmark.ImageTransparency = self.Theme.Text.Primary[2].Value
			end
		end)

		option.MouseButton1Click:Connect(function()
			if object then
				if object.Maximum and object.Maximum > 1 then
					local current = object.Value or {}
					if typeof(current) ~= "table" then
						current = current and { current } or {}
					end

					local foundIndex = nil
					for i, v in ipairs(current) do
						if v == index then
							foundIndex = i
							break
						end
					end

					if foundIndex then
						table.remove(current, foundIndex)
					else
						if #current < object.Maximum then
							table.insert(current, index)
						else
							table.remove(current, 1)
							table.insert(current, index)
						end
					end

					object.Value = current
				else
					object.Expanded = false
					task.wait(0.2)
					object.Value = index
				end
			end
		end)
	end

	--// UI
	properties = properties or {}
	properties.Maximum = properties.Maximum or 1
	properties.Expanded = properties.Expanded or false
	properties.Options = properties.Options or {}

	structures.Body = binder.Apply(
		properties,
		create("TextButton")({
			Name = "PopUpButton",
			AutomaticSize = Enum.AutomaticSize.XY,
			BackgroundColor3 = Color3.fromRGB(255, 255, 255),
			BackgroundTransparency = 1,
			BorderColor3 = Color3.fromRGB(0, 0, 0),
			BorderSizePixel = 0,
			Selectable = false,
			Text = "",
			Parent = parent,

			create("UIPadding")({
				Name = "UIPadding",
				PaddingBottom = UDim.new(0, 3),
				PaddingLeft = UDim.new(0, 3),
				PaddingRight = UDim.new(0, 3),
				PaddingTop = UDim.new(0, 3),
			}),

			create("UIListLayout")({
				Name = "UIListLayout",
				FillDirection = Enum.FillDirection.Horizontal,
				Padding = UDim.new(0, 7),
				SortOrder = Enum.SortOrder.LayoutOrder,
				VerticalAlignment = Enum.VerticalAlignment.Center,
			}),

			create("Frame")({
				Name = "PopUpIndicator",
				BorderColor3 = Color3.fromRGB(0, 0, 0),
				BorderSizePixel = 0,
				LayoutOrder = 1,
				Selectable = true,
				Size = UDim2.fromOffset(16, 16),

				__dynamicKeys = {
					BackgroundColor3 = theme.IndicatorBackground[1],
					BackgroundTransparency = theme.IndicatorBackground[2],
				},

				create("UICorner")({
					Name = "UICorner",
					CornerRadius = UDim.new(0, 4),
				}),

				create("ImageLabel")({
					Name = "Indicators",
					BackgroundColor3 = Color3.fromRGB(255, 255, 255),
					BackgroundTransparency = 1,
					BorderColor3 = Color3.fromRGB(0, 0, 0),
					BorderSizePixel = 0,
					Image = "rbxassetid://89151647333378",
					Size = UDim2.fromScale(1, 1),

					__dynamicKeys = {
						ImageColor3 = self.Theme.Text.Primary[1],
						ImageTransparency = self.Theme.Text.Primary[2],
					},
				}),
			}),

			create("TextLabel")({
				Name = "Label",
				AutomaticSize = Enum.AutomaticSize.XY,
				BackgroundColor3 = Color3.fromRGB(255, 255, 255),
				BackgroundTransparency = 1,
				BorderColor3 = Color3.fromRGB(0, 0, 0),
				BorderSizePixel = 0,
				FontFace = Font.new("rbxassetid://12187365364"),
				RichText = true,
				Text = "None",
				TextSize = 15,
				TextTransparency = 0.15,
				TextTruncate = Enum.TextTruncate.AtEnd,

				__dynamicKeys = {
					TextColor3 = self.Theme.Text.Primary[1],
					TextTransparency = self.Theme.Text.Primary[2],
				},
			}),
		})
	) :: TextButton

	--// Initialize
	structures.PopUpIndicator = structures.Body:FindFirstChild("PopUpIndicator") :: Frame
	structures.CurrentTab = structures.Body:FindFirstChild("Label") :: TextLabel

	structures.MenuContainer = create("ScreenGui")({
		Name = "Container",
		IgnoreGuiInset = true,
		ScreenInsets = Enum.ScreenInsets.None,
		ZIndexBehavior = Enum.ZIndexBehavior.Sibling,
		DisplayOrder = 201,
		OnTopOfCoreBlur = true,

		create("CanvasGroup")({
			Name = "MenuBody",
			BorderColor3 = Color3.fromRGB(0, 0, 0),
			BorderSizePixel = 0,
			BackgroundTransparency = 1,
			Size = UDim2.fromScale(1, 1),

			create("ScrollingFrame")({
				Name = "PopUpMenu",
				AutomaticSize = Enum.AutomaticSize.X,
				BorderColor3 = Color3.fromRGB(0, 0, 0),
				BorderSizePixel = 0,
				AutomaticCanvasSize = Enum.AutomaticSize.Y,
				CanvasSize = UDim2.new(),
				ScrollBarImageColor3 = Color3.fromRGB(0, 0, 0),
				ScrollBarImageTransparency = 0.5,
				ScrollBarThickness = 3,

				__dynamicKeys = {
					BackgroundColor3 = theme.MenuBackground[1],
					BackgroundTransparency = theme.MenuBackground[2],
				},

				create("UICorner")({
					Name = "UICorner",
					CornerRadius = UDim.new(0, 6),
				}),

				create("UIStroke")({
					Name = "UIStroke",
					ApplyStrokeMode = Enum.ApplyStrokeMode.Border,
					Transparency = 0.9,
				}),

				create("UIPadding")({
					Name = "UIPadding",
					PaddingBottom = UDim.new(0, 5),
					PaddingLeft = UDim.new(0, 5),
					PaddingRight = UDim.new(0, 5),
					PaddingTop = UDim.new(0, 5),
				}),

				create("UIListLayout")({
					Name = "UIListLayout",
					SortOrder = Enum.SortOrder.LayoutOrder,
					Padding = UDim.new(0, 1),
				}),
			}),
		}),
	}) :: ScreenGui

	structures.MenuBody = structures.MenuContainer:FindFirstChild("MenuBody") :: CanvasGroup
	structures.Menu = structures.MenuBody:FindFirstChild("PopUpMenu") :: ScrollingFrame

	local object
	local bindings = {
		Options = function(value: { [number]: string })
			for _, option in ipairs(structures.Options) do
				option:Destroy()
			end

			for index, _option in ipairs(value) do
				option(object, _option, index)
				resize()
			end
		end,

		Expanded = function(value: boolean)
			local expand = value == true

			if expand then
				structures.MenuContainer.Parent = structures.Body.__instance
			end

			anchor()

			local goal = { GroupTransparency = expand and 0 or 1 }
			local tweenInfo = TweenInfo.new(expand and 0 or 0.4, Enum.EasingStyle.Exponential)
			local tween = tweenService:Create(structures.MenuBody, tweenInfo, goal)

			tween:Play()
			tween.Completed:Connect(function()
				if object.Expanded == false then
					structures.MenuContainer.Parent = nil
				end
			end)
		end,

		Value = function(value)
			local isMulti = object and object.Maximum and object.Maximum > 1

			if isMulti then
				local selMap = {}
				if typeof(value) == "table" then
					for _, v in ipairs(value) do
						selMap[v] = true
					end
				elseif value then
					selMap[value] = true
				end

				local labels = {}
				for idx, opt in ipairs(structures.Options) do
					if selMap[idx] and opt and opt:FindFirstChild("Label") then
						table.insert(labels, opt:FindFirstChild("Label").Text)
					end
				end

				if #labels == 0 then
					structures.CurrentTab.Text = "None"
				else
					structures.CurrentTab.Text = table.concat(labels, ", ")
				end

				for index, option in ipairs(structures.Options) do
					if not option or not option:FindFirstChild("Checkmark") then
						continue
					end

					if selMap[index] then
						option:FindFirstChild("Checkmark").Visible = true
						option:FindFirstChild("CheckmarkRepl").Visible = false
					else
						option:FindFirstChild("Checkmark").Visible = false
						option:FindFirstChild("CheckmarkRepl").Visible = true
					end
				end
			else
				if not value or not structures.Options[value] then
					structures.CurrentTab.Text = "None"
				else
					structures.CurrentTab.Text = structures.Options[value]:FindFirstChild("Label").Text
				end

				for index, option in ipairs(structures.Options) do
					local currentIndex = index == value

					if not option or not option:FindFirstChild("Checkmark") then
						continue
					end

					if not currentIndex then
						option:FindFirstChild("Checkmark").Visible = false
						option:FindFirstChild("CheckmarkRepl").Visible = true -- Scuffed way to do this but 🤷♂
					else
						option:FindFirstChild("CheckmarkRepl").Visible = false
						if not value then
							option:FindFirstChild("Checkmark").Visible = false
						else
							option:FindFirstChild("Checkmark").Visible = true
						end
					end
				end
			end

			if properties.ValueChanged then
				properties.Value = value
				task.spawn(properties.ValueChanged, object, value)
			end
		end,
	}

	object = binder.Wrap(properties, bindings, structures.Body)

	object.Type = "PopUpButton"
	object.Theme = self.Theme
	object.Structures = structures
	object.Option = function(self, name: string?)
		local index = #structures.Options + 1

		option(object, name, index)
		resize()

		table.insert(object.Options, name)

		return structures.Options[index]
	end
	object.Remove = function(self, index: number?)
		if index and structures.Options[index] then
			structures.Options[index]:Destroy()
			object.Options[index] = nil
		end
	end

	binder.Apply(properties, object)

	structures.Body:GetPropertyChangedSignal("AbsolutePosition"):Connect(anchor)
	structures.Body:GetPropertyChangedSignal("AbsoluteSize"):Connect(anchor)
	structures.Menu:GetPropertyChangedSignal("AbsoluteSize"):Connect(anchor)

	userInputService.InputBegan:Connect(function(input)
		if
			object.Expanded
			and (
				input.UserInputType == Enum.UserInputType.MouseButton1
				or input.UserInputType == Enum.UserInputType.Touch
			)
		then
			local mouse = userInputService:GetMouseLocation()
			local inset = guiService:GetGuiInset()
			local menuFrame = structures.Menu
			local pos = menuFrame.AbsolutePosition
			local size = menuFrame.AbsoluteSize

			local adjustedMouseY = mouse.Y - inset.Y

			if
				mouse.X < pos.X
				or mouse.X > pos.X + size.X
				or adjustedMouseY < pos.Y
				or adjustedMouseY > pos.Y + size.Y
			then
				object.Expanded = false
			end
		end
	end)

	structures.Body.MouseButton1Click:Connect(function()
		object.Expanded = not object.Expanded
	end)

	return object
end