local Auth = require(script.Parent:WaitForChild("Auth"))
local Data = require(script.Parent:WaitForChild("Data"))
local Util = require(script.Parent:WaitForChild("Util"))

local Popup = require(script:WaitForChild("Popup"))
local Purchasables = require(script:WaitForChild("Purchasables"))
local Title = require(script:WaitForChild("Title"))

local Remote = Util.Remote

local VIP = { allowedBulkPurchaseIds = {}, effects = {}, popup = Popup, purchasables = Purchasables }

-- vip, supervip, premium
local gamePassDonations = { 5391359, 5391361, 5411126 }
local assetDonations = { { 88978146769822, 441133423, 313102724 }, { 115403290087767, 441134066, 423601416 } }

-- 5 group member
-- 4 chat commands/subscriber
-- 3 premium donor
-- 2 super vip
-- 1 vip
local function getDonationLevel(player)
	if Util.Service.Run:IsStudio() and shared._K_INTERFACE and shared._K_INTERFACE.DEBUG then
		return Util.Service.ReplicatedStorage:GetAttribute("DonationLevel") or 0
	end

	local okRank, rank = Util.Retry(function()
		return player:GetRankInGroupAsync(3403354)
	end)
	if okRank and rank > 1 then
		return 5
	end

	for _, ugcId in Purchasables.chatCommands do
		local ok, result = Util.Retry(function()
			return Util.Service.Marketplace:PlayerOwnsAssetAsync(player, ugcId)
		end)
		if ok and result then
			return 4
		end
	end

	for level = #gamePassDonations, 1, -1 do
		local okGamePass, result = Util.Retry(function()
			return Util.Service.Marketplace:UserOwnsGamePassAsync(player.UserId, gamePassDonations[level])
		end)
		if okGamePass and result then
			return level
		end
	end

	for level = #assetDonations, 1, -1 do
		for _, assetId in assetDonations[level] do
			local okAsset, result = Util.Retry(function()
				return Util.Service.Marketplace:PlayerOwnsAssetAsync(player, assetId)
			end)
			if okAsset and result then
				return level
			end
		end
	end

	return 0
end

local function setDonationLevel(player: Player, level: number?)
	if not level then
		level = getDonationLevel(player)
	end

	local current = player:GetAttribute("_KDonationLevel")
	player:SetAttribute("_KDonationLevel", math.max(level :: number, current or 0))

	if Data.settings.vip then
		if level > 0 then
			Auth.userRoleAdd(player.UserId, "vip")
		end
		if level < 3 then
			task.delay(8, Remote.VIPNotification.Fire, Remote.VIPNotification, player)
		end
	end
end

local adminUGCMap = {}
for _, module in script:WaitForChild("UGC"):GetChildren() do
	task.spawn(function()
		local result = require(module)
		if result then
			adminUGCMap[result.MatchId] = result
		end
	end)
end

if Util.Service.Run:IsServer() then
	local ownedCache = {}
	local function ownsAsset(player, assetId)
		local ownedUGC = ownedCache[player.UserId]
		if not ownedUGC then
			ownedUGC = {}
			ownedCache[player.UserId] = ownedUGC
		end

		if ownedUGC[assetId] then
			return true
		end

		local ok, result = Util.Retry(function()
			return Util.Service.Marketplace:PlayerOwnsAssetAsync(player, assetId)
		end)
		if ok then
			ownedUGC[assetId] = result
			return result
		end

		return
	end

	local ugcAssetMatch = {
		-- wings
		[133292294488871] = "rbxassetid://89119211625300", -- light
		[110848154960799] = "rbxassetid://89119211625300", -- dark
		[92807314389236] = "rbxassetid://89119211625300", -- gold
		-- crowns
		[18966788838] = "rbxassetid://18966762965", -- light
		[106645613603989] = "rbxassetid://18966762965", -- dark
		[99317257118206] = "rbxassetid://18966762965", -- gold
	}

	local cache = {}
	function VIP.Effect(player: Player, assetId: number, match: string, equip: boolean, name: string)
		if not Data.settings.vip then
			return
		end

		local ugcEffect = adminUGCMap[match]
		if not (ugcEffect and player.Character) then
			return
		end

		local userEffects = VIP.effects[player.UserId]
		if not userEffects then
			userEffects = {}
			VIP.effects[player.UserId] = userEffects
		end

		local existing = player.Character:FindFirstChild(ugcEffect.Name)
		if existing then
			existing:Destroy()
		end

		if not equip then
			userEffects[match] = nil
			return
		end

		if ugcAssetMatch[assetId] ~= match then
			return
		end

		local donationLevel = player:GetAttribute("_KDonationLevel") or 0
		local owned = donationLevel > 2
			or (match == "rbxassetid://18966762965" and donationLevel > 1)
			or ownsAsset(player, assetId)

		local tried = cache[assetId]
		if not tried then
			tried = {}
			cache[assetId] = tried
		end

		if owned or not tried[player.UserId] then
			local try
			if not tried[player.UserId] then
				try = true
				tried[player.UserId] = true
			end

			local ugc = ugcEffect.Method(player.Character, name)

			if try and not owned then
				task.delay(15, function()
					if ugc then
						ugc:Destroy()
					end
				end)
			else
				userEffects[match] = { Method = ugcEffect.Method, Params = { name } }
			end
		end
	end

	Remote.VIPUGCMethod:Connect(VIP.Effect)

	function VIP.Title(player: Player, title, ...)
		local definition = Title.definition[title and string.lower(title)]
		if definition and definition.gamepass then
			if definition.ownerCache[player.UserId] == false then
				return
			else
				local owned = false
				if definition.assetId then
					local assets = if typeof(definition.assetId) == "table"
						then definition.assetId
						else { definition.assetId }
					for _, assetId in assets do
						if not (player and player.Parent) then
							return
						end
						local okAsset, result = Util.Retry(function()
							return Util.Service.Marketplace:PlayerOwnsAssetAsync(player, assetId)
						end)
						if okAsset then
							definition.ownerCache[player.UserId] = result
							if result then
								owned = true
								break
							end
						end
					end
				end
				if not owned and definition.gamepass and player and player.Parent then
					local okGamePass, result = Util.Retry(function()
						return Util.Service.Marketplace:UserOwnsGamePassAsync(player.UserId, definition.gamepass)
					end)
					if okGamePass then
						definition.ownerCache[player.UserId] = result
					end
					if not (okGamePass and result) then
						return -- early return if they don't own
					end
				end
			end
		end

		local userEffects = VIP.effects[player.UserId]
		if not userEffects then
			userEffects = {}
			VIP.effects[player.UserId] = userEffects
		end

		userEffects.Title = if title then { Method = Title.Method, Params = { title, ... } } else nil

		if player.Character then
			Title.Method(player.Character, title, ...)
		end
	end

	Remote.Title:Connect(function(player: Player, title: string?)
		if not Data.settings.vip then
			return
		end
		local titleDefinition = Title.definition[title and string.lower(title)]
		if titleDefinition then
			VIP.Title(player, title)
		else
			VIP.Title(player)
		end
	end)

	function VIP.EffectHandler(character)
		if not Data.settings.vip or not character then
			return
		end

		-- ugc avatar effects
		for _, child in character:GetChildren() do
			if not child:IsA("Accessory") then
				continue
			end

			local handle = child:FindFirstChild("Handle")
			if not handle then
				continue
			end

			local mesh
			if handle:IsA("MeshPart") then
				mesh = handle.MeshId
			else
				local specialMesh = handle:FindFirstChildOfClass("SpecialMesh")
				if specialMesh then
					mesh = specialMesh.MeshId
				end
			end

			local ugcEffect = adminUGCMap[mesh]
			if ugcEffect then
				task.spawn(ugcEffect.Method, character, child)
			end
		end

		-- vip equipped effects
		local player = Util.Service.Players:GetPlayerFromCharacter(character)
		local effects = player and VIP.effects[player.UserId]
		if not effects then
			return
		end

		for _, effect in effects do
			task.spawn(effect.Method, character, unpack(effect.Params))
		end
	end

	local characterCleanup = {}

	function VIP.CharacterAdded(character)
		local humanoid = character:FindFirstChildOfClass("Humanoid")
		if not humanoid then
			return
		end
		characterCleanup[character] = humanoid.ApplyDescriptionFinished:Connect(function()
			VIP.EffectHandler(character)
		end)
	end

	local playerCleanup = {}
	Util.Service.Players.PlayerRemoving:Connect(function(player)
		if playerCleanup[player] then
			for _, connection in playerCleanup[player] do
				if connection and connection.Connected then
					connection:Disconnect()
				end
			end
			table.clear(playerCleanup[player])
		end
		playerCleanup[player] = nil
	end)

	Util.SafePlayerAdded(function(player)
		task.spawn(setDonationLevel, player)
		playerCleanup[player] = {}
		table.insert(playerCleanup[player], player.CharacterAdded:Connect(VIP.CharacterAdded))
		table.insert(playerCleanup[player], player.CharacterAppearanceLoaded:Connect(VIP.EffectHandler))
		table.insert(
			playerCleanup[player],
			player.CharacterRemoving:Connect(function(character)
				if characterCleanup[character] and characterCleanup[character].Connected then
					characterCleanup[character]:Disconnect()
				end
				characterCleanup[character] = nil
			end)
		)
		if player.Character then
			VIP.EffectHandler(player.Character)
		end
	end)

	do
		local checking = {}
		Remote.VIPCheck:Connect(function(player, id)
			if checking[player] then
				return
			end
			checking[player] = true

			local level = if table.find(Purchasables.chatCommands, id)
				then 4
				else table.find(Purchasables.chatCommandsLower, id) or 0

			if level > 0 then
				local ok, result = Util.Retry(function()
					return Util.Service.Marketplace:PlayerOwnsAssetAsync(player, id)
				end)
				if ok and result then
					setDonationLevel(player, level)
					Remote.RolesNotification:Fire(player)
				end
			end

			checking[player] = nil
		end)
	end

	Util.Service.Marketplace.PromptPurchaseFinished:Connect(function(player, assetId, purchased)
		if purchased then
			local ownedUGC = ownedCache[player.UserId]
			if not ownedUGC then
				ownedUGC = {}
				ownedCache[player.UserId] = ownedUGC
			end
			ownedUGC[assetId] = true

			for title, definition in Title.definition do
				if definition.assetId then
					local assets = if type(definition.assetId) == "table"
						then definition.assetId
						else { definition.assetId }
					for _, id in assets do
						if id == assetId then
							definition.ownerCache[player.UserId] = true
							break
						end
					end
				end
			end
		end
	end)

	Util.Service.Marketplace.PromptGamePassPurchaseFinished:Connect(function(player, passId, purchased)
		if purchased then
			local level = player:GetAttribute("_KDonationLevel") or 0
			local vipIndex = table.find(gamePassDonations, passId)
			if vipIndex then
				level = math.max(level, vipIndex)
				if Data.settings.vip then
					Auth.userRoleAdd(player.UserId, "vip")
					Remote.RolesNotification:Fire(player)
				end
			end
			player:SetAttribute("_KDonationLevel", level)

			for title, definition in Title.definition do
				if definition.gamepass == passId then
					definition.ownerCache[player.UserId] = true
				end
			end
		end
	end)

	Util.Remote.PromptBulkPurchase:Connect(function(player, id)
		if type(id) == "number" and VIP.allowedBulkPurchaseIds[id] then
			local items = { { Type = Enum.MarketplaceProductType.AvatarAsset, Id = tostring(id) } }
			Util.Service.Marketplace:PromptBulkPurchase(player, items, {})
		end
	end)

	for _, id in Purchasables.chatCommands do
		VIP.allowedBulkPurchaseIds[id] = true
	end

	for _, id in Purchasables.chatCommandsLower do
		VIP.allowedBulkPurchaseIds[id] = true
	end

	for _, data in Purchasables.donations do
		VIP.allowedBulkPurchaseIds[data.assetId] = true
	end

	for _, data in Purchasables.scriptedUGC do
		VIP.allowedBulkPurchaseIds[data.id] = true
	end
end

return VIP


-- src/init.luau
--- @class MainModule
if shared._K_INTERFACE then
	return shared._K_INTERFACE
end

local RunService = game:GetService("RunService")
local requireStart = os.clock()

local Client = script:WaitForChild("Client")
local Server = RunService:IsServer() and script:WaitForChild("Server")
local Shared = script:WaitForChild("Shared")

local Util = require(Shared:WaitForChild("Util"))

export type Log = Util.Log
export type LogType = Util.LogType
export type Logger = Util.Logger
export type Hook = "log" | "preCommand" | "postCommand"

local IS_DEMO_PLACE = game.PlaceId == 2569622788

if Server then
	Server.Parent = Util.Service.ServerStorage
end

--[=[
	@within MainModule
	@interface _K
	.Flux Flux

	.Auth Auth

	.Process Process
	.Registry Registry
	.Util Util
	.UI UI

	.IsClient boolean
	.IsServer boolean
	.IsStudio boolean

	.client { [any]: any }?
	.pinnedAnnouncement {}?
	._serverLock boolean

	.creatorId number
	.log Logger.log
	.logger Logger.logger
]=]
local _K = {
	script = script,
	IsClient = RunService:IsClient(),
	IsServer = RunService:IsServer(),
	IsStudio = RunService:IsStudio(),

	DEBUG = IS_DEMO_PLACE,
	VERSION = Util.String.trim(script:WaitForChild("VERSION").Value),

	Logger = Util.Logger.new(true),

	-- modules
	Util = Util,
	Data = require(Shared:WaitForChild("Data")),
	Hook = require(Shared:WaitForChild("Hook")),
	Remote = Util.Remote,
	UI = nil,

	-- submodules
	Flux = require(script:WaitForChild("Flux")),
	Z = require(script:WaitForChild("Z")),

	-- core modules
	Auth = require(Shared:WaitForChild("Auth")),
	Process = require(Shared:WaitForChild("Process")),
	Registry = require(Shared:WaitForChild("Registry")),
	VIP = require(Shared:WaitForChild("VIP")),

	-- shorthand
	Service = Util.Service,
	Server = Server,
	Tools = Server and Server:WaitForChild("Tools"),

	client = nil,
	pinnedAnnouncement = nil,
	ready = false,
	Notify = nil,

	cleanupCommands = {},
	_serverLock = false,
	_addonTag = "Kohl's Admin Addon",
}

-- Increase Z scratch buffer size to 4MB
_K.Z.BUFFER = buffer.create(4 * 1024 ^ 2)

-- register creator
task.spawn(function()
	if game.CreatorType == Enum.CreatorType.Group then
		_K.groupId = game.CreatorId
		local ok, result = Util.Retry(function()
			return _K.Service.Group:GetGroupInfoAsync(game.CreatorId)
		end)
		_K.creatorId = if ok then result.Owner.Id else 0
	else
		_K.creatorId = game.CreatorId
	end
	_K.Data.creatorId = _K.creatorId

	if _K.IsServer then
		local start = os.clock()
		while not _K.Data.roles and os.clock() - start < 10 do
			task.wait()
		end
		if _K.Data.roles then
			_K.Auth.userRoleAdd(_K.creatorId, "creator")
		end
	end
end)

function _K.getCommandPrefix(from: number?)
	if _K.IsClient then
		return _K.client.playerPrefix._value
	end
	return _K.Data.playerPrefix[from] or ";"
end

function _K.removeExcessLogs()
	local logs = _K.Data.logs
	local excess = #logs - _K.Logger.limit
	if excess > 0 then
		_K.Util.Table.fastRemove(logs, 1, excess)
	end
end

function _K.log(text: string, level: LogType, from: number?, filtered: boolean?): Log?
	if _K.Data.logsHidden[from] then
		return
	end
	local log = _K.Logger:log(text, level, from, true)
	if not log then
		return -- DEBUG disabled
	end

	if _K.IsClient then
		log[6] = true
	end

	task.defer(function()
		if from then
			log[5] = Util.getUserInfo(from).Username
		end

		if _K.IsServer then
			-- trim for 32KB sync max
			if #log[1] > 16 * 1024 then
				log[1] = string.sub(log[1] :: string, 1, 16 * 1024)
			end
			if from and filtered then
				log[1] = Util.String.filterForBroadcast(text, from)
			end
			if
				(level == "CHAT" and _K.Data.settings.saveChatLogs)
				or (
					level == "COMMAND"
					and _K.Data.settings.saveLogs
					and (not from or _K.Data.settings.saveLogsForAllRoles or _K.Auth.hasRestrictedRole(from))
				)
			then
				table.insert(_K.Data.Sync.logs, log)
			end
			for _, player in _K.Service.Players:GetPlayers() do
				if player:GetAttribute("_K_READY") and _K.Auth.hasPermission(player.UserId, "serverlogs") then
					_K.Remote.Log:Fire(player, log)
				end
			end
		elseif _K.client and _K.client.dashboard then
			_K.client.dashboard.Logs:updateList()
		end

		table.insert(_K.Data.logs, log)
		_K.Hook.log:Fire(log)
		_K.removeExcessLogs()
	end)

	return log
end
_K.Logger.logs = _K.Data.logs

function _K.alert(to: number | Player, text: string, isError: boolean?)
	if type(to) == "number" then
		to = _K.Service.Players:GetPlayerByUserId(to)
	end
	if typeof(to) == "Instance" and to:IsA("Player") then
		local props = { Text = text, From = if isError then "_K" else nil }
		if isError then
			props.TextColor3 = Color3.new(1, 0, 0)
			props.Sound = "Call_Leave"
		end
		if _K.IsServer then
			_K.Remote.Notify:Fire(to :: Player, props)
		else
			_K.Notify(props)
		end
	end
end

-- register initial UI children
if _K.IsClient then
	_K.UI = require(Client:WaitForChild("UI"))
	local uiRegisterStart = os.clock()
	_K.UI.registerClasses()
	task.spawn(_K.log, `UI classes registered in {math.round((os.clock() - uiRegisterStart) * 1000)} ms`, "DEBUG")
end

local typeRegisterStart = os.clock()
-- register types
for _, child in Shared.DefaultTypes:GetChildren() do
	require(child)(_K)
end
task.spawn(_K.log, `Default Types registered in {math.round((os.clock() - typeRegisterStart) * 1000)} ms`, "DEBUG")

local commandRegisterStart = os.clock()
-- register commands
for _, child in Shared.DefaultCommands:GetChildren() do
	_K.Registry.registerCommandModule(_K, child)
end
task.spawn(
	_K.log,
	`Default Commands registered in {math.round((os.clock() - commandRegisterStart) * 1000)} ms`,
	"DEBUG"
)

shared._K_INTERFACE = _K

if _K.IsServer then
	require(Server)(_K)
else
	if not _K.IsStudio or IS_DEMO_PLACE then
		print(`🛡 Running Kohl's Admin v{_K.VERSION} by @Scripth`)
	end
end

task.spawn(_K.log, `Required in {math.round((os.clock() - requireStart) * 1000)} ms`, "DEBUG")

export type _K = typeof(_K)

return _K


local OnyxUI = script.Parent.Parent.Parent.OnyxUI.Packages.OnyxUI
local Themer = require(OnyxUI.Themer)
local Fusion = require(OnyxUI.Parent.Fusion)
local Util = require(OnyxUI.Util)

local Children = Fusion.Children

local SwitchGroup = require(script.Parent.SwitchGroup)
local Switch = require(OnyxUI.Components.Switch)
local Text = require(OnyxUI.Components.Text)
local Components = {
	Text = Text,
	Switch = Switch,
	SwitchGroup = SwitchGroup,
}

local DISABLED_TRANSPARENCY = 0.5

export type Props = SwitchGroup.Props & {
	Label: Fusion.UsedAs<string>,
}

local function SettingToggle(Scope: Fusion.Scope<any>, Props: Props)
	local Scope = Fusion.innerScope(Scope, Fusion, Util, Components)
	local Theme = Themer.Theme:now()

	local Switched = Scope:EnsureValue(Util.Fallback(Props.Switched, false))
	local Disabled = Util.Fallback(Props.Disabled, false)

	Props.Switched = Switched

	return Scope:SwitchGroup(Util.CombineProps(Props, {
		Size = UDim2.fromScale(1, 0),
		AutomaticSize = Enum.AutomaticSize.Y,
		Switched = Switched,
		Disabled = Disabled,

		[Children] = {
			Scope:Text {
				AnchorPoint = Vector2.new(0, 0.5),
				Position = UDim2.fromScale(0, 0.5),
				Text = Props.Label,
				TextColor3 = Theme.Colors.BaseContent.Main,
				TextTransparency = Scope:Computed(function(Use)
					if Use(Disabled) then
						return DISABLED_TRANSPARENCY
					else
						return 0
					end
				end),
				TextWrapped = false,
			},
			Scope:Switch {
				AnchorPoint = Vector2.new(1, 0),
				Position = UDim2.fromScale(1, 0),
				Switched = Switched,
				Disabled = Props.Disabled,
				Selectable = false,
			},
		},
	}))
end

return SettingToggle


local OnyxUI = script.Parent.Parent.Parent.OnyxUI.Packages.OnyxUI
local Fusion = require(OnyxUI.Parent.Fusion)
local Themer = require(OnyxUI.Themer)
local Util = require(OnyxUI.Util)
local BitCave = require(script.Parent.Parent.Themes.BitCave)

local Children = Fusion.Children

local Frame = require(OnyxUI.Components.Frame)
local SettingsMenu = require(script.Parent)
local Components = {
	Frame = Frame,
	SettingsMenu = SettingsMenu,
}

return {
	story = function(Props)
		local Scope = Fusion.innerScope(Props.scope, Fusion, Util, Components)
		local Theme = Themer.Theme:now()

		Scope:Frame {
			Parent = Props.target,
			Padding = {
				All = Scope:UDim(0, Theme.StrokeThickness["1"]),
			},
			List = {
				FillDirection = Enum.FillDirection.Horizontal,
			},

			[Children] = {
				Scope:SettingsMenu {},
				Themer.Theme:is(BitCave):during(function()
					return Scope:SettingsMenu {}
				end),
			},
		}
	end,
	fusion = Fusion,
}


local OnyxUI = script.Parent.Parent.Parent.OnyxUI.Packages.OnyxUI
local Util = require(OnyxUI.Util)
local Themer = require(OnyxUI.Themer)
local Fusion = require(OnyxUI.Parent.Fusion)

local BaseButton = require(OnyxUI.Components.BaseButton)
local Switch = require(OnyxUI.Components.Switch)
local Components = {
	BaseButton = BaseButton,
	Switch = Switch,
}

export type Props = Switch.Props & {}

return function(Scope: Fusion.Scope<any>, Props: Props)
	local Scope = Fusion.innerScope(Scope, Fusion, Util, Components)
	local Theme = Themer.Theme:now()

	local Switched = Scope:EnsureValue(Util.Fallback(Props.Switched, false))

	Props.Switched = Switched

	return Scope:BaseButton(Util.CombineProps(Props, {
		Name = "SwitchGroup",
		ClickSound = Theme.Sound.Switch,
		Disabled = Props.Disabled,

		OnActivate = function()
			Switched:set(not Fusion.peek(Switched))
		end,
	}))
end


local OnyxUI = require(script.Parent.Parent.OnyxUI)
local Fusion = require(script.Parent.Parent.OnyxUI.Packages.Fusion)

local Themer = OnyxUI.Themer
local Util = OnyxUI.Util
local Children = Fusion.Children

local SettingToggle = require(script.SettingToggle)

export type Props = {
	Parent: Fusion.UsedAs<Instance>?,
}

return function(Scope: Fusion.Scope<any>, Props: Props)
	local Scope = Fusion.innerScope(Scope, Fusion, OnyxUI.Util, OnyxUI.Components, {
		SettingToggle = SettingToggle,
	})
	local Theme = Themer.Theme:now()

	return Scope:Card(Util.CombineProps(Props, {
		Parent = Props.Parent,
		Size = Scope:UDim2Offset(Theme.Sizing["16"], 0),
		AutomaticSize = Enum.AutomaticSize.Y,
		List = {
			HorizontalFlex = Enum.UIFlexAlignment.Fill,
		},
		Corner = {
			Radius = Scope:UDim(0, Theme.CornerRadius["2"]),
		},

		[Children] = {
			Scope:TitleBar {
				Content = { "Settings" },
				ContentSize = Theme.TextSize["1.25"],
			},
			Scope:Scroller {
				Size = UDim2.new(UDim.new(1, 0), UDim.new(0, 175)),
				AutomaticSize = Enum.AutomaticSize.None,
				List = {
					HorizontalFlex = Enum.UIFlexAlignment.Fill,
				},
				Padding = {
					All = Scope:UDim(0, Theme.StrokeThickness["1"]),
					Right = Scope:Computed(function(Use)
						return UDim.new(0, Use(Theme.StrokeThickness["1"]) + Use(Theme.Spacing["1"]))
					end),
				},

				[Children] = {
					Scope:SettingToggle {
						Label = "Music",
						Switched = true,
					},
					Scope:SettingToggle {
						Label = "Low quality",
					},
					Scope:SettingToggle {
						Label = "Copyrighted audio",
						Switched = true,
					},
					Scope:SettingToggle {
						Label = "Infinite Bobux",
						Disabled = true,
					},
					Scope:SettingToggle {
						Label = "Something else",
					},
					Scope:SettingToggle {
						Label = "Nothing same",
					},
					Scope:TextInput {
						AutomaticSize = Enum.AutomaticSize.Y,
						PlaceholderText = "Nickname",
						CharacterLimit = 20,
					},
					Scope:Slider {
						Unit = 1 / 8,
					},
				},
			},
			Scope:Button {
				Content = { "Close" },
				Color = Theme.Colors.Primary.Main,
				Size = UDim2.fromScale(1, 0),
				AutomaticSize = Enum.AutomaticSize.Y,
			},
		},
	}))
end


local OnyxUI = require(script.Parent.Parent.Parent.OnyxUI)
local Fusion = require(script.Parent.Parent.Parent.OnyxUI.Packages.OnyxUI.Parent.Fusion)

local Util = OnyxUI.Util
local Themer = OnyxUI.Themer
local Components = OnyxUI.Components
local Children = Fusion.Children

local function Palette(Scope: Fusion.Scope<any>, _: any)
	local Scope = Fusion.innerScope(Scope, Fusion, Util, Components)
	local Theme = Themer.Theme:now()

	return Scope:Base {
		Name = "Palette",
		BackgroundTransparency = 1,
		List = {
			Padding = Scope:UDim(0, Theme.Spacing["0.75"]),
		},

		[Children] = {
			{
				Scope:Base {
					Size = UDim2.fromOffset(100, 100),
					BackgroundColor3 = Theme.Colors.Info.Light,
					BackgroundTransparency = 0,
				},
				Scope:Base {
					Size = UDim2.fromOffset(100, 100),
					BackgroundColor3 = Theme.Colors.Info.Main,
					BackgroundTransparency = 0,
				},
				Scope:Base {
					Size = UDim2.fromOffset(100, 100),
					BackgroundColor3 = Theme.Colors.Info.Dark,
					BackgroundTransparency = 0,
				},
				Scope:Base {
					Size = UDim2.fromOffset(100, 100),
					BackgroundColor3 = Theme.Colors.Info.Contrast,
					BackgroundTransparency = 0,
				},
			},
		},
	}
end

return {
	story = function(Props)
		local Scope = Fusion.scoped(Fusion, Util, Components, {
			Palette = Palette,
		})

		local AnotherTheme = Themer.NewTheme(Scope, {
			Colors = {
				Info = { Main = Util.Colors.Blue["600"] },
			},
		})

		Scope:Base {
			Parent = Props.target,
			List = {
				FillDirection = Enum.FillDirection.Horizontal,
			},
			BackgroundTransparency = 1,

			[Children] = {
				Scope:Palette {},
				Themer.Theme:is(AnotherTheme):during(function()
					return Scope:Palette {}
				end),
			},
		}

		return function()
			Scope:doCleanup()
		end
	end,
	fusion = Fusion,
}


local OnyxUI = script.Parent.Parent.Parent.OnyxUI.Packages.OnyxUI
local Util = require(OnyxUI.Util)
local NewTheme = require(OnyxUI.Themer.NewTheme)
local Fusion = require(OnyxUI.Parent.Fusion)

local Scope = Fusion.scoped()

local BitCave = NewTheme(Scope, {
	Colors = {
		Primary = {
			Main = Util.Colors.White,
		},
		Secondary = {
			Main = Util.Colors.White,
		},
		Accent = {
			Main = Util.Colors.White,
		},

		Neutral = {
			Main = Util.Colors.Stone["800"],
		},
		NeutralContent = {
			Main = Util.Colors.Stone["300"],
		},

		Base = {
			Main = Util.Colors.Black,
		},
		BaseContent = {
			Main = Util.Colors.White,
		},

		Success = {
			Main = Util.Colors.Green["500"],
		},
		Error = {
			Main = Util.Colors.Red["500"],
		},
		Warning = {
			Main = Util.Colors.Amber["500"],
		},
		Info = {
			Main = Util.Colors.Cyan["400"],
		},
	},
	Font = {
		Body = "rbxassetid://12187371840",
		Heading = "rbxassetid://12187371840",
		Monospace = "rbxassetid://12187371840",
	},
	FontWeight = {
		Body = Enum.FontWeight.Bold,
		Bold = Enum.FontWeight.ExtraBold,
		Heading = Enum.FontWeight.ExtraBold,
	},
	TextSize = {
		Base = 18,
	},
	CornerRadius = {
		Base = 0,
	},
	StrokeThickness = {
		Base = 2,
	},
	StrokeEmphasis = {
		Regular = 0,
	},
	Spacing = {
		Base = 24,
	},
	Padding = {
		Base = 28,
	},
	Sizing = {
		Base = 24,
	},
	SpringSpeed = {
		Base = 60,
	},
	SpringDampening = {
		Base = 0.75,
	},
	Emphasis = {
		Regular = 0.125,
	},
})

return BitCave


local fs = require("@lune/fs")
local serde = require("@lune/serde")

local function convertDependencies(pesdeDependencies)
	local wallyDependencies = {}

	for alias, dependency in pairs(pesdeDependencies) do
		if next(dependency) ~= nil then
			assert(dependency.name == nil, `Package relies on Pesde package.`)

			if dependency.wally and dependency.version then
				wallyDependencies[alias] = `{dependency.wally}@{dependency.version}`
			end
		end
	end

	return wallyDependencies
end

local function convertName(pesdeName)
	return string.gsub(string.gsub(pesdeName, "avafe/", "imavafe/"), "_", "-")
end

local function convertManifest(pesdeToml)
	local wallyInfo = {
		package = {
			name = convertName(pesdeToml.name),
			version = pesdeToml.version,

			license = pesdeToml.license,
			authors = pesdeToml.authors,

			registry = pesdeToml["wally_indices"].default,
			realm = "shared",
		},
		dependencies = convertDependencies(pesdeToml.dependencies),
	}

	return wallyInfo
end

local function convertProject(path: string)
	if fs.isFile(`{path}/pesde.toml`) then
		local pesdeToml = serde.decode("toml", fs.readFile(`{path}/pesde.toml`))
		local wallyToml = serde.encode("toml", convertManifest(pesdeToml), true)

		fs.writeFile(`{path}/wally.toml`, wallyToml)
	else
		assert(false, `pesde.toml does not exist for {path}`)
	end
end

convertProject(".")


--[=[
		@class AutoScaler

		Automatically scales children for the user's screen. 📱💻📺🥽
]=]

--[=[
	@interface AutoScalerProps
	@within AutoScaler

	. ... FrameProps -- All Frame properties are accepted.
	.BaseResolution Vector2 -- The base resolution to scale from.
	.MinScale number -- The minimum scale factor.
	.MaxScale number -- The maximum scale factor.
	.ScaleMultiplier number -- A multiplier applied to the calculated scale.
]=]

local Workspace = game:GetService("Workspace")

local OnyxUI = script.Parent.Parent
local Fusion = require(OnyxUI.Parent.Fusion)
local Util = require(OnyxUI.Util)
local ViewportSize = require(OnyxUI.Util.ViewportSize)

local Out = Fusion.Out

local Base = require(script.Parent.Base)
local Frame = require(script.Parent.Frame)
local Components = {
	Base = Base,
	Frame = Frame,
}

export type Props = Base.Props & {
	BaseResolution: Fusion.UsedAs<Vector2>?,
	MinScale: Fusion.UsedAs<number>?,
	MaxScale: Fusion.UsedAs<number>?,
	ScaleMultiplier: Fusion.UsedAs<number>?,
}

return function(Scope: Fusion.Scope<any>, Props: Props)
	local Scope = Fusion.innerScope(Scope, Fusion, Util, Components)

	local BaseResolution = Util.Fallback(Props.BaseResolution, Vector2.new())
	local MinScale = Util.Fallback(Props.MinScale, 0.8)
	local MaxScale = Util.Fallback(Props.MaxScale, math.huge)
	local ScaleMultiplier = Util.Fallback(Props.ScaleMultiplier, 1)

	local ScreenSize = Scope:Value(Vector2.new())

	ViewportSize:Observe(function(Size)
		ScreenSize:set(Size)
	end)

	return Scope:Frame(Util.CombineProps(Props, {
		Name = script.Name,
		Scale = {
			Scale = Scope:Computed(function(Use)
				local Ratio = Use(ScaleMultiplier)
					/ math.max((Use(BaseResolution).X / Use(ScreenSize).X), (Use(BaseResolution).Y / Use(ScreenSize).Y))
				return math.clamp(Ratio, Use(MinScale), Use(MaxScale))
			end),
		},
	}))
end


local OnyxUI = script.Parent.Parent
local Fusion = require(OnyxUI.Parent.Fusion)
local Themer = require(OnyxUI.Themer)
local Util = require(OnyxUI.Util)

local Children = Fusion.Children

local AutoScaler = require(OnyxUI.Components.AutoScaler)
local Card = require(OnyxUI.Components.Card)
local Components = {
	AutoScaler = AutoScaler,
	Card = Card,
}

return {
	story = function(Props)
		local Scope = Fusion.innerScope(Props.scope, Fusion, Util, Components)
		local Theme = Themer.Theme:now()

		Scope:AutoScaler {
			Parent = Props.target,
			BaseResolution = Vector2.new(800, 800),
			List = {
				FillDirection = Enum.FillDirection.Vertical,
				Padding = Scope:UDim(0, Theme.Spacing["0.75"]),
			},

			[Children] = {
				Scope:Card {
					Size = Scope:UDim2Offset(Theme.Sizing["16"], Theme.Sizing["8"]),
					AutomaticSize = Enum.AutomaticSize.None,
				},
			},
		}
	end,
	fusion = Fusion,
}


--[=[
		@class Avatar

		Useful for displaying player headshots and profile pictures. And optionally, user status.
]=]

--[=[
	@interface AvatarProps
	@within Avatar

	. ... ImageProps -- All Image properties are accepted.
	.Image string? -- The image to display in the avatar.
	.RingEnabled boolean? -- Whether the ring around the avatar is enabled.
	.RingColor Color3? -- The color of the ring around the avatar.
	.RingThickness number? -- The thickness of the ring around the avatar.
	.IndicatorEnabled boolean? -- Whether the indicator is enabled.
	.IndicatorColor Color3? -- The color of the indicator.
	.IndicatorIcon string? -- The icon to display in the indicator.
	.IndicatorIconColor Color3? -- The color of the indicator icon.
	.IndicatorCornerRadius UDim? -- The corner radius of the indicator.
]=]

local OnyxUI = script.Parent.Parent

local Fusion = require(OnyxUI.Parent.Fusion)
local Util = require(OnyxUI.Util)
local Themer = require(OnyxUI.Themer)

local Children = Fusion.Children

local Image = require(script.Parent.Image)
local Group = require(script.Parent.Group)
local Icon = require(script.Parent.Icon)
local Components = {
	Image = Image,
	Group = Group,
	Icon = Icon,
}

export type Props = Image.Props & {
	Image: Fusion.UsedAs<string>?,
	RingEnabled: Fusion.UsedAs<boolean>?,
	RingColor: Fusion.UsedAs<Color3>?,
	RingThickness: Fusion.UsedAs<number>?,
	IndicatorEnabled: Fusion.UsedAs<boolean>?,
	IndicatorColor: Fusion.UsedAs<Color3>?,
	IndicatorIcon: Fusion.UsedAs<string>?,
	IndicatorIconColor: Fusion.UsedAs<Color3>?,
	IndicatorCornerRadius: Fusion.UsedAs<UDim>?,
}

return function(Scope: Fusion.Scope<any>, Props: Props)
	local Scope = Fusion.innerScope(Scope, Fusion, Util, Components)
	local Theme = Themer.Theme:now()

	local ImageProp = Util.Fallback(Props.Image, nil)
	local RingEnabled = Util.Fallback(Props.RingEnabled, false)
	local RingColor = Util.Fallback(Props.RingColor, Theme.Colors.Primary.Main)
	local RingThickness = Util.Fallback(Props.RingThickness, Theme.StrokeThickness["2"])
	local IndicatorEnabled = Util.Fallback(Props.IndicatorEnabled, false)
	local IndicatorColor = Util.Fallback(Props.IndicatorColor, Theme.Colors.Primary.Main)
	local IndicatorCornerRadius = Util.Fallback(Props.IndicatorCornerRadius, Scope:UDim(0, Theme.CornerRadius["Full"]))
	local IndicatorIcon = Util.Fallback(Props.IndicatorIcon, nil)
	local IndicatorIconColor = Util.Fallback(Props.IndicatorIconColor, Util.Colors.White)

	return Scope:Image(Util.CombineProps(Props, {
		Name = script.Name,
		Image = ImageProp,
		Size = Scope:UDim2Offset(Theme.TextSize["4.5"], Theme.TextSize["4.5"]),
		BackgroundColor3 = Theme.Colors.Neutral.Dark,
		Stroke = {
			Enabled = RingEnabled,
			Color = Scope:Spring(RingColor, Theme.SpringSpeed["0.5"], Theme.SpringDampening["1"]),
			Thickness = Scope:Spring(RingThickness, Theme.SpringSpeed["0.5"], Theme.SpringDampening["1"]),
		},
		Corner = {
			Radius = Scope:UDim(0, Theme.CornerRadius["1"]),
		},

		[Children] = {
			Scope:Computed(function(Use)
				if Use(IndicatorEnabled) then
					return Themer.Theme:is(Theme):during(function()
						return Scope:Group {
							Name = "Indicator",
							BackgroundColor3 = Scope:Spring(
								IndicatorColor,
								Theme.SpringSpeed["0.5"],
								Theme.SpringDampening["1"]
							),
							BackgroundTransparency = 0,
							Size = UDim2.fromScale(0.25, 0.25),
							AutomaticSize = Enum.AutomaticSize.None,
							AnchorPoint = Vector2.new(1, 1),
							Position = UDim2.fromScale(1, 1),
							Aspect = {
								Ratio = 1,
							},
							Corner = {
								Radius = IndicatorCornerRadius,
							},

							[Children] = {
								Scope:Icon {
									Image = IndicatorIcon,
									ImageColor3 = IndicatorIconColor,
									ImageTransparency = Scope:Computed(function(Use)
										if Use(IndicatorIcon) then
											return 0
										else
											return 1
										end
									end),
									Size = UDim2.fromScale(1, 1),
									AnchorPoint = Vector2.new(0.5, 0.5),
									Position = UDim2.fromScale(0.5, 0.5),
								},
							},
						}
					end)
				else
					return
				end
			end),
		},
	}))
end


local OnyxUI = script.Parent.Parent

local Fusion = require(OnyxUI.Parent.Fusion)
local Themer = require(OnyxUI.Themer)
local Util = require(OnyxUI.Util)

local Children = Fusion.Children

local Frame = require(script.Parent.Frame)
local Avatar = require(script.Parent.Avatar)
local Components = {
	Frame = Frame,
	Avatar = Avatar,
}

local INDICATOR_COLORS =
	{ Util.Colors.Red["500"], Util.Colors.Green["400"], Util.Colors.Orange["500"], Util.Colors.Stone["600"] }

return {
	story = function(Props)
		local Scope = Fusion.innerScope(Props.scope, Fusion, Util, Components)
		local Theme = Themer.Theme:now()

		local IndicatorColor = Scope:Value(INDICATOR_COLORS[2])
		local RingThickness = Scope:Value(Fusion.peek(Theme.StrokeThickness["2"]))

		local RandomizerThread = task.spawn(function()
			while task.wait(1) do
				IndicatorColor:set(INDICATOR_COLORS[math.random(1, #INDICATOR_COLORS)])

				if Fusion.peek(RingThickness) == Fusion.peek(Theme.StrokeThickness["2"]) then
					RingThickness:set(Fusion.peek(Theme.StrokeThickness["3"]))
				else
					RingThickness:set(Fusion.peek(Theme.StrokeThickness["2"]))
				end
			end
		end)

		Scope:innerScope({
			function()
				task.cancel(RandomizerThread)
			end,
		})

		Scope:Frame {
			Parent = Props.target,
			Padding = {
				All = Scope:UDim(0, Theme.StrokeThickness["4"]),
			},
			List = {
				Padding = Scope:UDim(0, Theme.Spacing["1"]),
				FillDirection = Enum.FillDirection.Horizontal,
			},

			[Children] = {
				Scope:Avatar {
					Image = "rbxthumb://type=AvatarHeadShot&id=144146784&w=150&h=150",
				},
				Scope:Avatar {
					Image = "rbxthumb://type=AvatarHeadShot&id=144146784&w=150&h=150",
					Corner = {
						Radius = Scope:UDim(0, Theme.CornerRadius.Full),
					},
				},
				Scope:Avatar {
					Image = "rbxthumb://type=AvatarHeadShot&id=144146784&w=150&h=150",
					Corner = {
						Radius = Scope:UDim(0, Theme.CornerRadius.Full),
					},
					RingEnabled = true,
					RingColor = IndicatorColor,
				},
				Scope:Avatar {
					Image = "rbxthumb://type=AvatarHeadShot&id=144146784&w=150&h=150",
					Corner = {
						Radius = Scope:UDim(0, Theme.CornerRadius.Full),
					},
					IndicatorEnabled = true,
					IndicatorColor = IndicatorColor,
				},
				Scope:Avatar {
					Image = "rbxthumb://type=AvatarHeadShot&id=144146784&w=150&h=150",
					Corner = {
						Radius = Scope:UDim(0, Theme.CornerRadius.Full),
					},
					RingEnabled = true,
					RingColor = Util.Colors.Green["400"],
					RingThickness = RingThickness,
				},
				Scope:Avatar {
					Image = "rbxthumb://type=AvatarHeadShot&id=144146784&w=150&h=150",
					Corner = {
						Radius = Scope:UDim(0, Theme.CornerRadius.Full),
					},
					IndicatorEnabled = true,
					IndicatorColor = Util.Colors.Sky["500"],
					IndicatorIcon = "rbxassetid://13805569043",
				},
			},
		}
	end,
	fusion = Fusion,
}


--[=[
		@class Badge

		Used to inform the user of something's status. E.g. a notification indicator or discount tag.

]=]

--[=[
	@interface BadgeProps
	@within Badge

	. ... FrameProps -- All Frame properties are accepted.
	.Content {string}? -- The content to display inside the badge.
	.ContentWrapped boolean? -- Whether the content should wrap if it overflows.
	.Color Color3? -- The background color of the badge.
	.ContentColor Color3? -- The color of the content inside the badge.
	.ContentSize number? -- The size of the content inside the badge.
]=]

local OnyxUI = script.Parent.Parent
local Fusion = require(OnyxUI.Parent.Fusion)
local Util = require(OnyxUI.Util)
local Themer = require(OnyxUI.Themer)

local Children = Fusion.Children

local Frame = require(script.Parent.Frame)
local IconText = require(script.Parent.IconText)
local Components = {
	Frame = Frame,
	IconText = IconText,
}

export type Props = Frame.Props & {
	Content: Fusion.UsedAs<{ string }>?,
	ContentWrapped: Fusion.UsedAs<boolean>?,
	Color: Fusion.UsedAs<Color3>?,
	ContentColor: Fusion.UsedAs<Color3>?,
	ContentSize: Fusion.UsedAs<number>?,
}

return function(Scope: Fusion.Scope<any>, Props: Props)
	local Scope = Fusion.innerScope(Scope, Fusion, Util, Components)
	local Theme = Themer.Theme:now()

	local Content = Util.Fallback(Props.Content, {})
	local ContentWrapped = Util.Fallback(Props.ContentWrapped, true)
	local Color = Util.Fallback(Props.Color, Theme.Colors.Base.Main)
	local ContentColor = Util.Fallback(
		Props.ContentColor,

		Scope:Computed(function(Use)
			return Util.Emphasize(Use(Color), Use(Theme.Emphasis.Contrast))
		end)
	)
	local ContentSize = Util.Fallback(Props.ContentSize, Theme.TextSize["1"])

	return Scope:Frame(Util.CombineProps(Props, {
		Name = script.Name,
		BackgroundColor3 = Color,
		BackgroundTransparency = 0,
		Padding = {
			All = Scope:UDim(0, Theme.Padding["0"]),
			Left = Scope:UDim(0, Theme.Padding["0.25"]),
			Right = Scope:UDim(0, Theme.Padding["0.25"]),
		},
		Corner = {
			Radius = Scope:UDim(0, Theme.CornerRadius["2"]),
		},
		List = {
			Padding = Scope:UDim(0, Theme.Spacing["0.25"]),
			FillDirection = Enum.FillDirection.Horizontal,
			HorizontalAlignment = Enum.HorizontalAlignment.Center,
			VerticalAlignment = Enum.VerticalAlignment.Center,
			Wraps = ContentWrapped,
		},
		Stroke = {},

		[Children] = {
			Scope:IconText {
				Content = Content,
				ContentColor = ContentColor,
				ContentSize = ContentSize,
				ContentWrapped = ContentWrapped,
				List = {
					HorizontalAlignment = Enum.HorizontalAlignment.Center,
					VerticalAlignment = Enum.VerticalAlignment.Center,
					Padding = Scope:UDim(0, Theme.Spacing["0.25"]),
				},
			},
		},
	}))
end


local OnyxUI = script.Parent.Parent

local Fusion = require(OnyxUI.Parent.Fusion)
local Themer = require(OnyxUI.Themer)
local Util = require(OnyxUI.Util)

local Children = Fusion.Children

local Frame = require(OnyxUI.Components.Frame)
local Badge = require(OnyxUI.Components.Badge)
local Text = require(OnyxUI.Components.Text)
local Components = {
	Frame = Frame,
	Badge = Badge,
	Text = Text,
}

return {
	story = function(Props)
		local Scope = Fusion.innerScope(Props.scope, Fusion, Util, Components)
		local Theme = Themer.Theme:now()

		local NotificationCount = Scope:Value(0)

		local CountThread = task.spawn(function()
			while task.wait(0.08) do
				if Fusion.peek(NotificationCount) == 100 then
					task.wait(3)
					NotificationCount:set(1)
				else
					NotificationCount:set(Fusion.peek(NotificationCount) + 1)
				end
			end
		end)

		Scope:innerScope({
			function()
				task.cancel(CountThread)
			end,
		})

		Scope:Frame {
			Parent = Props.target,
			List = {
				Padding = Scope:UDim(0, Theme.Spacing["0.5"]),
			},

			[Children] = {
				Scope:Badge {
					Content = { "Badge" },
				},
				Scope:Badge {
					Content = { "rbxassetid://103798699021677", "-50%" },
					Color = Util.Colors.Red["500"],
				},
				Scope:Badge {
					Content = { "rbxassetid://140490867216758", "LIMITED" },
					Color = Util.Colors.Red["500"],
				},
				Scope:Badge {
					Content = Scope:Computed(function(Use)
						if Use(NotificationCount) >= 100 then
							return { "99+" }
						else
							return { Use(NotificationCount) }
						end
					end),
					Color = Theme.Colors.Primary.Main,
				},
				Scope:Frame {
					List = {
						HorizontalAlignment = Enum.HorizontalAlignment.Center,
						FillDirection = Enum.FillDirection.Horizontal,
						Padding = Scope:UDim(0, Theme.Spacing["0.25"]),
					},

					[Children] = {
						Scope:Text {
							Text = "It's also proportional alongside text.",
						},
						Scope:Badge {
							Content = { "rbxassetid://137979359742656", "TRUE" },
							Color = Util.Colors.Green["500"],
						},
					},
				},
			},
		}
	end,
	fusion = Fusion,
}


--[=[
		@class Base

		The foundational component of OnyxUI, from which all other components are built off of. Props supported here typically work in all other components.
]=]

--[=[
	@interface GradientProps
	@within Base

	.Enabled boolean? -- Whether the gradient is enabled.
	.Color ColorSequence? -- The color sequence of the gradient.
	.Offset UDim? -- The offset of the gradient.
	.Rotation number? -- The rotation of the gradient.
	.Transparency NumberSequence? -- The transparency sequence of the gradient.
]=]

--[=[
	@interface PaddingProps
	@within Base

	.Enabled boolean? -- Whether the padding is enabled.
	.All UDim? -- The padding applied to all sides.
	.Top UDim? -- The padding applied to the top side.
	.Left UDim? -- The padding applied to the left side.
	.Right UDim? -- The padding applied to the right side.
	.Bottom UDim? -- The padding applied to the bottom side.
]=]

--[=[
	@interface CornerProps
	@within Base

	.Enabled boolean? -- Whether the corner is enabled.
	.Radius UDim? -- The radius of the corner.
]=]

--[=[
	@interface StrokeProps
	@within Base

	.Enabled boolean? -- Whether the stroke is enabled.
	.Thickness number? -- The thickness of the stroke.
	.Color Color3? -- The color of the stroke.
	.Transparency number? -- The transparency of the stroke.
	.LineJoinMode Enum.LineJoinMode? -- The line join mode of the stroke.
	.ApplyStrokeMode Enum.ApplyStrokeMode? -- The apply stroke mode of the stroke.
	.Offset UDim? -- The offset of the stroke's position, relative to the parent's minimum height or width.
	.Position Enum.BorderStrokePosition? -- The stroke's position on its parent's border.
	.SizingMode Enum.StrokeSizingMode? -- The sizing mode of the stroke.
	.ZIndex number? -- The render order of the stroke relative to sibling stroke instances.
	.Gradient GradientProps? -- The gradient applied to the stroke.
]=]

--[=[
	@interface AspectProps
	@within Base

	.Enabled boolean? -- Whether the aspect ratio constraint is enabled.
	.Ratio number? -- The aspect ratio.
	.Type Enum.AspectType? -- The aspect type.
	.DominantAxis Enum.DominantAxis? -- The dominant axis.
]=]

--[=[
	@interface ScaleProps
	@within Base

	.Enabled boolean? -- Whether the scale is enabled.
	.Scale number? -- The scale factor.
]=]

--[=[
	@interface FlexProps
	@within Base

	.Enabled boolean? -- Whether the flex item is enabled.
	.Mode Enum.UIFlexMode? -- The flex mode.
	.ItemLineAlignment Enum.ItemLineAlignment? -- The alignment of items along the line.
	.GrowRatio number? -- The grow ratio of the flex item.
	.ShrinkRatio number? -- The shrink ratio of the flex item.
]=]

--[=[
	@interface ListProps
	@within Base

	.Enabled boolean? -- Whether the list layout is enabled.
	.Padding UDim? -- The padding between items in the list.
	.FillDirection Enum.FillDirection? -- The fill direction of the list.
	.SortOrder Enum.SortOrder? -- The sort order of the list.
	.Wraps boolean? -- Whether the list wraps.
	.HorizontalAlignment Enum.HorizontalAlignment? -- The horizontal alignment of the list.
	.HorizontalFlex boolean? -- Whether horizontal flex is enabled.
	.VerticalAlignment Enum.VerticalAlignment? -- The vertical alignment of the list.
	.VerticalFlex boolean? -- Whether vertical flex is enabled.
	.ItemLineAlignment Enum.ItemLineAlignment? -- The alignment of items along the line.
]=]

--[=[
	@interface GridProps
	@within Base

	.Enabled boolean? -- Whether the grid layout is enabled.
	.CellPadding UDim2? -- The padding between cells in the grid.
	.CellSize UDim2? -- The size of each cell in the grid.
	.FillDirection Enum.FillDirection? -- The fill direction of the grid.
	.FillDirectionMaxCells number? -- The maximum number of cells in the fill direction.
	.SortOrder Enum.SortOrder? -- The sort order of the grid.
	.StartCorner Enum.StartCorner? -- The starting corner of the grid.
	.HorizontalAlignment Enum.HorizontalAlignment? -- The horizontal alignment of the grid.
	.VerticalAlignment Enum.VerticalAlignment? -- The vertical alignment of the grid.
]=]

--[=[
	@interface TableProps
	@within Base

	.Enabled boolean? -- Whether the table layout is enabled.
	.Padding UDim? -- The padding between items in the table.
	.FillEmptySpaceColumns boolean? -- Whether empty space in columns is filled.
	.FillEmptySpaceRows boolean? -- Whether empty space in rows is filled.
	.FillDirection Enum.FillDirection? -- The fill direction of the table.
	.SortOrder Enum.SortOrder? -- The sort order of the table.
	.MajorAxis Enum.TableMajorAxis? -- The major axis of the table.
	.HorizontalAlignment Enum.HorizontalAlignment? -- The horizontal alignment of the table.
	.VerticalAlignment Enum.VerticalAlignment? -- The vertical alignment of the table.
]=]

--[=[
	@interface PageProps
	@within Base

	.Enabled boolean? -- Whether the page layout is enabled.
	.Animated boolean? -- Whether the page transitions are animated.
	.Circular boolean? -- Whether the pages are circular.
	.EasingDirection Enum.EasingDirection? -- The easing direction for transitions.
	.EasingStyle Enum.EasingStyle? -- The easing style for transitions.
	.Padding UDim? -- The padding between pages.
	.TweenTime number? -- The time for page transitions.
	.FillDirection Enum.FillDirection? -- The fill direction of the pages.
	.SortOrder Enum.SortOrder? -- The sort order of the pages.
	.HorizontalAlignment Enum.HorizontalAlignment? -- The horizontal alignment of the pages.
	.VerticalAlignment Enum.VerticalAlignment? -- The vertical alignment of the pages.
	.GamepadInputEnabled boolean? -- Whether gamepad input is enabled.
	.ScrollWheelInputEnabled boolean? -- Whether scroll wheel input is enabled.
	.TouchInputEnabled boolean? -- Whether touch input is enabled.
]=]

--[=[
	@interface SizeLimitProps
	@within Base

	.Enabled boolean? -- Whether the size constraint is enabled.
	.Max Vector2? -- The maximum size.
	.Min Vector2? -- The minimum size.
]=]

--[=[
	@interface TextSizeLimitProps
	@within Base

	.Enabled boolean? -- Whether the text size constraint is enabled.
	.Max number? -- The maximum text size.
	.Min number? -- The minimum text size.
]=]

--[=[
	@interface BaseProps
	@within Base

	.ClassName string? -- The class name of the component.
	.Name string? -- The name of the component.
	.Parent Instance? -- The parent instance of the component.
	.Position UDim2? -- The position of the component.
	.Rotation number? -- The rotation of the component.
	.AnchorPoint Vector2? -- The anchor point of the component.
	.Size UDim2? -- The size of the component.
	.AutomaticSize Enum.AutomaticSize? -- The automatic size of the component.
	.Visible boolean? -- Whether the component is visible.
	.ZIndex number? -- The ZIndex of the component.
	.LayoutOrder number? -- The layout order of the component.
	.ClipsDescendants boolean? -- Whether the component clips its descendants.
	.Active boolean? -- Whether the component is active.
	.Selectable boolean? -- Whether the component is selectable.
	.Interactable boolean? -- Whether the component is interactable.
	.BackgroundColor3 Color3? -- The background color of the component.
	.BackgroundTransparency number? -- The background transparency of the component.
	.NextSelectionDown GuiObject? -- The next selection down.
	.NextSelectionUp GuiObject? -- The next selection up.
	.NextSelectionRight GuiObject? -- The next selection right.
	.NextSelectionLeft GuiObject? -- The next selection left.
	.SelectionImageObject GuiObject? -- The selection image object.
	.SelectionOrder number? -- The selection order.
	.SizeConstraint Enum.SizeConstraint? -- The size constraint of the component.
	.AutoLocalize boolean? -- Whether the component auto-localizes.
	.RootLocalizationTable LocalizationTable? -- The root localization table.
	.SelectionBehaviorDown Enum.SelectionBehavior? -- The selection behavior down.
	.SelectionBehaviorUp Enum.SelectionBehavior? -- The selection behavior up.
	.SelectionBehaviorRight Enum.SelectionBehavior? -- The selection behavior right.
	.SelectionBehaviorLeft Enum.SelectionBehavior? -- The selection behavior left.
	.SelectionGroup boolean? -- Whether the component is part of a selection group.

	.Corner CornerProps? -- The corner properties.
	.Padding PaddingProps? -- The padding properties.
	.Stroke StrokeProps? -- The stroke properties.
	.Gradient GradientProps? -- The gradient properties.
	.Aspect AspectProps? -- The aspect ratio properties.
	.Scale ScaleProps? -- The scale properties.

	.List ListProps? -- The list layout properties.
	.Grid GridProps? -- The grid layout properties.
	.Table TableProps? -- The table layout properties.
	.Page PageProps? -- The page layout properties.

	.Flex FlexProps? -- The flex layout properties.
	.SizeLimit SizeLimitProps? -- The size limit properties.
	.TextSizeLimit TextSizeLimitProps? -- The text size limit properties.
]=]

local OnyxUI = script.Parent.Parent
local Fusion = require(OnyxUI.Parent.Fusion)
local Util = require(OnyxUI.Util)
local Themer = require(OnyxUI.Themer)

local Children = Fusion.Children

export type GradientProps = {
	Enabled: Fusion.UsedAs<boolean>?,
	Color: Fusion.UsedAs<ColorSequence>?,
	Offset: Fusion.UsedAs<UDim>?,
	Rotation: Fusion.UsedAs<number>?,
	Transparency: Fusion.UsedAs<NumberSequence>?,
}
export type PaddingProps = {
	Enabled: Fusion.UsedAs<boolean>?,
	All: Fusion.UsedAs<UDim>?,
	Top: Fusion.UsedAs<UDim>?,
	Left: Fusion.UsedAs<UDim>?,
	Right: Fusion.UsedAs<UDim>?,
	Bottom: Fusion.UsedAs<UDim>?,
}
export type CornerProps = {
	Enabled: Fusion.UsedAs<boolean>?,
	Radius: Fusion.UsedAs<UDim>?,
}
export type StrokeProps = {
	Enabled: Fusion.UsedAs<boolean>?,
	Thickness: Fusion.UsedAs<number>?,
	Color: Fusion.UsedAs<Color3>?,
	Transparency: Fusion.UsedAs<number>?,
	LineJoinMode: Fusion.UsedAs<Enum.LineJoinMode>?,
	ApplyStrokeMode: Fusion.UsedAs<Enum.ApplyStrokeMode>?,
	Offset: Fusion.UsedAs<UDim>?,
	Position: Fusion.UsedAs<Enum.BorderStrokePosition>?,
	SizingMode: Fusion.UsedAs<Enum.StrokeSizingMode>?,
	ZIndex: Fusion.UsedAs<number>?,

	Gradient: Fusion.UsedAs<GradientProps>?,
}
export type AspectProps = {
	Enabled: Fusion.UsedAs<boolean>?,
	Ratio: Fusion.UsedAs<number>?,
	Type: Fusion.UsedAs<Enum.AspectType>?,
	DominantAxis: Fusion.UsedAs<Enum.DominantAxis>?,
}
export type ScaleProps = {
	Enabled: Fusion.UsedAs<boolean>?,
	Scale: Fusion.UsedAs<number>?,
}
export type FlexProps = {
	Enabled: Fusion.UsedAs<boolean>?,
	Mode: Fusion.UsedAs<Enum.UIFlexMode>?,
	ItemLineAlignment: Fusion.UsedAs<Enum.ItemLineAlignment>?,
	GrowRatio: Fusion.UsedAs<number>?,
	ShrinkRatio: Fusion.UsedAs<number>?,
}
export type ListProps = {
	Enabled: Fusion.UsedAs<boolean>?,
	Padding: Fusion.UsedAs<UDim>?,
	FillDirection: Fusion.UsedAs<Enum.FillDirection>?,
	SortOrder: Fusion.UsedAs<Enum.SortOrder>?,
	Wraps: Fusion.UsedAs<boolean>?,
	HorizontalAlignment: Fusion.UsedAs<Enum.HorizontalAlignment>?,
	HorizontalFlex: Fusion.UsedAs<boolean>?,
	VerticalAlignment: Fusion.UsedAs<Enum.VerticalAlignment>?,
	VerticalFlex: Fusion.UsedAs<boolean>?,
	ItemLineAlignment: Fusion.UsedAs<Enum.ItemLineAlignment>?,
}
export type GridProps = {
	Enabled: Fusion.UsedAs<boolean>?,
	CellPadding: Fusion.UsedAs<UDim>?,
	CellSize: Fusion.UsedAs<UDim2>?,
	FillDirection: Fusion.UsedAs<Enum.FillDirection>?,
	FillDirectionMaxCells: Fusion.UsedAs<number>?,
	SortOrder: Fusion.UsedAs<Enum.SortOrder>?,
	StartCorner: Fusion.UsedAs<Enum.StartCorner>?,
	HorizontalAlignment: Fusion.UsedAs<Enum.HorizontalAlignment>?,
	VerticalAlignment: Fusion.UsedAs<Enum.VerticalAlignment>?,
}
export type TableProps = {
	Enabled: Fusion.UsedAs<boolean>?,
	Padding: Fusion.UsedAs<UDim>?,
	FillEmptySpaceColumns: Fusion.UsedAs<boolean>?,
	FillEmptySpaceRows: Fusion.UsedAs<boolean>?,
	FillDirection: Fusion.UsedAs<Enum.FillDirection>?,
	SortOrder: Fusion.UsedAs<Enum.SortOrder>?,
	MajorAxis: Fusion.UsedAs<Enum.TableMajorAxis>?,
	HorizontalAlignment: Fusion.UsedAs<Enum.HorizontalAlignment>?,
	VerticalAlignment: Fusion.UsedAs<Enum.VerticalAlignment>?,
}
export type PageProps = {
	Enabled: Fusion.UsedAs<boolean>?,
	Animated: Fusion.UsedAs<boolean>?,
	Circular: Fusion.UsedAs<boolean>?,
	EasingDirection: Fusion.UsedAs<Enum.EasingDirection>?,
	EasingStyle: Fusion.UsedAs<Enum.EasingStyle>?,
	Padding: Fusion.UsedAs<UDim>?,
	TweenTime: Fusion.UsedAs<number>?,
	FillDirection: Fusion.UsedAs<Enum.FillDirection>?,
	SortOrder: Fusion.UsedAs<Enum.SortOrder>?,
	HorizontalAlignment: Fusion.UsedAs<Enum.HorizontalAlignment>?,
	VerticalAlignment: Fusion.UsedAs<Enum.VerticalAlignment>?,
	GamepadInputEnabled: Fusion.UsedAs<boolean>?,
	ScrollWheelInputEnabled: Fusion.UsedAs<boolean>?,
	TouchInputEnabled: Fusion.UsedAs<boolean>?,
}
export type SizeLimitProps = {
	Enabled: Fusion.UsedAs<boolean>?,
	Max: Fusion.UsedAs<Vector2>?,
	Min: Fusion.UsedAs<Vector2>?,
}
export type TextSizeLimitProps = {
	Enabled: Fusion.UsedAs<boolean>?,
	Max: Fusion.UsedAs<number>?,
	Min: Fusion.UsedAs<number>?,
}
export type Props = {
	ClassName: string?,

	Name: Fusion.UsedAs<string>?,
	Parent: Fusion.UsedAs<Instance>?,
	Position: Fusion.UsedAs<UDim2>?,
	Rotation: Fusion.UsedAs<number>?,
	AnchorPoint: Fusion.UsedAs<Vector2>?,
	Size: Fusion.UsedAs<UDim2>?,
	AutomaticSize: Fusion.UsedAs<Enum.AutomaticSize>?,
	Visible: Fusion.UsedAs<boolean>?,
	ZIndex: Fusion.UsedAs<number>?,
	LayoutOrder: Fusion.UsedAs<number>?,
	ClipsDescendants: Fusion.UsedAs<boolean>?,
	Active: Fusion.UsedAs<boolean>?,
	Selectable: Fusion.UsedAs<boolean>?,
	Interactable: Fusion.UsedAs<boolean>?,
	BackgroundColor3: Fusion.UsedAs<Color3>?,
	BackgroundTransparency: Fusion.UsedAs<number>?,
	NextSelectionDown: Fusion.UsedAs<GuiObject>?,
	NextSelectionUp: Fusion.UsedAs<GuiObject>?,
	NextSelectionRight: Fusion.UsedAs<GuiObject>?,
	NextSelectionLeft: Fusion.UsedAs<GuiObject>?,
	SelectionImageObject: Fusion.UsedAs<GuiObject>?,
	SelectionOrder: Fusion.UsedAs<number>?,
	SizeConstraint: Fusion.UsedAs<Enum.SizeConstraint>?,
	AutoLocalize: Fusion.UsedAs<boolean>?,
	RootLocalizationTable: Fusion.UsedAs<LocalizationTable>?,
	SelectionBehaviorDown: Fusion.UsedAs<Enum.SelectionBehavior>?,
	SelectionBehaviorUp: Fusion.UsedAs<Enum.SelectionBehavior>?,
	SelectionBehaviorRight: Fusion.UsedAs<Enum.SelectionBehavior>?,
	SelectionBehaviorLeft: Fusion.UsedAs<Enum.SelectionBehavior>?,
	SelectionGroup: Fusion.UsedAs<boolean>?,

	Corner: CornerProps?,
	Padding: PaddingProps?,
	Stroke: StrokeProps?,
	Gradient: GradientProps?,
	Aspect: AspectProps?,
	Scale: ScaleProps?,

	List: ListProps?,
	Grid: GridProps?,
	Table: TableProps?,
	Page: PageProps?,
	Flex: FlexProps?,

	SizeLimit: SizeLimitProps?,
	TextSizeLimit: TextSizeLimitProps?,
}

return function(Scope: Fusion.Scope<any>, Props: Props): Instance
	local Scope = Fusion.innerScope(Scope, Fusion, Util)
	local Theme = Themer.Theme:now()

	local ClassName = Util.Fallback(Props.ClassName, "Frame")
	local Name = Util.Fallback(Props.Name, "Base")
	local AutomaticSize = Util.Fallback(Props.AutomaticSize, Enum.AutomaticSize.XY)
	local BackgroundColor3 = Util.Fallback(Props.BackgroundColor3, Theme.Colors.Base.Main)
	local Corner = Util.Fallback(Props.Corner, {
		Radius = Scope:UDim(Scope, 0, Theme.CornerRadius["1"]),
	})
	local Stroke = Util.Fallback(Props.Stroke, {
		Thickness = Theme.StrokeThickness["1"],
		Color = Scope:Computed(function(Use)
			return Util.Emphasize(Use(BackgroundColor3), Use(Theme.StrokeEmphasis["Regular"]))
		end),
		ApplyStrokeMode = Enum.ApplyStrokeMode.Border,
		LineJoinMode = Scope:Computed(function(Use)
			local CornerRadiusValue = Use(Use(Corner).Radius)

			if (CornerRadiusValue ~= nil) and ((CornerRadiusValue.Offset > 1) or (CornerRadiusValue.Scale > 1)) then
				return Enum.LineJoinMode.Round
			else
				return Enum.LineJoinMode.Miter
			end
		end),
	})
	local Padding = Util.Fallback(Props.Padding, {
		All = Scope:UDim(0, Theme.Padding["1"]),
	})
	local List = Util.Fallback(Props.List, {
		Padding = Scope:UDim(0, Theme.Padding["1"]),
		SortOrder = Enum.SortOrder.LayoutOrder,
	})
	local Grid = Util.Fallback(Props.Grid, {
		CellPadding = Scope:UDim2Offset(Theme.Padding["1"], Theme.Padding["1"]),
		SortOrder = Enum.SortOrder.LayoutOrder,
	})
	local Table = Util.Fallback(Props.Table, {
		Padding = Scope:UDim2Offset(Theme.Padding["1"], Theme.Padding["1"]),
		SortOrder = Enum.SortOrder.LayoutOrder,
	})
	local Page = Util.Fallback(Props.Page, {
		Padding = Scope:UDim(0, Theme.Padding["1"]),
		SortOrder = Enum.SortOrder.LayoutOrder,
	})

	local PaddingActive = Scope:Computed(function(Use)
		local InProps = Use(Props.Padding) ~= nil
		local PaddingValue = Use(Padding) or {}
		local Paddings =
			{ PaddingValue.All, PaddingValue.Top, PaddingValue.Left, PaddingValue.Right, PaddingValue.Bottom }

		if InProps then
			for _, PaddingProp in Paddings do
				local PaddingPropValue = Use(PaddingProp)

				if typeof(PaddingPropValue) == "UDim" then
					return true
				end
			end
		end

		return false
	end)

	return Scope:New(ClassName) {
		Name = Name,
		AutomaticSize = AutomaticSize,

		Parent = Props.Parent,
		Position = Props.Position,
		Rotation = Props.Rotation,
		AnchorPoint = Props.AnchorPoint,
		Size = Props.Size,
		Visible = Props.Visible,
		ZIndex = Props.ZIndex,
		LayoutOrder = Props.LayoutOrder,
		ClipsDescendants = Props.ClipsDescendants,
		Active = Props.Active,
		Selectable = Props.Selectable,
		Interactable = Props.Interactable,
		BackgroundColor3 = Props.BackgroundColor3,
		BackgroundTransparency = Props.BackgroundTransparency,
		NextSelectionDown = Props.NextSelectionDown,
		NextSelectionUp = Props.NextSelectionUp,
		NextSelectionRight = Props.NextSelectionRight,
		NextSelectionLeft = Props.NextSelectionLeft,
		SelectionImageObject = Props.SelectionImageObject,
		SelectionOrder = Props.SelectionOrder,
		SizeConstraint = Props.SizeConstraint,
		AutoLocalize = Props.AutoLocalize,
		RootLocalizationTable = Props.RootLocalizationTable,
		SelectionBehaviorDown = Props.SelectionBehaviorDown,
		SelectionBehaviorUp = Props.SelectionBehaviorUp,
		SelectionBehaviorRight = Props.SelectionBehaviorRight,
		SelectionBehaviorLeft = Props.SelectionBehaviorLeft,
		SelectionGroup = Props.SelectionGroup,

		[Children] = {
			-- Styling
			Scope:Computed(function(Use)
				local CornerValue: CornerProps = Use(Corner) or {}
				local InProps = Use(Props.Corner) ~= nil

				if InProps and (Use(CornerValue.Enabled) ~= false) then
					return Scope:New "UICorner" {
						CornerRadius = CornerValue.Radius,
					}
				end
			end),
			Scope:Computed(function(Use)
				local PaddingActiveValue = Use(PaddingActive)
				local PaddingValue: PaddingProps = Use(Padding) or {}

				if PaddingActiveValue == true then
					return Scope:New "UIPadding" {
						PaddingTop = Scope:Computed(function(Use)
							local PaddingAllValue = Use(PaddingValue.All)
							local PaddingTopValue = Use(PaddingValue.Top)

							return PaddingTopValue or PaddingAllValue or UDim.new()
						end),
						PaddingBottom = Scope:Computed(function(Use)
							local PaddingAllValue = Use(PaddingValue.All)
							local PaddingBottomValue = Use(PaddingValue.Bottom)

							return PaddingBottomValue or PaddingAllValue or UDim.new()
						end),
						PaddingLeft = Scope:Computed(function(Use)
							local PaddingAllValue = Use(PaddingValue.All)
							local PaddingLeftValue = Use(PaddingValue.Left)

							return PaddingLeftValue or PaddingAllValue or UDim.new()
						end),
						PaddingRight = Scope:Computed(function(Use)
							local PaddingAllValue = Use(PaddingValue.All)
							local PaddingRightValue = Use(PaddingValue.Right)

							return PaddingRightValue or PaddingAllValue or UDim.new()
						end),
					}
				end
			end),
			Scope:Computed(function(Use)
				local StrokeValue: StrokeProps = Use(Stroke) or {}
				local InProps = Use(Props.Stroke) ~= nil

				if InProps and (Use(StrokeValue.Enabled) ~= false) then
					return Scope:New "UIStroke" {
						Enabled = StrokeValue.Enabled,
						Thickness = StrokeValue.Thickness,
						Color = StrokeValue.Color,
						Transparency = StrokeValue.Transparency,
						ApplyStrokeMode = StrokeValue.ApplyStrokeMode,
						LineJoinMode = StrokeValue.LineJoinMode,
						BorderOffset = StrokeValue.Offset,
						BorderStrokePosition = StrokeValue.Position,
						StrokeSizingMode = StrokeValue.SizingMode,
						ZIndex = StrokeValue.ZIndex,

						[Children] = {
							Scope:Computed(function(Use)
								local GradientValue: GradientProps = Use(StrokeValue.Gradient) or {}
								local GradientInProps = StrokeValue.Gradient ~= nil

								if GradientInProps and (Use(GradientValue.Enabled) ~= false) then
									return Scope:New "UIGradient" {
										Enabled = GradientValue.Enabled,
										Color = GradientValue.Color,
										Offset = GradientValue.Offset,
										Rotation = GradientValue.Rotation,
										Transparency = GradientValue.Transparency,
									}
								end
							end),
						},
					}
				end
			end),
			Scope:Computed(function(Use)
				local GradientValue: GradientProps = Use(Props.Gradient) or {}
				local InProps = Use(Props.Gradient) ~= nil

				if InProps and (Use(GradientValue.Enabled) ~= false) then
					return Scope:New "UIGradient" {
						Enabled = GradientValue.Enabled,
						Color = GradientValue.Color,
						Offset = GradientValue.Offset,
						Rotation = GradientValue.Rotation,
						Transparency = GradientValue.Transparency,
					}
				end
			end),

			-- Sizing
			Scope:Computed(function(Use)
				local ScaleValue: ScaleProps = Use(Props.Scale) or {}
				local InProps = Use(Props.Scale) ~= nil

				if InProps and (Use(ScaleValue.Enabled) ~= false) then
					return Scope:New "UIScale" {
						Scale = ScaleValue.Scale,
					}
				end
			end),
			Scope:Computed(function(Use)
				local AspectValue: AspectProps = Use(Props.Aspect) or {}
				local InProps = Use(Props.Aspect) ~= nil

				if InProps and (Use(AspectValue.Enabled) ~= false) then
					return Scope:New "UIAspectRatioConstraint" {
						AspectRatio = AspectValue.Ratio,
						DominantAxis = AspectValue.DominantAxis,
						AspectType = AspectValue.Type,
					}
				end
			end),
			Scope:Computed(function(Use)
				local SizeLimitValue: SizeLimitProps = Use(Props.SizeLimit) or {}

				if
					(Use(SizeLimitValue.Enabled) ~= false) and (Use(SizeLimitValue.Max) ~= nil)
					or (Use(SizeLimitValue.Min) ~= nil)
				then
					return Scope:New "UISizeConstraint" {
						MaxSize = SizeLimitValue.Max,
						MinSize = SizeLimitValue.Min,
					}
				end
			end),
			Scope:Computed(function(Use)
				local TextSizeLimitValue: TextSizeLimitProps = Use(Props.TextSizeLimit) or {}

				if (Use(TextSizeLimitValue.Max) ~= nil) or (Use(TextSizeLimitValue.Min) ~= nil) then
					return Scope:New "UITextSizeConstraint" {
						MaxTextSize = TextSizeLimitValue.Max,
						MinTextSize = TextSizeLimitValue.Min,
					}
				end
			end),

			-- Layout
			Scope:Computed(function(Use)
				local ListValue: ListProps = Use(List) or {}
				local InProps = Use(Props.List) ~= nil

				if InProps and (Use(ListValue.Enabled) ~= false) then
					return Scope:New "UIListLayout" {
						Padding = ListValue.Padding,
						FillDirection = ListValue.FillDirection,
						SortOrder = ListValue.SortOrder,
						Wraps = ListValue.Wraps,
						HorizontalAlignment = ListValue.HorizontalAlignment,
						HorizontalFlex = ListValue.HorizontalFlex,
						ItemLineAlignment = ListValue.ItemLineAlignment,
						VerticalAlignment = ListValue.VerticalAlignment,
						VerticalFlex = ListValue.VerticalFlex,
					}
				end
			end),
			Scope:Computed(function(Use)
				local GridValue = Use(Grid) or {}
				local InProps = Use(Props.Grid) ~= nil

				if InProps and (Use(GridValue.Enabled) ~= false) then
					return Scope:New "UIGridLayout" {
						CellPadding = GridValue.CellPadding,
						CellSize = GridValue.CellSize,
						FillDirection = GridValue.FillDirection,
						FillDirectionMaxCells = GridValue.FillDirectionMaxCells,
						SortOrder = GridValue.SortOrder,
						StartCorner = GridValue.StartCorner,
						HorizontalAlignment = GridValue.HorizontalAlignment,
						VerticalAlignment = GridValue.VerticalAlignment,
					}
				end
			end),
			Scope:Computed(function(Use)
				local TableValue = Use(Table) or {}
				local InProps = Use(Props.Table) ~= nil

				if InProps and (Use(TableValue.Enabled) ~= false) then
					return Scope:New "UITableLayout" {
						Padding = TableValue.Padding,
						FillEmptySpaceColumns = TableValue.FillEmptySpaceColumns,
						FillEmptySpaceRows = TableValue.FillEmptySpaceRows,
						FillDirection = TableValue.FillDirection,
						SortOrder = TableValue.SortOrder,
						MajorAxis = TableValue.MajorAxis,
						HorizontalAlignment = TableValue.HorizontalAlignment,
						VerticalAlignment = TableValue.VerticalAlignment,
					}
				else
					return
				end
			end),
			Scope:Computed(function(Use)
				local PageValue = Use(Page) or {}
				local InProps = Use(Props.Page) ~= nil

				if InProps and (Use(PageValue.Enabled) ~= false) then
					return Scope:New "UIPageLayout" {
						Animated = PageValue.Animated,
						Circular = PageValue.Circular,
						EasingDirection = PageValue.EasingDirection,
						EasingStyle = PageValue.EasingStyle,
						Padding = PageValue.Padding,
						TweenTime = PageValue.TweenTime,
						FillDirection = PageValue.FillDirection,
						SortOrder = PageValue.SortOrder,
						HorizontalAlignment = PageValue.HorizontalAlignment,
						VerticalAlignment = PageValue.VerticalAlignment,
						GamepadInputEnabled = PageValue.GamepadInputEnabled,
						ScrollWheelInputEnabled = PageValue.ScrollWheelInputEnabled,
						TouchInputEnabled = PageValue.TouchInputEnabled,
					}
				end
			end),
			Scope:Computed(function(Use)
				local FlexValue = Use(Props.Flex) or {}
				local InProps = Use(Props.Flex) ~= nil

				if InProps and (Use(FlexValue.Mode) ~= Enum.UIFlexMode.None) then
					return Scope:New "UIFlexItem" {
						FlexMode = FlexValue.Mode,
						ItemLineAlignment = FlexValue.ItemLineAlignment,
						GrowRatio = FlexValue.GrowRatio,
						ShrinkRatio = FlexValue.ShrinkRatio,
					}
				end
			end),

			Props[Children],
		},
	}
end


local OnyxUI = script.Parent.Parent
local Fusion = require(OnyxUI.Parent.Fusion)
local Themer = require(OnyxUI.Themer)
local Util = require(OnyxUI.Util)
local Components = require(OnyxUI.Components)

local Children = Fusion.Children

return {
	story = function(Props)
		local Theme = Themer.Theme:now()
		local Scope = Fusion.innerScope(Props.scope, Fusion, Util, Components)

		Scope:Base {
			Parent = Props.target,
			BackgroundTransparency = 1,
			List = {},
			Padding = {
				All = Scope:UDim(0, Theme.StrokeThickness["1"]),
			},

			[Children] = {
				Scope:Base {
					ClassName = "Frame",
					Size = UDim2.fromOffset(100, 100),
					Corner = {
						-- Enabled = false,
						Radius = UDim.new(0, 100),
					},
					Padding = {
						Left = UDim.new(0, 50),
					},
					Stroke = {
						Thickness = 5,
						Color = Color3.fromRGB(255, 0, 0),
						Offset = UDim.new(0, 5),
						Position = Enum.BorderStrokePosition.Outer,
						SizingMode = Enum.StrokeSizingMode.FixedSize,
						ZIndex = 34,
					},
				},
				Scope:Base {
					ClassName = "Frame",
					AutomaticSize = Enum.AutomaticSize.XY,
					Padding = {
						All = UDim.new(0, 30),
						Left = UDim.new(0, 10),
					},
					List = {
						Padding = UDim.new(0, 15),
					},

					[Children] = {
						Scope:Base {
							ClassName = "TextButton",
							Size = UDim2.fromOffset(200, 50),
							BackgroundColor3 = Color3.fromRGB(255, 0, 0),
							Stroke = {
								Thickness = 3,
								ApplyMode = Enum.ApplyStrokeMode.Border,
								Transparency = 0.5,
								LineJoinMode = Enum.LineJoinMode.Miter,
							},
						},
						Scope:Base {
							ClassName = "TextButton",
							Size = UDim2.fromOffset(200, 50),
							BackgroundColor3 = Color3.fromRGB(255, 0, 0),
							Text = "Button",
							Scale = {
								Scale = 0.95,
							},
							Stroke = {
								Thickness = 3,
								Color = Color3.fromRGB(0, 0, 0),
								ApplyMode = Enum.ApplyStrokeMode.Border,
							},
							Corner = {
								Radius = UDim.new(0, 15),
							},
							Gradient = {
								Color = ColorSequence.new({
									ColorSequenceKeypoint.new(0, Color3.fromRGB(255, 255, 255)),
									ColorSequenceKeypoint.new(1, Color3.fromRGB(0, 0, 0)),
								}),
								Rotation = 90,
								Transparency = NumberSequence.new(0, 0.5),
							},
						},
						Scope:Base {
							ClassName = "TextButton",
							Size = UDim2.fromOffset(200, 50),
							BackgroundColor3 = Color3.fromRGB(255, 0, 0),
							Stroke = {
								Thickness = 3,
								ApplyMode = Enum.ApplyStrokeMode.Border,
							},
							Aspect = {
								Ratio = 1,
								DominantAxis = Enum.DominantAxis.Height,
								AspectType = Enum.AspectType.ScaleWithParentSize,
							},
						},
					},
				},
				Scope:Base {
					ClassName = "Frame",
					Size = UDim2.fromOffset(200, 200),
					BackgroundColor3 = Color3.fromRGB(255, 0, 0),
					Grid = {
						CellSize = UDim2.fromOffset(50, 50),
					},
					Padding = {
						All = UDim.new(0, 10),
					},
					Corner = {
						Radius = UDim.new(0, 10),
					},

					[Children] = {
						Scope:Base {
							ClassName = "Frame",
						},
						Scope:Base {
							ClassName = "Frame",
							Stroke = {
								Color = Color3.fromRGB(0, 0, 255),
								Thickness = 2,
							},
						},
						Scope:Base {
							ClassName = "Frame",
						},
						Scope:Base {
							ClassName = "Frame",
						},
						Scope:Base {
							ClassName = "Frame",
						},
					},
				},
			},
		}
	end,
	fusion = Fusion,
}


--[=[
		@class BaseButton

		A barebones button component, like if Roblox had a "`Button`" class rather than only a `TextButton`.
]=]

--[=[
	@interface BaseButtonProps
	@within BaseButton

	. ... BaseProps -- All Base properties are accepted.
	.Disabled boolean? -- Whether the button is disabled.
	.OnActivate (() -> ())? -- Callback for when the button is activated.
	.OnHover (() -> ())? -- Callback for when the button is hovered over.
	.OnHoverEnd (() -> ())? -- Callback for when the hover ends.
	.OnHold (() -> ())? -- Callback for when the button is held.
	.OnHoldEnd (() -> ())? -- Callback for when the hold ends.
	.Hovering boolean? -- Whether the button is currently being hovered over.
	.Holding boolean? -- Whether the button is currently being held.
	.HoverSound Sound? -- The sound to play when the button is hovered over.
	.ClickSound Sound? -- The sound to play when the button is clicked.
]=]

local SoundService = game:GetService("SoundService")

local OnyxUI = script.Parent.Parent
local Fusion = require(OnyxUI.Parent.Fusion)
local Util = require(OnyxUI.Util)
local Themer = require(OnyxUI.Themer)

local OnEvent = Fusion.OnEvent

local Base = require(script.Parent.Base)
local Components = {
	Base = Base,
}

export type Props = Base.Props & {
	Disabled: Fusion.UsedAs<boolean>?,

	OnActivate: Fusion.UsedAs<() -> ()>?,
	OnHover: Fusion.UsedAs<() -> ()>?,
	OnHoverEnd: Fusion.UsedAs<() -> ()>?,
	OnHold: Fusion.UsedAs<() -> ()>?,
	OnHoldEnd: Fusion.UsedAs<() -> ()>?,

	Hovering: Fusion.UsedAs<boolean>?,
	Holding: Fusion.UsedAs<boolean>?,

	HoverSound: Fusion.UsedAs<Sound>?,
	ClickSound: Fusion.UsedAs<Sound>?,
}

return function(Scope: Fusion.Scope<any>, Props: Props)
	local Scope = Fusion.innerScope(Scope, Fusion, Util, Components)
	local Theme = Themer.Theme:now()

	local Disabled = Util.Fallback(Props.Disabled, false)
	local OnActivate = Util.Fallback(Props.OnActivate, function() end)
	local OnHover = Util.Fallback(Props.OnHover, function() end)
	local OnHoverEnd = Util.Fallback(Props.OnHoverEnd, function() end)
	local OnHold = Util.Fallback(Props.OnHold, function() end)
	local OnHoldEnd = Util.Fallback(Props.OnHoldEnd, function() end)
	local HoverSound = Util.Fallback(Props.HoverSound, Theme.Sound.Hover)
	local ClickSound = Util.Fallback(Props.ClickSound, Theme.Sound.Click)
	local Active = Util.Fallback(
		Props.Active,
		Scope:Computed(function(Use)
			return not Use(Disabled)
		end)
	)
	local Selectable = Util.Fallback(
		Props.Selectable,
		Scope:Computed(function(Use)
			return not Use(Disabled)
		end)
	)

	local Hovering = Scope:EnsureValue(Util.Fallback(Props.Hovering, false))
	local Holding = Scope:EnsureValue(Util.Fallback(Props.Holding, false))

	return Scope:Hydrate(Scope:Base(Util.CombineProps(Props, {
		ClassName = "TextButton",
		Name = script.Name,
		AutomaticSize = Enum.AutomaticSize.XY,
		Selectable = Selectable,
		BackgroundTransparency = 1,
	}))) {
		Text = "",
		RichText = false,
		TextSize = 0,

		[OnEvent "Activated"] = function()
			if not Fusion.peek(Disabled) then
				SoundService:PlayLocalSound(Fusion.peek(ClickSound))

				Fusion.peek(OnActivate)()
			end
		end,
		[OnEvent "MouseEnter"] = function()
			if Fusion.peek(Active) then
				SoundService:PlayLocalSound(Fusion.peek(HoverSound))
			end

			Hovering:set(true)

			Fusion.peek(OnHover)()
		end,
		[OnEvent "SelectionGained"] = function()
			if Fusion.peek(Active) then
				SoundService:PlayLocalSound(Fusion.peek(HoverSound))
			end

			Hovering:set(true)

			Fusion.peek(OnHover)()
		end,
		[OnEvent "SelectionLost"] = function()
			Hovering:set(false)
			Holding:set(false)

			Fusion.peek(OnHoverEnd)()
		end,
		[OnEvent "MouseLeave"] = function()
			Hovering:set(false)
			Holding:set(false)

			Fusion.peek(OnHoverEnd)()
		end,
		[OnEvent "MouseButton1Down"] = function()
			if not Fusion.peek(Disabled) then
				Holding:set(true)

				Fusion.peek(OnHold)()
			end
		end,
		[OnEvent "MouseButton1Up"] = function()
			Holding:set(false)

			Fusion.peek(OnHoldEnd)()
		end,
	}
end


--[=[
		@class Button

		A robust button component, supporting text and icons, and multiple variants.
]=]

--[=[
	@interface ButtonProps
	@within Button

	. ... BaseButtonProps -- All BaseButton properties are accepted.
	.Disabled boolean? -- Whether the button is disabled.
	.Style string? -- The style of the button (e.g., "Filled", "Outlined", "Ghost").
	.Color Color3? -- The background color of the button.
	.Content {string}? -- The content of the button (e.g., text or icons).
	.ContentColor Color3? -- The color of the button's content.
	.ContentSize number? -- The size of the button's content.
	.ContentWrapped boolean? -- Whether the content should wrap.
	.SizeVariant "ExtraSmall" | "Small" | "Medium" | "Large" | "ExtraLarge"? -- The size variant of the button.
	.Holding boolean? -- Whether the button is being held.
	.Hovering boolean? -- Whether the button is being hovered over.
]=]

local OnyxUI = script.Parent.Parent
local Fusion = require(OnyxUI.Parent.Fusion)
local Util = require(OnyxUI.Util)
local Themer = require(OnyxUI.Themer)
local ColorUtils = require(OnyxUI.Parent.ColorUtils)

local Children = Fusion.Children

local BaseButton = require(script.Parent.BaseButton)
local IconText = require(script.Parent.IconText)
local Components = {
	BaseButton = BaseButton,
	IconText = IconText,
}

local DISABLED_BACKGROUND_TRANSPARENCY = 0.925
local DISABLED_CONTENT_TRANSPARENCY = 0.75

export type Props = BaseButton.Props & {
	Disabled: Fusion.UsedAs<boolean>?,
	Style: Fusion.UsedAs<string>?,
	Color: Fusion.UsedAs<Color3>?,
	Content: Fusion.UsedAs<{ string }>?,
	ContentColor: Fusion.UsedAs<Color3>?,
	ContentSize: Fusion.UsedAs<number>?,
	ContentWrapped: Fusion.UsedAs<boolean>?,
	SizeVariant: Fusion.UsedAs<"ExtraSmall" | "Small" | "Medium" | "Large" | "ExtraLarge">?,
	Holding: Fusion.UsedAs<boolean>?,
}

return function(Scope: Fusion.Scope<any>, Props: Props)
	local Scope = Fusion.innerScope(Scope, Fusion, Util, Components)
	local Theme = Themer.Theme:now()

	local SizeVariant = Util.Fallback(Props.SizeVariant, "Medium")
	local Disabled = Util.Fallback(Props.Disabled, false)
	local Content = Util.Fallback(Props.Content, {})
	local Style = Util.Fallback(Props.Style, "Filled")
	local Color = Util.Fallback(Props.Color, Theme.Colors.Neutral.Main)
	local ContentColor = Util.Fallback(
		Props.ContentColor,
		Scope:Computed(function(Use)
			return Util.Emphasize(Use(Color), Use(Theme.Emphasis.Contrast))
		end)
	)
	local ContentSize = Util.Fallback(
		Props.ContentSize,
		Scope:Computed(function(Use)
			local VariantSizes = {
				ExtraSmall = Use(Theme.TextSize["0.875"]),
				Small = Use(Theme.TextSize["1"]),
				Medium = Use(Theme.TextSize["1"]),
				Large = Use(Theme.TextSize["1.25"]),
				ExtraLarge = Use(Theme.TextSize["1.25"]),
			}

			return VariantSizes[Use(SizeVariant)]
		end)
	)
	local ContentWrapped = Util.Fallback(Props.ContentWrapped, false)

	local Hovering = Scope:EnsureValue(Util.Fallback(Props.Hovering, false))
	local Holding = Scope:EnsureValue(Util.Fallback(Props.Holding, false))

	local EffectiveColor = Scope:Computed(function(Use)
		if Use(Disabled) then
			return Use(Theme.Colors.BaseContent.Main)
		else
			local BaseColor = Use(Color)

			if Use(Holding) then
				return Util.Emphasize(BaseColor, Use(Theme.Emphasis.Regular))
			elseif Use(Hovering) then
				return Util.Emphasize(BaseColor, Use(Theme.Emphasis.Light))
			else
				return BaseColor
			end
		end
	end)
	local EffectiveContentColor = Scope:Computed(function(Use)
		if Use(Disabled) then
			return Use(Theme.Colors.BaseContent.Main)
		else
			if Use(Style) == "Filled" then
				return Use(ContentColor)
			elseif Use(Style) == "Outlined" then
				return Use(EffectiveColor)
			elseif Use(Style) == "Ghost" then
				return Use(EffectiveColor)
			else
				return Use(ContentColor)
			end
		end
	end)
	local EffectiveStrokeEmphasis = Scope:Computed(function(Use)
		local StrokeEmphasis = Use(Theme.StrokeEmphasis.Regular)

		if (Use(Style) ~= "Filled") or Use(Disabled) or Use(Hovering) or Use(Holding) then
			return 0
		else
			return StrokeEmphasis
		end
	end)
	local EffectiveContentTransparency = Scope:Computed(function(Use)
		if Use(Disabled) then
			return DISABLED_CONTENT_TRANSPARENCY
		else
			return 0
		end
	end)
	local PaddingX = Scope:Computed(function(Use)
		local VariantSizes = {
			ExtraSmall = Use(Theme.Padding["0.25"]),
			Small = Use(Theme.Padding["0.5"]),
			Medium = Use(Theme.Padding["0.75"]),
			Large = Use(Theme.Padding["1"]),
			ExtraLarge = Use(Theme.Padding["1.5"]),
		}

		return UDim.new(0, VariantSizes[Use(SizeVariant)])
	end)
	local PaddingY = Scope:Computed(function(Use)
		local VariantSizes = {
			ExtraSmall = 0.5,
			Small = 0.75,
			Medium = 1.25,
			Large = 1.5,
			ExtraLarge = 2,
		}

		return UDim.new(0, Use(Theme.Padding["0.25"]) * VariantSizes[Use(SizeVariant)])
	end)

	return Scope:BaseButton(Util.CombineProps(Props, {
		Name = script.Name,
		BackgroundTransparency = Scope:Computed(function(Use)
			if Use(Style) == "Filled" then
				if Use(Disabled) then
					return DISABLED_BACKGROUND_TRANSPARENCY
				else
					return 0
				end
			else
				return 1
			end
		end),
		BackgroundColor3 = Scope:Spring(EffectiveColor, Theme.SpringSpeed["1"], Theme.SpringDampening["1"]),
		Padding = {
			Left = PaddingX,
			Right = PaddingX,
			Top = PaddingY,
			Bottom = PaddingY,
		},
		Corner = {
			Radius = Scope:UDim(0, Theme.CornerRadius["1"]),
		},
		List = {
			FillDirection = Enum.FillDirection.Horizontal,
			HorizontalAlignment = Enum.HorizontalAlignment.Center,
			VerticalAlignment = Enum.VerticalAlignment.Center,
			Wraps = false,
		},
		Stroke = {
			Color = Color3.fromRGB(255, 255, 255),
			Gradient = {
				Color = Scope:Computed(function(Use)
					return ColorSequence.new({
						ColorSequenceKeypoint.new(
							0,
							ColorUtils.Lighten(Use(EffectiveColor), Use(EffectiveStrokeEmphasis))
						),
						ColorSequenceKeypoint.new(1, Use(EffectiveColor)),
					})
				end),
				Rotation = 90,
			},
			Transparency = Scope:Computed(function(Use)
				if Use(Style) == "Ghost" then
					return 1
				elseif Use(Disabled) then
					return DISABLED_BACKGROUND_TRANSPARENCY
				else
					return 0
				end
			end),
		},

		Holding = Holding,
		Hovering = Hovering,

		[Children] = {
			Scope:IconText {
				Content = Content,
				ContentColor = EffectiveContentColor,
				ContentTransparency = EffectiveContentTransparency,
				ContentSize = ContentSize,
				ContentWrapped = ContentWrapped,
				List = {
					Padding = Scope:UDim(0, Theme.Spacing["0.25"]),
					VerticalAlignment = Enum.VerticalAlignment.Center,
					HorizontalAlignment = Enum.HorizontalAlignment.Center,
				},
			},
		},
	}))
end


local OnyxUI = script.Parent.Parent
local Fusion = require(OnyxUI.Parent.Fusion)
local Util = require(OnyxUI.Util)
local Themer = require(OnyxUI.Themer)

local Children = Fusion.Children

local Button = require(script.Parent.Button)
local Frame = require(script.Parent.Frame)
local Divider = require(script.Parent.Divider)
local Components = {
	Button = Button,
	Frame = Frame,
	Divider = Divider,
}

return {
	story = function(Props)
		local Scope = Fusion.innerScope(Props.scope, Fusion, Util, Components)
		local Theme = Themer.Theme:now()

		Scope:Frame {
			Parent = Props.target,
			List = {
				Padding = Scope:UDim(0, Theme.Spacing["0.5"]),
			},
			Padding = {
				All = Scope:UDim(0, Theme.StrokeThickness["1"]),
			},

			[Children] = {
				Scope:Button {
					Content = { "Button" },
				},
				Scope:Button {
					Content = { "Button" },
					Color = Theme.Colors.BaseContent.Main,
				},
				Scope:Button {
					Content = { "Button" },
					Color = Theme.Colors.Primary.Main,
				},
				Scope:Button {
					Content = { "Button" },
					Style = "Outlined",
					Color = Theme.Colors.Primary.Main,
				},
				Scope:Button {
					Content = { "rbxassetid://11560341132", "Purchase" },
					Color = Color3.fromRGB(86, 255, 70),
				},
				Scope:Button {
					Content = { "rbxassetid://13405228418", "Delete" },
					Style = "Outlined",
					Color = Theme.Colors.Error.Main,
				},
				Scope:Button {
					Content = { "Ghost" },
					Style = "Ghost",
					Color = Theme.Colors.BaseContent.Main,
				},
				Scope:Button {
					Content = { "rbxassetid://11560341132", "Bobux" },
					Color = Color3.fromRGB(86, 255, 70),
					Disabled = true,
				},
				Scope:Button {
					Content = { "Testing" },
					Color = Color3.fromRGB(86, 255, 70),
					Disabled = true,
					Style = "Outlined",
				},
				Scope:Divider {},
				Scope:Frame {
					List = {
						FillDirection = Enum.FillDirection.Horizontal,
						VerticalAlignment = Enum.VerticalAlignment.Center,
					},
					Padding = {
						All = Scope:UDim(0, Theme.Padding["1"]),
					},

					[Children] = {
						Scope:Button {
							Content = { "Button (xs)" },
							SizeVariant = "ExtraSmall",
							Color = Theme.Colors.Primary.Main,
						},
						Scope:Button {
							Content = { "Button (sm)" },
							SizeVariant = "Small",
							Color = Theme.Colors.Primary.Main,
						},
						Scope:Button {
							Content = { "Button (md)" },
							SizeVariant = "Medium",
							Color = Theme.Colors.Primary.Main,
						},
						Scope:Button {
							Content = { "Button (lg)" },
							SizeVariant = "Large",
							Color = Theme.Colors.Primary.Main,
						},
						Scope:Button {
							Content = { "Button (xl)" },
							SizeVariant = "ExtraLarge",
							Color = Theme.Colors.Primary.Main,
						},
					},
				},
			},
		}
	end,
	fusion = Fusion,
}


--[=[
		@class Card

		Useful for grouping and displaying Content in a user friendly way.
]=]

--[=[
		@within Card
		@interface CardProps

		. ... FrameProps -- All Frame properties are accepted.
]=]

local OnyxUI = script.Parent.Parent
local Fusion = require(OnyxUI.Parent.Fusion)
local Themer = require(OnyxUI.Themer)
local Util = require(OnyxUI.Util)

local Frame = require(script.Parent.Frame)
local Components = {
	Frame = Frame,
}

export type Props = Frame.Props & {}

return function(Scope: Fusion.Scope<any>, Props: Props)
	local Scope = Fusion.innerScope(Scope, Fusion, Util, Components)
	local Theme = Themer.Theme:now()

	local BackgroundColor3 = Util.Fallback(Props.BackgroundColor3, Theme.Colors.Base.Main)

	return Scope:Frame(Util.CombineProps(Props, {
		Name = script.Name,
		BackgroundColor3 = BackgroundColor3,
		BackgroundTransparency = 0,
		Corner = {
			Radius = Scope:UDim(0, Theme.CornerRadius["1"]),
		},
		Padding = {
			All = Scope:UDim(0, Theme.Padding["1"]),
		},
		Stroke = {
			Color = Scope:Computed(function(Use)
				return Util.Emphasize(Use(BackgroundColor3), Use(Theme.StrokeEmphasis.Light))
			end),
		},
	}))
end


local OnyxUI = script.Parent.Parent
local Fusion = require(OnyxUI.Parent.Fusion)
local Themer = require(OnyxUI.Themer)
local Util = require(OnyxUI.Util)

local Children = Fusion.Children

local Frame = require(OnyxUI.Components.Frame)
local Card = require(OnyxUI.Components.Card)
local Text = require(OnyxUI.Components.Text)
local Divider = require(OnyxUI.Components.Divider)
local Components = {
	Frame = Frame,
	Divider = Divider,
	Text = Text,
	Card = Card,
}

return {
	story = function(Props)
		local Scope = Fusion.innerScope(Props.scope, Fusion, Util, Components)
		local Theme = Themer.Theme:now()

		Scope:Frame {
			Parent = Props.target,
			Size = UDim2.fromOffset(300, 0),
			AutomaticSize = Enum.AutomaticSize.Y,
			List = {
				FillDirection = Enum.FillDirection.Vertical,
				Padding = Scope:UDim(0, Theme.Spacing["0.75"]),
			},

			[Children] = {
				Scope:Card {
					Size = UDim2.new(UDim.new(1, 0), UDim.new(0, 75)),
					AutomaticSize = Enum.AutomaticSize.None,
				},
				Scope:Card {
					Size = UDim2.fromScale(1, 0),
					AutomaticSize = Enum.AutomaticSize.Y,
					List = {
						Padding = Scope:UDim(0, Theme.Spacing["0.5"]),
					},

					[Children] = {
						Scope:Text {
							Text = "Title",
							TextSize = Theme.TextSize["1.25"],
							FontFace = Scope:Font(Theme.Font.Heading, Theme.FontWeight.Heading),
						},
						Scope:Divider {},
						Scope:Text {
							Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.",
						},
					},
				},
			},
		}
	end,
	fusion = Fusion,
}


--[=[
		@class Checkbox

		Useful for settings, to-do lists, and anything needing a "Check!"
]=]

--[=[
	@interface CheckboxProps
	@within Checkbox

	. ... BaseButtonProps -- All BaseButton properties are accepted.
	.Checked boolean? -- Whether the checkbox is checked.
	.Icon string? -- The icon to display inside the checkbox.
	.Color Color3? -- The color of the checkbox.
]=]

local OnyxUI = script.Parent.Parent
local Fusion = require(OnyxUI.Parent.Fusion)
local Util = require(OnyxUI.Util)
local Themer = require(OnyxUI.Themer)
local ColorUtils = require(OnyxUI.Parent.ColorUtils)

local Children = Fusion.Children

local BaseButton = require(script.Parent.BaseButton)
local Icon = require(script.Parent.Icon)
local Components = {
	BaseButton = BaseButton,
	Icon = Icon,
}

export type Props = BaseButton.Props & {
	Checked: Fusion.UsedAs<boolean>?,
	Icon: Fusion.UsedAs<string>?,
	Color: Fusion.UsedAs<Color3>?,
}

local DISABLED_BACKGROUND_TRANSPARENCY = 0.925
local DISABLED_CONTENT_TRANSPARENCY = 0.75

return function(Scope: Fusion.Scope<any>, Props: Props)
	local Scope = Fusion.innerScope(Scope, Fusion, Util, Components)
	local Theme = Themer.Theme:now()

	local Checked = Scope:EnsureValue(Util.Fallback(Props.Checked, false))
	local Disabled = Util.Fallback(Props.Disabled, false)
	local Color = Util.Fallback(Props.Color, Theme.Colors.Primary.Main)
	local IconId = Util.Fallback(Props.Icon, "rbxassetid://13858821963")

	local Hovering = Scope:EnsureValue(Util.Fallback(Props.Hovering, false))
	local Holding = Scope:EnsureValue(Util.Fallback(Props.Holding, false))

	local EffectiveColor = Scope:Computed(function(Use)
		if Use(Disabled) then
			return Use(Theme.Colors.BaseContent.Main)
		else
			if Use(Holding) then
				return Util.Emphasize(Use(Color), Use(Theme.Emphasis.Regular))
			elseif Use(Hovering) then
				return Util.Emphasize(Use(Color), Use(Theme.Emphasis.Light))
			else
				return Use(Color)
			end
		end
	end)
	local EffectiveStrokeEmphasis = Scope:Computed(function(Use)
		local StrokeEmphasis = Use(Theme.StrokeEmphasis.Regular)

		if Use(Disabled) or (not Use(Checked)) or Use(Hovering) or Use(Holding) then
			return 0
		else
			return StrokeEmphasis
		end
	end)

	return Scope:BaseButton(Util.CombineProps(Props, {
		Name = script.Name,
		BackgroundColor3 = EffectiveColor,
		BackgroundTransparency = Scope:Spring(
			Scope:Computed(function(Use)
				if Use(Disabled) then
					return DISABLED_BACKGROUND_TRANSPARENCY
				else
					if Use(Checked) then
						return 0
					else
						return 1
					end
				end
			end),
			Theme.SpringSpeed["1"],
			Theme.SpringDampening["1"]
		),
		Disabled = Disabled,
		Corner = {
			Radius = Scope:UDim(0, Theme.CornerRadius["0.5"]),
		},
		Stroke = {
			Color = Color3.fromRGB(255, 255, 255),
			Gradient = {
				Color = Scope:Computed(function(Use)
					return ColorSequence.new({
						ColorSequenceKeypoint.new(
							0,
							ColorUtils.Lighten(Use(EffectiveColor), Use(EffectiveStrokeEmphasis))
						),
						ColorSequenceKeypoint.new(1, Use(EffectiveColor)),
					})
				end),
				Rotation = 90,
			},
			Transparency = Scope:Computed(function(Use)
				if Use(Disabled) then
					return DISABLED_BACKGROUND_TRANSPARENCY
				else
					return 0
				end
			end),
		},

		Hovering = Hovering,
		Holding = Holding,

		OnActivate = function()
			Checked:set(not Fusion.peek(Checked))
		end,

		[Children] = {
			Scope:Icon {
				Name = "Checkmark",
				Image = IconId,
				ImageTransparency = Scope:Spring(
					Scope:Computed(function(Use)
						if Use(Checked) then
							if Use(Disabled) then
								return DISABLED_CONTENT_TRANSPARENCY
							else
								return 0
							end
						else
							return 1
						end
					end),
					Theme.SpringSpeed["1"],
					Theme.SpringDampening["1"]
				),
				ImageColor3 = Scope:Computed(function(Use)
					return Util.Emphasize(Use(Color), Use(Theme.Emphasis.Contrast))
				end),
				Rotation = Scope:Spring(
					Scope:Computed(function(Use)
						return (Use(Checked) and 0) or -30
					end),
					Theme.SpringSpeed["1"],
					Theme.SpringDampening["1"]
				),
			},
		},
	}))
end


local OnyxUI = script.Parent.Parent
local Fusion = require(OnyxUI.Parent.Fusion)
local Themer = require(OnyxUI.Themer)
local Util = require(OnyxUI.Util)

local Children = Fusion.Children

local Frame = require(OnyxUI.Components.Frame)
local Checkbox = require(OnyxUI.Components.Checkbox)
local Components = {
	Frame = Frame,
	Checkbox = Checkbox,
}

return {
	story = function(Props)
		local Scope = Fusion.innerScope(Props.scope, Fusion, Util, Components)
		local Theme = Themer.Theme:now()

		Scope:Frame {
			Parent = Props.target,
			Padding = {
				All = Scope:UDim(0, Theme.StrokeThickness["1"]),
			},
			List = {
				FillDirection = Enum.FillDirection.Horizontal,
				Padding = Scope:UDim(0, Theme.Spacing["0.5"]),
			},

			[Children] = {
				Scope:Checkbox {},
				Scope:Checkbox {
					Checked = true,
				},
				Scope:Checkbox {
					Disabled = true,
				},
				Scope:Checkbox {
					Disabled = true,
					Checked = true,
				},
				Scope:Checkbox {
					Icon = "rbxassetid://16743550373",
					Color = Util.Colors.Red["500"],
					Checked = true,
				},
			},
		}
	end,
	fusion = Fusion,
}


--[=[
		@class Divider

		Useful for separating UI into sections.
]=]

--[=[
	@interface DividerProps
	@within Divider

	. ... FrameProps -- All Frame properties are accepted.
	.Length UDim -- The length of the divider.
	.FillDirection Enum.FillDirection -- The direction in which the divider fills (Horizontal or Vertical).
	.Color Color3 -- The color of the divider.
	.Transparency number -- The transparency of the divider.
	.Spacing UDim -- The spacing around the divider.
]=]

local OnyxUI = script.Parent.Parent
local Fusion = require(OnyxUI.Parent.Fusion)
local Util = require(OnyxUI.Util)
local Themer = require(OnyxUI.Themer)

local Children = Fusion.Children

local Frame = require(script.Parent.Frame)
local Components = {
	Frame = Frame,
}

export type Props = Frame.Props & {
	Length: Fusion.UsedAs<UDim>?,
	FillDirection: Fusion.UsedAs<Enum.FillDirection>?,
	Color: Fusion.UsedAs<Color3>?,
	Transparency: Fusion.UsedAs<number>?,
	Spacing: Fusion.UsedAs<UDim>?,
}

return function(Scope: Fusion.Scope<any>, Props: Props)
	local Scope = Fusion.innerScope(Scope, Fusion, Util, Components)
	local Theme = Themer.Theme:now()

	local Length = Util.Fallback(Props.Length, UDim.new(1, 0))
	local FillDirection = Util.Fallback(Props.FillDirection, Enum.FillDirection.Horizontal)
	local Color = Util.Fallback(Props.Color, Theme.Colors.BaseContent.Main)
	local Transparency = Util.Fallback(Props.Transparency, 0.9)
	local Spacing = Util.Fallback(Props.Spacing, Scope:UDim(0, Theme.Spacing["0.5"]))

	local VerticalPadding = Scope:Computed(function(Use)
		if Use(FillDirection) == Enum.FillDirection.Horizontal then
			return Use(Spacing)
		else
			return UDim.new()
		end
	end)
	local HorizontalPadding = Scope:Computed(function(Use)
		if Use(FillDirection) == Enum.FillDirection.Vertical then
			return Use(Spacing)
		else
			return UDim.new()
		end
	end)

	return Scope:Frame(Util.CombineProps(Props, {
		Name = script.Name,
		Size = Scope:Computed(function(Use)
			if Use(FillDirection) == Enum.FillDirection.Horizontal then
				return UDim2.new(Length, UDim.new(0, 0))
			else
				return UDim2.new(UDim.new(0, 0), Use(Length))
			end
		end),
		AutomaticSize = Scope:Computed(function(Use)
			if Use(FillDirection) == Enum.FillDirection.Horizontal then
				return Enum.AutomaticSize.Y
			else
				return Enum.AutomaticSize.X
			end
		end),
		Padding = {
			Top = VerticalPadding,
			Bottom = VerticalPadding,
			Left = HorizontalPadding,
			Right = HorizontalPadding,
		},

		[Children] = {
			Scope:Frame {
				Name = "DividingLine",
				Size = Scope:Computed(function(Use)
					if Use(FillDirection) == Enum.FillDirection.Horizontal then
						return UDim2.new(UDim.new(1, 0), UDim.new(0, Use(Theme.StrokeThickness["1"])))
					else
						return UDim2.new(UDim.new(0, Use(Theme.StrokeThickness["1"])), UDim.new(1, 0))
					end
				end),
				AutomaticSize = Enum.AutomaticSize.None,
				BackgroundColor3 = Color,
				BackgroundTransparency = Transparency,
			},
		},
	}))
end


local OnyxUI = script.Parent.Parent
local Util = require(OnyxUI.Util)
local Fusion = require(OnyxUI.Parent.Fusion)
local Themer = require(OnyxUI.Themer)

local Children = Fusion.Children

local Frame = require(OnyxUI.Components.Frame)
local Divider = require(OnyxUI.Components.Divider)
local Text = require(OnyxUI.Components.Text)
local Components = {
	Frame = Frame,
	Text = Text,
	Divider = Divider,
}

return {
	story = function(Props)
		local Scope = Fusion.innerScope(Props.scope, Fusion, Util, Components)
		local Theme = Themer.Theme:now()

		Scope:Frame {
			Parent = Props.target,
			Size = UDim2.fromOffset(300, 0),
			AutomaticSize = Enum.AutomaticSize.Y,
			List = {
				FillDirection = Enum.FillDirection.Vertical,
				Padding = Scope:UDim(0, Theme.Spacing["0.5"]),
			},

			[Children] = {
				Scope:Text {
					Text = "Some top content..",
				},
				Scope:Divider {
					FillDirection = Enum.FillDirection.Horizontal,
				},
				Scope:Text {
					Text = "And some bottom content too.",
				},
			},
		}
	end,
	fusion = Fusion,
}


--[=[
		@class Frame

		A barebones container object. Unlike Roblox's `Frame`, it is transparent by default.
]=]

--[=[
		@within Frame
		@interface FrameProps

		. ... BaseProps -- All Base properties are accepted.
]=]

local OnyxUI = script.Parent.Parent
local Fusion = require(OnyxUI.Parent.Fusion)
local Util = require(OnyxUI.Util)

local Base = require(script.Parent.Base)
local Components = {
	Base = Base,
}

export type Props = Base.Props & {}

return function(Scope: Fusion.Scope<any>, Props: Props)
	local Scope = Fusion.innerScope(Scope, Fusion, Util, Components)

	return Scope:Base(Util.CombineProps(Props, {
		ClassName = "Frame",
		Name = script.Name,
		BackgroundTransparency = 1,
		AutomaticSize = Enum.AutomaticSize.XY,
	}))
end


--[=[
		@class Group

		Equivalent to Roblox's `CanvasGroup` instance.
]=]

--[=[
		@within Group
		@interface GroupProps

		@field ... BaseProps -- All Base properties are accepted.
		@field GroupTransparency Fusion.UsedAs<number>?
		@field GroupColor3 Fusion.UsedAs<Color3>?
]=]

local OnyxUI = script.Parent.Parent
local Util = require(OnyxUI.Util)
local Fusion = require(OnyxUI.Parent.Fusion)

local Base = require(script.Parent.Base)
local Components = {
	Base = Base,
}

export type Props = Base.Props & {
	GroupTransparency: Fusion.UsedAs<number>?,
	GroupColor3: Fusion.UsedAs<Color3>?,
}

return function(Scope: Fusion.Scope<any>, Props: Props)
	local Scope = Fusion.innerScope(Scope, Fusion, Util, Components)

	return Scope:Hydrate(Scope:Base(Util.CombineProps(Props, {
		ClassName = "CanvasGroup",
		Name = script.Name,
		BackgroundTransparency = 1,
		AutomaticSize = Enum.AutomaticSize.XY,
	}))) {
		GroupTransparency = Props.GroupTransparency,
		GroupColor3 = Props.GroupColor3,
	}
end