return {
	NoFill = {
		Disabled = {
			Name = 'NoFill/Disabled',
			IndicatorHeight = 0,
			Fill = "colors/Fill_Color/Subtle/Disabled",
			Indicator = "colors/Fill_Color/Accent/Disabled",
			Stroke = "colors/Fill_Color/Subtle/Disabled",
			Text = "colors/Fill_Color/Text/Disabled"
		},
		Rest = {
			Name = 'NoFill/Rest',
			IndicatorHeight = 0,
			Fill = "colors/Fill_Color/Subtle/Transparent",
			Indicator = "colors/Fill_Color/Accent/Default",
			Stroke = "colors/Fill_Color/Subtle/Transparent",
			Text = "colors/Fill_Color/Text/Primary"
		},
		Hover = {
			Name = 'NoFill/Hover',
			IndicatorHeight = 0,
			Fill = "colors/Fill_Color/Subtle/Secondary",
			Indicator = "colors/Fill_Color/Accent/Default",
			Stroke = "colors/Fill_Color/Subtle/Secondary",
			Text = "colors/Fill_Color/Text/Primary"
		},
		Pressed = {
			Name = 'NoFill/Pressed',
			IndicatorHeight = 10,
			Fill = "colors/Fill_Color/Subtle/Tertiary",
			Indicator = "colors/Fill_Color/Accent/Default",
			Stroke = "colors/Fill_Color/Subtle/Tertiary",
			Text = "colors/Fill_Color/Text/Secondary"
		}
	},
	Fill = {
		Disabled = {
			Name = 'Fill/Disabled',
			IndicatorHeight = 16,
			Fill = "colors/Fill_Color/Subtle/Secondary",
			Indicator = "colors/Fill_Color/Accent/Disabled",
			Stroke = "colors/Fill_Color/Subtle/Secondary",
			Text = "colors/Fill_Color/Text/Disabled"
		},
		Rest = {
			Name = 'Fill/Rest',
			IndicatorHeight = 16,
			Fill = "colors/Fill_Color/Subtle/Secondary",
			Indicator = "colors/Fill_Color/Accent/Default",
			Stroke = "colors/Fill_Color/Subtle/Secondary",
			Text = "colors/Fill_Color/Text/Primary"
		},
		Hover = {
			Name = 'Fill/Hover',
			IndicatorHeight = 16,
			Fill = "colors/Fill_Color/Subtle/Tertiary",
			Indicator = "colors/Fill_Color/Accent/Default",
			Stroke = "colors/Fill_Color/Subtle/Tertiary",
			Text = "colors/Fill_Color/Text/Primary"
		},
		Pressed = {
			Name = 'Fill/Pressed',
			IndicatorHeight = 10,
			Fill = "colors/Fill_Color/Subtle/Secondary",
			Indicator = "colors/Fill_Color/Accent/Secondary",
			Stroke = "colors/Fill_Color/Subtle/Secondary",
			Text = "colors/Fill_Color/Text/Secondary"
		}
	}
}


-- Expander: An expandable list collector

local Winro = script.Parent.Parent.Parent
local Packages = Winro.Parent

local Theme = require(Winro.Theme)
local WithTheme = Theme.WithTheme

local GetTextSize = require(Winro.Utility.GetTextSize)

local Sift = require(Packages.Sift)
local t = require(Packages.t)
local Roact = require(Packages.Roact)
local new = Roact.createElement

local RoundedSurface = require(Winro.App.Surface.RoundedSurface)

local Expander = Roact.PureComponent:extend(script.Name)

Expander.defaultProps = {
	Size = UDim2.new(1, 0, 0, 62), --- @defaultProp
}

function Expander:render()
	local props = self.props

	-- ////////// Expander
	return WithTheme(function(Theme)

		-- ////////// LeftContent/Icon

		local IconImageStyle = props.Icon and Theme[props.Icon]
		local IconStyle = Theme[IconImageStyle and IconImageStyle.Color or 'colors/Fill_Color/Text/Primary']

		local IconImage = props.Icon and new('ImageLabel', {
			AnchorPoint = Vector2.new(0.5, 0.5),
			BackgroundTransparency = 1,
			Image = IconImageStyle.Image,
			ImageColor3 = IconStyle.Color,
			ImageRectOffset = IconImageStyle.ImageRectOffset,
			ImageRectSize = IconImageStyle.ImageRectSize,
			ImageTransparency = IconStyle.Transparency,
			Position = UDim2.fromScale(0.5, 0.5),
			Size = UDim2.fromOffset(IconImageStyle.ImageRectSize.X, IconImageStyle.ImageRectSize.Y),
		}) or nil

		local Icon = IconImage and new('Frame', {
			BackgroundTransparency = 1,
			LayoutOrder = 1,
			Size = UDim2.fromOffset(16, 16),
		}, IconImage)

		-- ////////// LeftContent/Text/Heading

		local HeadingTextStyle = Theme['colors/Fill_Color/Text/Primary']
		local HeadingFontStyle = Theme['fonts/Body']

		local GotHeadingTextSize, HeadingTextSize = GetTextSize(
			props.Heading,
			HeadingFontStyle.Font,
			HeadingFontStyle.Size
		)

		local Heading = props.Heading and new('TextLabel', {
			AutomaticSize = (not GotHeadingTextSize) and Enum.AutomaticSize.XY or Enum.AutomaticSize.None,
			BackgroundTransparency = 1,
			FontFace = HeadingFontStyle.Font,
			LayoutOrder = 1,
			LineHeight = HeadingFontStyle.LineHeight,
			Size = UDim2.fromOffset(HeadingTextSize.X, HeadingTextSize.Y),
			Text = props.Heading,
			TextColor3 = HeadingTextStyle.Color,
			TextTransparency = HeadingTextStyle.Transparency,
			TextSize = HeadingFontStyle.Size,
		}) or nil

		-- ////////// LeftContent/Text/Caption

		local CaptionTextStyle = Theme['colors/Fill_Color/Text/Secondary']
		local CaptionFontStyle = Theme['fonts/Caption']

		local GotCaptionTextSize, CaptionTextSize = GetTextSize(
			props.Caption,
			CaptionFontStyle.Font,
			CaptionFontStyle.Size
		)

		local Caption = props.Caption and new('TextLabel', {
			AutomaticSize = (not GotCaptionTextSize) and Enum.AutomaticSize.XY or Enum.AutomaticSize.None,
			BackgroundTransparency = 1,
			FontFace = CaptionFontStyle.Font,
			LayoutOrder = 2,
			LineHeight = CaptionFontStyle.LineHeight,
			Size = UDim2.fromOffset(CaptionTextSize.X, CaptionTextSize.Y),
			Text = props.Caption,
			TextColor3 = CaptionTextStyle.Color,
			TextTransparency = CaptionTextStyle.Transparency,
			TextSize = CaptionFontStyle.Size,
		}) or nil

		-- ////////// LeftContent/Text

		local Text = new('Frame', {
			AutomaticSize = Enum.AutomaticSize.XY,
			BackgroundTransparency = 1,
			Size = UDim2.fromScale(0, 0),
			LayoutOrder = 2,
		}, {
			Heading = Heading,
			Caption = Caption,

			Layout = new('UIListLayout', {
				FillDirection = Enum.FillDirection.Vertical,
				HorizontalAlignment = Enum.HorizontalAlignment.Left,
				SortOrder = Enum.SortOrder.LayoutOrder,
				VerticalAlignment = Enum.VerticalAlignment.Center,
			}),
		})

		-- ////////// LeftContent

		local LeftContent = new('Frame', {
			AutomaticSize = Enum.AutomaticSize.X,
			BackgroundTransparency = 1,
			Size = UDim2.fromScale(0, 1),
		}, {
			Icon = Icon,
			Text = Text,

			Layout = new('UIListLayout', {
				Padding = UDim.new(0, 16),
				FillDirection = Enum.FillDirection.Horizontal,
				HorizontalAlignment = Enum.HorizontalAlignment.Left,
				SortOrder = Enum.SortOrder.LayoutOrder,
				VerticalAlignment = Enum.VerticalAlignment.Center,
			}),
			Padding = new('UIPadding', {
				PaddingLeft = UDim.new(0, 15),
				PaddingTop = UDim.new(0, 13),
				PaddingBottom = UDim.new(0, 13),
			}),
		})

		-- ////////// RightContent/

		-- ////////// Expander

		local ExpanderStyle = Theme['colors/Fill_Color/Subtle/Tertiary']

		return new(RoundedSurface, {
			BackgroundColor = ExpanderStyle,
			BackgroundTransparency = 0,
			CornerRadius = UDim.new(0, 3),
			Size = props.Size,
			LayoutOrder = 1,
			ShowTopLeftCorner = true,
			ShowTopRightCorner = true,
			ShowBottomLeftCorner = not props.Expanded,
			ShowBottomRightCorner = not props.Expanded,
		}, LeftContent)
	end)
end

return Expander


local Winro = script.Parent.Parent.Parent
local Packages = Winro.Parent

local Sift = require(Packages.Sift)
local Roact = require(Packages.Roact)
local new = Roact.createElement

local Expander = require(script.Parent.Expander)

local ExpanderStory = Roact.PureComponent:extend(script.Name)

function ExpanderStory:render()
	local props = self.props
	local state = self.state

	return new(Expander, Sift.Dictionary.join({
		Expanded = state.Expanded,
		Heading = props.Heading and 'Power button functionality' or nil,
		Caption = props.Caption and 'Adjust what your power buttons control' or nil,
		Icon = props.Icon and 'images/roblox/icons/logo/studiologo/1x',

		[Roact.Event.Activated] = function(...)
			print(...)

			self:setState({
				Expanded = not state.Expanded,
			})
		end,
	}, props.Props))
end

return {
	controls = {
		Icon = true,
		Heading = true,
		Caption = true,
	},
	stories = {
		Expander = function(props)

			return new(ExpanderStory, props.controls)
		end
	}
}


-- Simple divider, with theme

local Winro = script.Parent.Parent.Parent
local Packages = Winro.Parent

local WithTheme = require(Winro.Theme).WithTheme
local Roact = require(Packages.Roact)
local new = Roact.createElement

local ListDivider = Roact.PureComponent:extend(script.Name)

function ListDivider:render()
	local props = self.props

	return WithTheme(function(Theme)
		local DividerStyle = Theme["colors/Stroke_Color/Divider_Stroke/Default"]
		return new('Frame', {
			BackgroundTransparency = 1,
			LayoutOrder = props.LayoutOrder,
			Position = props.Position,
			Size = UDim2.new(
				props.Size.X.Scale,
				props.Size.X.Offset,
				props.Size.Y.Scale,
				props.Size.Y.Offset == 0 and 4 or props.Size.Y.Offset
			),
		}, {
			Divider = new('Frame', {
				AnchorPoint = Vector2.new(0, 1),
				BorderSizePixel = 0,
				BackgroundColor3 = DividerStyle.Color,
				BackgroundTransparency = DividerStyle.Transparency,
				Position = UDim2.new(0, 1, 0.5, 0),
				Size = UDim2.new(1, -2, 0, 1)
			})
		})
	end)
end

return ListDivider


-- ListItem: A list item
-- Assets/Lists & Collections/Lists & Collections/List View/List Item

local Winro = script.Parent.Parent.Parent
local Packages = Winro.Parent

local Theme = require(Winro.Theme)
local WithTheme = Theme.WithTheme
local ApplyDescription = Theme.ApplyDescription
local RegisterStateAction = Theme.RegisterStateAction

local Validators = Winro.Validators
local StyleValidator = require(Validators.StyleValidator)

local Flipper = require(Packages.Flipper)
local Sift = require(Packages.Sift)
local t = require(Packages.t)
local Roact = require(Packages.Roact)
local new = Roact.createElement

local ListRoot = script.Parent
local Descriptions = require(ListRoot.Descriptions.ListItemDescriptions)

local LISTITEM_COLOR_ANIMATION_SPRING_SETTINGS = "styles/AnimationSpringParams/Control/List/ListItem/Color"
local LISTITEM_TRANSPARENCY_ANIMATION_SPRING_SETTINGS = "styles/AnimationSpringParams/Control/List/ListItem/Transparency"
local LISTITEM_INDICATOR_SIZE_ANIMATION_SPRING_SETTINGS = "styles/AnimationSpringParams/Control/List/ListItem/Indicator"

local ListItem = Roact.PureComponent:extend(script.Name)

ListItem.StyleBindings = {
	'Fill',
	'Indicator',
	'Stroke',
	'Text',
}

ListItem.defaultProps = {
	Width = UDim.new(0, 160), --- @defaultProp
	Height = UDim.new(0, 40), --- @defaultProp
	ShowIndicator = true, --- @defaultProp
	Font = "fonts/Body", --- @defaultProp
}

ListItem.validateProps = t.strictInterface({

	--- @prop @optional Selected boolean The ListItem's selected state
	Selected = t.optional(t.boolean),

	--- @prop @optional Size UDim2 The ListItem's size
	Size = t.optional(t.UDim2),

	--- @prop @optional ShowIndicator boolean Determines indicator visability
	ShowIndicator = t.optional(t.boolean),

	--- @prop @optional @style Font string|table The label's font style
	Font = t.optional(StyleValidator),

	--- @prop @optional AnchorPoint Vector2 The ListItem's anchor point
	AnchorPoint = t.optional(t.Vector2),

	--- @prop @optional Disabled boolean Determines if the item is shown as disabled
	Disabled = t.optional(t.boolean),

	--- @prop @optional LayoutOrder number The ListItem's layout order
	LayoutOrder = t.optional(t.number),

	--- @prop @optional Position UDim2 The ListItem's position
	Position = t.optional(t.UDim2),

	--- @prop @optional Width UDim The ListItem's Width @depricated Use Size instead
	Width = t.optional(t.UDim),

	--- @prop @optional Height UDim The ListItem's Height @depricated Use Size instead
	Height = t.optional(t.UDim),

	--- @prop @optional Text string The ListItem's text
	Text = t.optional(t.string),

	--- @prop @optional @style Icon string|table The ListItem's icon
	Icon = t.optional(StyleValidator),

	--- @prop @optional Native table The native props
	Native = t.optional(t.table),

	--- @prop @optional [Roact.Event.Activated] function Roact.Event.Activated
	[Roact.Event.Activated] = t.optional(t.callback),

	--- @prop @optional [Roact.Event.MouseButton1Down] function Roact.Event.MouseButton1Down
	[Roact.Event.MouseButton1Down] = t.optional(t.callback),

	--- @prop @optional [Roact.Event.MouseButton1Up] function Roact.Event.MouseButton1Up
	[Roact.Event.MouseButton1Up] = t.optional(t.callback),

	--- @prop @optional [Roact.Event.MouseEnter] function Roact.Event.MouseEnter
	[Roact.Event.MouseEnter] = t.optional(t.callback),

	--- @prop @optional [Roact.Event.MouseLeave] function Roact.Event.MouseLeave
	[Roact.Event.MouseLeave] = t.optional(t.callback),
})

function ListItem:init()

	-- Indicator size binding
	self.IndicatorHeight, self.SetIndicatorHeight = Roact.createBinding(0)

	-- Create Style Bindings
	for _, StyleBinding in pairs(self.StyleBindings) do
		self[StyleBinding], self['Set' .. StyleBinding] = Roact.createBinding({})
	end

	-- Actions
	RegisterStateAction(self, Roact.Event.Activated, nil)
	RegisterStateAction(self, Roact.Event.MouseButton1Down, 'Pressed')
	RegisterStateAction(self, Roact.Event.MouseButton1Up, 'Hover')
	RegisterStateAction(self, Roact.Event.MouseEnter, 'Hover')
	RegisterStateAction(self, Roact.Event.MouseLeave, 'Rest')

	-- Initial State
	self:setState({
		State = 'Rest'
	})
end

function ListItem:willUnmount()

	-- Clear motors for each style binding
	for _, StyleBinding in pairs(self.StyleBindings) do

		-- Look for a motor
		local Motor = self[StyleBinding .. 'Motor']

		-- Remove motor if found
		if Motor then
			pcall(Motor.Destroy, Motor)
			self[StyleBinding .. 'Motor'] = nil
		end
	end
end

function ListItem:ApplyDescription(Description, Theme)
	local props = self.props
	Description = Sift.Dictionary.copy(Description)

	-- Prop Overrides
	local FillOverride = props.BackgroundColor
	local TextOverride = props.TextColor

	if FillOverride then
		Description.Fill = FillOverride
	end

	if TextOverride then
		Description.Text = TextOverride
	end

	-- Set Indicator Size
	local InitialIndicatorHeight = self.IndicatorHeight:getValue()

	-- Animate
	if InitialIndicatorHeight then

		-- Remove exiting motor
		local Existing = self.IndicatorHeightMotor

		if Existing then
			pcall(Existing.destroy, Existing)
		end

		-- Create a new motor
		local Motor = Flipper.SingleMotor.new(InitialIndicatorHeight)
		self.IndicatorHeightMotor = Motor

		-- Bind
		Motor:onStep(self.SetIndicatorHeight)
		Motor:onComplete(function()
			Motor:destroy()
			self.IndicatorHeightMotor = nil
		end)

		-- Animate
		Motor:setGoal(Flipper.Spring.new(Description.IndicatorHeight,
			Theme[LISTITEM_INDICATOR_SIZE_ANIMATION_SPRING_SETTINGS])
		)
	else
		self.SetIndicatorHeight(Description.IndicatorHeight)
	end

	ApplyDescription(self, Description, Theme, LISTITEM_COLOR_ANIMATION_SPRING_SETTINGS, LISTITEM_TRANSPARENCY_ANIMATION_SPRING_SETTINGS)
end

function ListItem:render()
	local props = self.props
	local state = self.state

	return WithTheme(function(Theme)

		-- Apply Description
		if not props.Selected then
			if props.Disabled then
				self:ApplyDescription(Descriptions.NoFill.Disabled, Theme)
			elseif state.State == 'Rest' then
				self:ApplyDescription(Descriptions.NoFill.Rest, Theme)
			elseif state.State == 'Hover' then
				self:ApplyDescription(Descriptions.NoFill.Hover, Theme)
			else
				self:ApplyDescription(Descriptions.NoFill.Pressed, Theme)
			end
		else
			if props.Disabled then
				self:ApplyDescription(Descriptions.Fill.Disabled, Theme)
			elseif state.State == 'Rest' then
				self:ApplyDescription(Descriptions.Fill.Rest, Theme)
			elseif state.State == 'Hover' then
				self:ApplyDescription(Descriptions.Fill.Hover, Theme)
			else
				self:ApplyDescription(Descriptions.Fill.Pressed, Theme)
			end
		end

		-- ///////// ListItem Label

		local LabelFontStyle = Theme[props.Font]

		local Label = new('TextLabel', {
			AnchorPoint = Vector2.new(0, 0.5),
			BackgroundTransparency = 1,
			FontFace = LabelFontStyle.Font,
			Position = UDim2.new(0, 16 + (props.Icon and 28 or 0), 0.5, 0),
			Size = UDim2.new(0, 10, 1, 0),
			Text = props.Text,
			TextSize = LabelFontStyle.Size,
			TextXAlignment = 'Left',

			TextColor3 = self.Text:map(function(Style)
				return Style.Color
			end),
			TextTransparency = self.Text:map(function(Style)
				return Style.Transparency
			end),
		})

		-- ////////// ListItem Indicator

		local Indicator = new('Frame', {
			Visible = props.ShowIndicator,
			AnchorPoint = Vector2.new(0, 0.5),
			BorderSizePixel = 0,
			Position = UDim2.new(0, 5, 0.5, 0),

			BackgroundColor3 = self.Indicator:map(function(Style)
				return Style.Color
			end),
			BackgroundTransparency = self.Indicator:map(function(Style)
				return Style.Transparency
			end),
			Size = self.IndicatorHeight:map(function(Height)
				return UDim2.fromOffset(3, Height)
			end),
		}, {

			Corners = new('UICorner', {
				CornerRadius = UDim.new(1, 0)
			}),
		})

		-- ////////// ListItem Base

		local Base = new('ImageButton', {
			AnchorPoint = Vector2.new(0, 0.5),
			AutoButtonColor = false,
			Size = UDim2.new(1, -(4 * 2), 1, -(2 * 2)) - UDim2.fromOffset(2, 2), -- Account for stroke thickness
			Position = UDim2.new(0, 4, 0.5, 0) + UDim2.fromOffset(1, 0), -- Accont for stroke thickness

			BackgroundColor3 = self.Fill:map(function(Style)
				return Style.Color
			end),
			BackgroundTransparency = self.Fill:map(function(Style)
				return Style.Transparency
			end),

			[Roact.Event.Activated] = self[Roact.Event.Activated],
			[Roact.Event.MouseButton1Down] = self[Roact.Event.MouseButton1Down],
			[Roact.Event.MouseButton1Up] = self[Roact.Event.MouseButton1Up],
			[Roact.Event.MouseEnter] = self[Roact.Event.MouseEnter],
			[Roact.Event.MouseLeave] = self[Roact.Event.MouseLeave],
		}, {

			Corners = new('UICorner', {
				CornerRadius = UDim.new(0, Theme['styles/CornerRadius/Default/Inner'] - 1) -- Account for 1px added by stroke
			}),
			Stroke = new('UIStroke', {
				Thickness = 1,
				Color = self.Stroke:map(function(Style)
					return Style.Color
				end),
				Transparency = self.Stroke:map(function(Style)
					return Style.Transparency
				end)
			})
		})

		-- ////////// ListItem Icon

		local IconImage = props.Icon and Theme[props.Icon]
		local IconImageSize = nil

		if IconImage then
			local IconImageRectSize = IconImage.ImageRectSize == Vector2.new() and Vector2.new(16, 16) or IconImage.ImageRectSize
			IconImageSize = UDim2.fromOffset(
				math.clamp(IconImageRectSize.X, 0, 9*4),
				math.clamp(IconImageRectSize.Y, 0, 9*4)
			)
		else
			IconImageSize = UDim2.fromOffset(16, 16)
		end

		local IconImage = IconImage and new('ImageLabel', {
			AnchorPoint = Vector2.new(0.5, 0.5),
			BackgroundTransparency = 1,
			Image = IconImage.Image,
			ImageRectOffset = IconImage.ImageRectOffset,
			ImageRectSize = IconImage.ImageRectSize,
			Position = UDim2.fromScale(0.5, 0.5),
			ResampleMode = IconImage.ResampleMode,
			Size = IconImageSize,

			ImageColor3 = self.Text:map(function(Style)
				return Style.Color
			end),
			ImageTransparency = self.Text:map(function(Style)
				return Style.Transparency
			end),
		})

		local Icon = new('Frame', {
			AnchorPoint = Vector2.new(0.5, 0.5),
			BackgroundTransparency = 1,
			Position = UDim2.new(0, 16 + 8, 0.5, 0),
			Size = UDim2.new(0, 0, 1, 0),
		}, IconImage)

		return new('Frame', Sift.Dictionary.join({
			AnchorPoint = props.AnchorPoint,
			BackgroundTransparency = 1,
			Position = props.Position,
			Size = props.Size or UDim2.new(props.Width.Scale, props.Width.Offset, props.Height.Scale, props.Height.Offset),
			LayoutOrder = props.LayoutOrder
		}), {
			Text = Label,
			Indicator = Indicator,
			Base = Base,
			Icon = Icon
		})
	end)
end

return ListItem


local Winro = script.Parent.Parent.Parent
local Packages = Winro.Parent

local Theme = require(Winro.Theme)
local WithTheme = Theme.WithTheme

local FrameVisualizer = require(Winro.Utility.FrameVisualizer)

local Sift = require(Packages.Sift)
local Roact = require(Packages.Roact)
local new = Roact.createElement

local ListRoot = script.Parent
local ListItem = require(ListRoot.ListItem)

local BORDER_PADDING = UDim.new(0, 8)

local ListItemStory = Roact.PureComponent:extend(script.Name)

function ListItemStory:render()
	local props = self.props

	return WithTheme(function(Theme)
		local Element = new('Frame', {
			BackgroundTransparency = props.BackgroundTransparency,
			BackgroundColor3 = Theme['colors/Background/Fill_Color/Solid_Background/Base'].Color,
			AutomaticSize = 'XY',
			Size = UDim2.fromOffset(160+16, 40+16)
		}, {
			Padding = new('UIPadding', {
				PaddingBottom = BORDER_PADDING,
				PaddingLeft = BORDER_PADDING,
				PaddingRight = BORDER_PADDING,
				PaddingTop = BORDER_PADDING,
			}),
			ListItem = new(ListItem, {
				Icon = props.Icon and 'images/roblox/icons/logo/studiologo_small/1x' or nil,
				AnchorPoint = Vector2.new(0, 0),
				Disabled = props.Disabled,
				Position = UDim2.fromScale(0, 0),
				Selected = self.state.Selected,
				[Roact.Event.Activated] = function(...)
					print(...)
					self:setState({
						Selected = not self.state.Selected
					})
				end
			})
		})

		if props.FrameVisualizer then
			return new(FrameVisualizer, {}, Element)
		else
			return Element
		end
	end)
end

return {
	controls = {
		Disabled = false,
		FrameVisualizer = false,
		Icon = true,
	},
	stories = {
		Button = function (props)
			return Roact.createFragment({
				OnBackground = new(ListItemStory, Sift.Dictionary.join({
					BackgroundTransparency = 0,
				}, props.controls)),
				NoBackground = new(ListItemStory, Sift.Dictionary.join({
					BackgroundTransparency = 1,
				}, props.controls))
			})
		end
	}
}


-- ContextMenu: A Context menu element

local Winro = script.Parent.Parent.Parent
local Packages = Winro.Parent

local Theme = require(Winro.Theme)
local WithTheme = Theme.WithTheme

local Validators = Winro.Validators
local StyleValidator = require(Validators.StyleValidator)

local t = require(Packages.t)
local Roact = require(Packages.Roact)
local new = Roact.createElement

local ListDivider = require(Winro.App.List.ListDivider)
local ListItem = require(Winro.App.List.ListItem)

local Acrylic = require(Winro.App.Surface.Acrylic)

local CONTEXTMENU_BACKGROUND_STYLE = "colors/Background/Fill_Color/Acrylic_Background/Default"
local CONTEXTMENU_BORDER_STYLE = "colors/Stroke_Color/Surface_Stroke/Flyout"

local ContextMenu = Roact.PureComponent:extend(script.Name)

ContextMenu.defaultProps = {
	AnchorPoint = Vector2.new(), --- @defaultProp
	Position = UDim2.new(), --- @defaultProp
	Size = UDim2.fromOffset(150, 150), --- @defaultProp
	FitContents = true, --- @defaultProp
}

ContextMenu.validateProps = t.strictInterface({

	--- @prop @optional AnchorPoint Vector2 The Context Menu's anchor point
	AnchorPoint = t.optional(t.Vector2),

	--- @prop @optional BackgroundTransparency number Background Transparency
	BackgroundTransparency = t.optional(t.number),

	--- @prop @optional Position UDim2 The Context Menu's position
	Position = t.optional(t.UDim2),

	--- @prop @optional Size UDim2 The Context Menu's size
	Size = t.optional(t.UDim2),

	--- @prop @optional UseIcon boolean Determines the visibility of an icon on each option
	UseIcon = t.optional(t.boolean),

	--- @prop @optional FitContents boolean Determines if the Context Menu will resize to fit it's contents
	FitContents = t.optional(t.boolean),

	--- @prop Options array The options to display
	Options = t.array(t.strictInterface({
		Disabled = t.optional(t.boolean),
		IsDivider = t.optional(t.boolean),
		LayoutOrder = t.optional(t.numberPositive),
		OnClicked = t.optional(t.callback),
		Selected = t.optional(t.boolean),
		Text = t.optional(t.string),
		Icon = t.optional(StyleValidator)
	}))
})

function ContextMenu:init()

	-- Content size binding
	self.ContentSize, self.SetContentSize = Roact.createBinding(self.props.Size)
end

function ContextMenu:GetOptions()
	local props = self.props

	-- Create a list of all options to display
	local Children = {}

	-- Go through each option, creating it
	for LayoutOrder, OptionProps in pairs(props.Options) do

		-- Create divider, if set
		if OptionProps.IsDivider then
			Children[LayoutOrder] = new(ListDivider, {
				LayoutOrder = OptionProps.LayoutOrder or LayoutOrder,
				Size = UDim2.fromScale(1, 0)
			})

		-- Create list items
		else
			Children[LayoutOrder] = new(ListItem, {
				ShowIndicator = OptionProps.Selected,
				Disabled = OptionProps.Disabled,
				LayoutOrder = OptionProps.LayoutOrder or LayoutOrder,
				[Roact.Event.Activated] = OptionProps.OnClicked,
				Selected = OptionProps.Selected,
				Width = UDim.new(1, 0),
				Text = OptionProps.Text,
				Icon = props.UseIcon and (OptionProps.Icon or {
					Image = '',
					ImageRectSize = Vector2.new(),
					ImageRectOffset = Vector2.new()
				}) or nil
			})
		end
	end

	return Roact.createFragment(Children)
end

function ContextMenu:render()
	local props = self.props

	return WithTheme(function(Theme)

		-- Create a list items container
		local Container = new('Frame', {
			AutomaticSize = props.FitContents and 'Y' or 'None',
			BackgroundTransparency = 1,
			Position = UDim2.fromOffset(0, 2),
			Size = UDim2.fromScale(1, props.FitContents and 0 or 1),

			[Roact.Change.AbsoluteSize] = function(rbx)
				if props.FitContents then
					self.SetContentSize(UDim2.fromOffset(rbx.AbsoluteSize.X, rbx.AbsoluteSize.Y + 2 * 2)) -- Accont for Vertical padding
				end
			end
		}, {

			Layout = new('UIListLayout', {
				SortOrder = Enum.SortOrder.LayoutOrder,
				FillDirection = Enum.FillDirection.Vertical,
				HorizontalAlignment = Enum.HorizontalAlignment.Center,
				VerticalAlignment = Enum.VerticalAlignment.Bottom
			}),

			Contents = self:GetOptions()
		})

		local BaseStyle = Theme[CONTEXTMENU_BACKGROUND_STYLE]
		local StrokeStyle = Theme[CONTEXTMENU_BORDER_STYLE]

		local Base = new(Acrylic, {
			BackgroundColor3 = BaseStyle.Color,
			BackgroundTransparency = props.BackgroundTransparency or BaseStyle.Transparency,
			BorderSizePixel = 0,
			Size = self.ContentSize,
		}, {

			Corners = new('UICorner', {
				CornerRadius = UDim.new(0, Theme['styles/CornerRadius/Default/Outer'] - 1), -- -1px to account for stroke
			}),

			Stroke = new('UIStroke', {
				Color = StrokeStyle.Color,
				Transparency = StrokeStyle.Transparency,
				Thickness = 1
			}),
		})

		return new('Frame', {
			AutomaticSize = props.FitContents and 'Y' or 'None',
			AnchorPoint = props.AnchorPoint,
			BackgroundTransparency = 1,
			Position = props.Position,
			Size = self.ContentSize
		}, {
			Container = Container,
			Base = Base,
		})
	end)
end

return ContextMenu


local Winro = script.Parent.Parent.Parent
local Packages = Winro.Parent

local Sift = require(Packages.Sift)
local Roact = require(Packages.Roact)
local new = Roact.createElement

local FrameVisualizer = require(Winro.Utility.FrameVisualizer)
local ContextMenu = require(script.Parent.ContextMenu)

local ContextMenuStory = Roact.PureComponent:extend(script.Name)

function ContextMenuStory:render()
	local Element = new(ContextMenu, Sift.Dictionary.join({
		Size = UDim2.new(0, 200, 0, 0),
		FitContents = true,
		UseIcon = self.props.Icon,
		Options = {
			{
				Selected = true,
				Text = 'Selected',
				Icon = 'images/roblox/icons/actions/randomize/1x',
				OnClicked = print
			},
			{
				Selected = false,
				Text = 'Deselected',
				Icon = 'images/roblox/icons/controls/keys/command/1x',
				OnClicked = print
			},
			{ IsDivider = true },
			{
				Disabled = true,
				Text = 'Disabled',
				Icon = 'images/roblox/icons/controls/keys/alt/1x',
				OnClicked = print
			},
			{
				Selected = true,
				Disabled = true,
				Text = 'DisabledSelected',
				Icon = 'images/roblox/icons/graphic/blocktheft_2xl/1x',
				OnClicked = print
			},
			{
				Selected = false,
				Text = 'No icon',
				OnClicked = print
			},
			{ IsDivider = true },
			{
				Selected = true,
				Text = 'No icon selected',
				OnClicked = print
			},
		}
	}, self.props.Props))

	if self.props.Wireframe then
		return new(FrameVisualizer, {}, Element)
	else
		return Element
	end
end

return {
	controls = {
		Wireframe = false,
		Icon = true,
	},
	stories = {
		ContextMenu = function (props)
			return new(ContextMenuStory, props.controls)
		end
	}
}


local Winro = script.Parent.Parent.Parent
local Packages = Winro.Parent

local Sift = require(Packages.Sift)
local Roact = require(Packages.Roact)
local new = Roact.createElement

local RadialProgressBar = require(script.Parent.RadialProgressBar)
local RadialProgressBarStory = Roact.PureComponent:extend(script.Name)

function RadialProgressBarStory:render()
	local props = self.props

	return new(RadialProgressBar, Sift.Dictionary.join({
		--StartValue = props.Start,
		Clockwise = props.Clockwise,
		Value = props.End,
	}, props.Props))
end

return {
	controls = {
		Clockwise = false,
		End = 0.5,
	},
	stories = {
		ClockwiseRadialProgressBar = function(props)
			props.controls.Clockwise = true
			return new(RadialProgressBarStory, props.controls)
		end,
		ConterClockwiseRadialProgressBar = function(props)
			props.controls.Clockwise = false
			return new(RadialProgressBarStory, props.controls)
		end
	},
}


-- Acrylic: The acrylic surface

local Winro = script.Parent.Parent.Parent
local Packages = Winro.Parent

local Sift = require(Packages.Sift)
local Roact = require(Packages.Roact)
local new = Roact.createElement

local WithTheme = require(Winro.Theme).WithTheme

local ACRYLIC_TEXTURE_STYLE = 'images/Texture/Effect/Acrylic'

local Acrylic = Roact.PureComponent:extend(script.Name)

function Acrylic:render()

	-- Use the acrylic styling
	return WithTheme(function(Theme)

		-- Get the acrylic texture
		local Texture = Theme[ACRYLIC_TEXTURE_STYLE]

		return new('ImageLabel', Sift.Dictionary.join({
			BackgroundTransparency = 0.5,
			Image = Texture.Image,
			ImageRectOffset = Texture.ImageRectOffset,
			ImageRectSize = Texture.ImageRectSize,
			ImageTransparency = Texture.ImageTransparency,
			ScaleType = Texture.ScaleType,
			TileSize = Texture.TileSize
		}, self.props))
	end)
end

return Acrylic


-- RoundedSurface: A rounded surface with individual corner visibility support

local Winro = script.Parent.Parent.Parent
local Packages = Winro.Parent

local Theme = require(Winro.Theme)
local WithTheme = Theme.WithTheme

local Validators = Winro.Validators
local StyleValidator = require(Validators.StyleValidator)

local Sift = require(Packages.Sift)
local t = require(Packages.t)
local Roact = require(Packages.Roact)
local new = Roact.createElement

local DEFAULT_CORNER_RADIUS = UDim.new(0, 5)

local RoundedSurface = Roact.PureComponent:extend(script.Name)

RoundedSurface.Corners = {
	TopLeft = 'TopLeft',
	TopRight = 'TopRight',
	BottomLeft = 'BottomLeft',
	BottomRight = 'BottomRight',
}

RoundedSurface.defaultProps = {
	Size = UDim2.fromScale(1, 1), --- @defaultProp
	BackgroundTransparency = 0, --- @defaultProp
	CornerRadius = DEFAULT_CORNER_RADIUS, --- @defaultProp
	ShowTopLeftCorner = false, --- @defaultProp
	ShowTopRightCorner = false, --- @defaultProp
	ShowBottomLeftCorner = false, --- @defaultProp
	ShowBottomRightCorner = false, --- @defaultProp
}

RoundedSurface.validateProps = t.strictInterface({

	--- @prop @optional AnchorPoint Vector2 The Frame's anchor point
	AnchorPoint = t.optional(t.Vector2),

	--- @prop @optional AutomaticSize Enum.AutomaticSize The Frame's autmatic size
	AutomaticSize = t.optional(t.enum(Enum.AutomaticSize)),

	--- @prop @optional @style BackgroundColor string|table Style
	BackgroundColor = t.optional(StyleValidator),

	--- @prop @optional BackgroundColor3 Color3 Background Color
	BackgroundColor3 = t.optional(t.Color3),

	--- @prop @optional BackgroundTransparency number positive Background Transparency
	BackgroundTransparency = t.optional(t.number),

	--- @prop @optional BorderSizePixel number Border thickness, in pixels
	BorderSizePixel = t.optional(t.number),

	--- @prop @optional LayoutOrder number The Surface's layout order
	LayoutOrder = t.optional(t.number),

	--- @prop @optional ShowTopLeftCorner boolean Determines the visibility status of the TopLeft Corner
	ShowTopLeftCorner = t.optional(t.boolean),

	--- @prop @optional ShowTopRightCorner boolean Determines the visibility status of the TopRight Corner
	ShowTopRightCorner = t.optional(t.boolean),

	--- @prop @optional ShowBottomLeftCorner boolean Determines the visibility status of the BottomLeft Corner
	ShowBottomLeftCorner = t.optional(t.boolean),

	--- @prop @optional ShowBottomRightCorner boolean Determines the visibility status of the BottomRight Corner
	ShowBottomRightCorner = t.optional(t.boolean),

	--- @prop @optional CornerRadius UDim The corner radius
	CornerRadius = t.optional(t.UDim),

	--- @prop @optional Position UDim2 The Frame's position
	Position = t.optional(t.UDim2),

	--- @prop @optional Size UDim2 The Frame's size
	Size = t.optional(t.UDim2),

	--- @prop @optional Native table {property:value} The native props for the Frame's main element
	Native = t.optional(t.table),

	--- @prop @optional [Roact.Change.AbsoluteSize] function Roact.Change.AbsoluteSize
	[Roact.Change.AbsoluteSize] = t.optional(t.callback),

	--- @prop @optional [Roact.Children] table The Frame's contents
	[Roact.Children] = t.optional(t.table),
})

function RoundedSurface:CreateCornerFilling(Corner, Theme)
	local props = self.props
	local state = self.state

	local Radius = self.props.CornerRadius
	local AnchorPoint, Position = nil, nil

	-- Calculate the size
	local Size = UDim2.new(Radius.Scale, Radius.Offset, Radius.Scale, Radius.Offset)

	if Corner == self.Corners.TopLeft then
		AnchorPoint = Vector2.new(0, 0)
		Position = UDim2.fromScale(0, 0)

	elseif Corner == self.Corners.TopRight then
		AnchorPoint = Vector2.new(1, 0)
		Position = UDim2.fromScale(1, 0)

	elseif Corner == self.Corners.BottomLeft then
		AnchorPoint = Vector2.new(0, 1)
		Position = UDim2.fromScale(0, 1)

	elseif Corner == self.Corners.BottomRight then
		AnchorPoint = Vector2.new(1, 1)
		Position = UDim2.fromScale(1, 1)

	end

	local FillStyle = Theme[props.BackgroundColor or {
		Color = props.BackgroundColor3,
		Transparency = props.BackgroundTransparency,
	}]

	return new('Frame', {
		AnchorPoint = AnchorPoint,
		BackgroundColor3 = (not state.FallbackMode) and Color3.new(1, 1, 1) or FillStyle.Color,
		BackgroundTransparency = state.FallbackMode and FillStyle.Transparency or nil,
		BorderSizePixel = 0,
		Position = Position,
		Size = Size,
	})
end

function RoundedSurface:init()
	local props = self.props

	-- Content size binding
	self.Size, self.SetSize = Roact.createBinding(UDim2.fromScale(0, 0))

	-- Update size and call prop
	self[Roact.Change.AbsoluteSize] = function(rbx, ...)

		local AbsoluteSize = rbx.AbsoluteSize

		self.SetSize(UDim2.fromOffset(AbsoluteSize.X, AbsoluteSize.Y))

		local PropCallback = props[Roact.Change.AbsoluteSize]

		if PropCallback then
			task.spawn(PropCallback, rbx, ...)
		end
	end
end

function RoundedSurface:render()
	local props = self.props
	local state = self.state

	return WithTheme(function(Theme)

		-- ////////// Corner Fillings

		-- Gather corner fillings
		local CornerFillings = {}

		for _, Corner in pairs(self.Corners) do
			local CornerVisibility = props['Show' .. Corner .. 'Corner']

			if not CornerVisibility then
				CornerFillings[Corner .. 'CornerFilling'] = self:CreateCornerFilling(Corner, Theme)
			end
		end

		-- ////////// Rounded frame

		local FillStyle = Theme[props.BackgroundColor or {
			Color = props.BackgroundColor3,
			Transparency = props.BackgroundTransparency,
		}]

		local RoundedFrame = new('Frame', {
			Size = self.Size,
			BackgroundColor3 = state.FallbackMode and FillStyle.Color or Color3.new(1, 1, 1),
			BorderSizePixel = props.BorderSizePixel,
			BackgroundTransparency = state.FallbackMode and FillStyle.Transparency or 0,
		}, {
			CornerFillings = Roact.createFragment(CornerFillings),

			Corners = new('UICorner', {
				CornerRadius = props.CornerRadius,
			}),
		})

		-- ////////// Rounded Filling

		local RoundedFilling = new((not state.FallbackMode) and 'CanvasGroup' or 'Frame', {
			GroupColor3 = (not state.FallbackMode) and FillStyle.Color or nil,
			GroupTransparency = (not state.FallbackMode) and FillStyle.Transparency or nil,
			BackgroundTransparency = 1,
			Size = self.Size,
			ZIndex = 1,

			-- Determine fallback mode, as CanvasGroup instances only work under a ScreenGui with ZIndexBehavior set to Sibling
			[Roact.Ref] = function (rbx: CanvasGroup | Frame)

				if self.DeterminedFallback then
					return
				end

				if rbx then

					task.spawn(function()

						task.wait(0.1)

						local Gui = rbx:FindFirstAncestorWhichIsA('LayerCollector') or rbx:FindFirstAncestorWhichIsA('PluginGui')

						self.DeterminedFallback = true

						if not Gui then
							self:setState({
								FallbackMode = true
							})

							warn(
								'[Winro Component Library]: The Component Winro.App.Surface.RoundedSurface must be the descendant of a ScreenGui in order to function correctly.'
								.. '\nDue to not being a descendant of a ScreenGui, rounded corners are being rendered in Fallback mode and may not display correctly.'
							)

							return
						end

						if Gui.ZIndexBehavior ~= Enum.ZIndexBehavior.Sibling then

							-- -- Automatically resolve on storybook
							-- if Gui.Name:lower():find('storybook') then
							-- 	Gui.ZIndexBehavior = Enum.ZIndexBehavior.Sibling

							-- 	self:setState({
							-- 		FallbackMode = Roact.None,
							-- 	})

							-- 	return
							-- end

							self:setState({
								FallbackMode = true,
							})

							warn(
								'[Winro Component Library]: The Component Winro.App.Surface.RoundedSurface must be the descendant of a ScreenGui with ZIndexBehavior set to Enum.ZIndexBehavior.Sibling in order to function correctly.'
								.. '\nDue to ZIndexBehavior not being set to Enum.ZIndexBahavior.Sibling, rounded corners are being rendered in Fallback mode and may not display correctly.'
								.. '\nPlease set the ScreenGui\'s ZIndexBehaviour property to Enum.ZIndexBehavior.Sibling in order to resolve this issue.'
							)

							return
						end

						-- Disable fallback mode
						self:setState({
							FallbackMode = Roact.None,
						})
					end)
				end
			end
		}, {
			RoundedFrame = RoundedFrame
		})

		-- ////////// Content Wrapper

		local ContentWrapper = new('Frame', {
			AutomaticSize = props.AutomaticSize,
			BackgroundTransparency = 1,
			Size = props.Size,
			ZIndex = 2,

			[Roact.Change.AbsoluteSize] = self[Roact.Change.AbsoluteSize],
		}, props[Roact.Children])

		-- ////////// Rounded Surface
		return new('Frame', Sift.Dictionary.join({
			AutomaticSize = props.AutomaticSize,
			BackgroundTransparency = 1,
			LayoutOrder = props.LayoutOrder,
			Size = props.Size,
			Position = props.Position,
			AnchorPoint = props.AnchorPoint,
		}, props.Native), {
			ContentWrapper = ContentWrapper,
			RoundedFilling = RoundedFilling,
		})
	end)
end

return RoundedSurface


local Winro = script.Parent.Parent.Parent
local Packages = Winro.Parent

local Sift = require(Packages.Sift)
local Roact = require(Packages.Roact)
local new = Roact.createElement

local SurfaceRoot = script.Parent
local RoundedSurface = require(SurfaceRoot.RoundedSurface)

local RoundedSurfaceStory = Roact.PureComponent:extend(script.Name)

function RoundedSurfaceStory:render()
	return new(RoundedSurface, Sift.Dictionary.join({
		Size = UDim2.fromOffset(50, 50),
		BackgroundColor = {
			Color = Color3.new(1, 1, 1),
			Transparency = self.props.Alpha or 0.5
		},
		CornerRadius = UDim.new(0, self.props.Radius or 5),
		ShowTopLeftCorner = self.props.TLeft,
		ShowTopRightCorner =self.props.TRight,
		ShowBottomLeftCorner =self.props.BLeft,
		ShowBottomRightCorner = self.props.BRight,
	}, self.props.Props))
end

return {
	controls = {
		Radius = 10,
		Alpha = 0.5,
		TLeft = false,
		TRight = true,
		BLeft = true,
		BRight = false,
	},
	stories = {
		RoundedSurface = function (props)
			return new(RoundedSurfaceStory, props.controls)
		end
	}
}


-- Window: A component that is the base structure for a UI Window

local Winro = script.Parent.Parent.Parent
local Packages = Winro.Parent

local Theme = require(Winro.Theme)
local WithTheme = Theme.WithTheme

local Sift = require(Packages.Sift)
local t = require(Packages.t)
local Roact = require(Packages.Roact)
local new = Roact.createElement

local HyperlinkButton = require(Winro.App.Input.Hyperlink.HyperlinkButton)
local ButtonStack = require(Winro.App.Input.Button.ButtonStack)

local WindowRoot = script.Parent
local Window = require(WindowRoot.Window)

local Dialog = Roact.PureComponent:extend(script.Name)

Dialog.defaultProps = {
	AutomaticSize = Enum.AutomaticSize.Y, --- @defaultProp
	Position = UDim2.fromScale(0.5, 0.5), --- @defaultProp
	Size = UDim2.fromOffset(540, 0), --- @defaultProp
	TitleBarProps = {}, --- @defaultProp
	WindowProps = {}, --- @defaultProp
}

Dialog.validateProps = t.strictInterface({

	--- @prop @optional AnchorPoint Vector2 The Window's anchor point
	AnchorPoint = t.optional(t.Vector2),

	--- @prop @optional AutomaticSize Enum.AutomaticSize Auto sizing
	AutomaticSize = t.optional(t.EnumItem),

	--- @prop @optional Butttons table The buttons to be displayed
	Buttons = t.optional(t.table),

	--- @prop @optional Position UDim2 The Window's position
	Position = t.optional(t.UDim2),

	--- @prop @optional RichText boolean Body text Rich Text
	RichText = t.optional(t.boolean),

	--- @prop @optional Size UDim2 The Window's size
	Size = t.optional(t.UDim2),

	--- @prop @optional DetailTitle string The detail section's tile text
	DetailTitle = t.optional(t.string),

	--- @prop @optional DetailBody string The detail section's body text
	DetailBody = t.optional(t.string),

	--- @prop @optional DetailContents table The contents to display in the detail section
	DetailContents = t.optional(t.table),

	--- @prop @optional BodyText string Body text
	BodyText = t.optional(t.string),

	--- @prop @optional TitleText string Title text
	TitleText = t.optional(t.string),

	--- @prop @optional TitleBarProps table The props to be provided to the Title Bar
	TitleBarProps = t.optional(t.table),

	--- @prop @optional WindowProps table The props to be provided to the Window
	WindowProps = t.optional(t.table),

	--- @prop @optional [Roact.Children] table The contents to display in the window area
	[Roact.Children] = t.optional(t.table),

	--- @prop @optional ButtonStackProps table ButtonStackProps
	ButtonStackProps = t.optional(t.table),

	--- @prop @optional Native table Native props
	Native = t.optional(t.table),
})

function Dialog:render()
	local props = self.props
	local state = self.state

	return WithTheme(function(Theme)

		-- ////////// Title

		local TitleFontStyle = Theme['fonts/Subtitle']
		local TitleTextStyle = Theme['colors/Fill_Color/Text/Primary']

		local Title = props.TitleText and new('TextLabel', {
			AutomaticSize = Enum.AutomaticSize.Y,
			BackgroundTransparency = 1,
			FontFace = TitleFontStyle.Font,
			LayoutOrder = 1,
			LineHeight = TitleFontStyle.LineHeight,
			Size = UDim2.fromScale(1, 0),
			Text = props.TitleText,
			TextSize = TitleFontStyle.Size,
			TextColor3 = TitleTextStyle.Color,
			TextTransparency = TitleTextStyle.Transparency,
			TextWrapped = true,
			TextXAlignment = Enum.TextXAlignment.Left,
			TextYAlignment = Enum.TextYAlignment.Top,
		})

		-- ////////// Body

		local BodyFontStyle = Theme['fonts/Body']
		local BodyTextStyle = Theme['colors/Fill_Color/Text/Primary']

		local Body = props.BodyText and new('TextLabel', {
			AutomaticSize = Enum.AutomaticSize.Y,
			BackgroundTransparency = 1,
			FontFace = BodyFontStyle.Font,
			LayoutOrder = 2,
			LineHeight = BodyFontStyle.LineHeight,
			RichText = props.RichText,
			Size = UDim2.fromScale(1, 0),
			Text = props.BodyText,
			TextSize = BodyFontStyle.Size,
			TextColor3 = BodyTextStyle.Color,
			TextTransparency = BodyTextStyle.Transparency,
			TextWrapped = true,
			TextXAlignment = Enum.TextXAlignment.Left,
			TextYAlignment = Enum.TextYAlignment.Top,
		})

		-- ////////// Detail Hyperlink

		-- Check if the detail container should be craeted
		local DetailContainerEnabled = props.DetailTitle or props.DetailBody or props.DetailContents

		local DetailHyperlink = DetailContainerEnabled and new(HyperlinkButton, {
			AutomaticSize = Enum.AutomaticSize.XY,
			LayoutOrder = state.DetailShown and 4 or 3,
			Size = UDim2.fromScale(0, 0),
			Text = props.DetailButtonText,
			TextXAlignment = Enum.TextXAlignment.Left,
		})

		-- ////////// Buttons

		local Buttons = props.Buttons and new(ButtonStack, Sift.Dictionary.join({
			AnchorPoint = Vector2.new(0.5, 0.5),
			Buttons = props.Buttons,
			Position = UDim2.fromScale(0.5, 0.5),
			Size = UDim2.new(1, 0, 1, 0),
			PaddingLeft = UDim.new(0, Theme['styles/Padding/Default/Outer/Left']),
			PaddingRight = UDim.new(0, Theme['styles/Padding/Default/Outer/Right']),
		}, props.ButtonStackProps))

		-- ////////// Dialog
		return new(Window, Sift.Dictionary.join({
			AnchorPoint = props.AnchorPoint,
			AutomaticSize = props.AutomaticSize,
			ContentBackgroundColor = 'colors/Background/Fill_Color/Layer/Alt',
			Position = props.Position,
			Size = props.Size,
			Native = props.Native,

			FooterHeight = Buttons and 80 or 0,
			FooterContents = Buttons,

			TitleBarProps = Sift.Dictionary.join({
				BackgroundColor = 'colors/Background/Fill_Color/Layer/Alt',
			}, props.TitleBarProps),
		}, props.WindowProps), {
			Title = Title,
			Body = Body,
			DetailHyperlink = DetailHyperlink,

			Layout = new('UIListLayout', {
				SortOrder = Enum.SortOrder.LayoutOrder,
				Padding = UDim.new(0, 12),
			}),
			Padding = new('UIPadding', {
				PaddingBottom = UDim.new(0, Theme['styles/Padding/Content/Outer/Bottom']),
				PaddingLeft = UDim.new(0, Theme['styles/Padding/Content/Outer/Left']),
				PaddingRight = UDim.new(0, Theme['styles/Padding/Content/Outer/Right']),
				PaddingTop = UDim.new(0, Theme['styles/Padding/Content/Outer/Top']),
			}),
		})
	end)
end

return Dialog


-- TitleBar: The top bar of a window component

local Winro = script.Parent.Parent.Parent
local Packages = Winro.Parent

local FrameVisualizer = require(Winro.Utility.FrameVisualizer)

local Sift = require(Packages.Sift)
local Roact = require(Packages.Roact)
local new = Roact.createElement

local Dialog = require(script.Parent.Dialog)

local DialogStory = Roact.PureComponent:extend(script.Name)

function DialogStory:render()
	local props = self.props

	local Dialog = new(Dialog, Sift.Dictionary.join({
		TitleText = 'Title',
		BodyText = props.BodyText,

		Buttons = props.Buttons and {
			[1] = {
				Text = 'Accept',
				Style = 'Accent',
				[Roact.Event.Activated] = print,
			},
			[2] = {
				Text = 'Cancel',
				Style = 'Standard',
				[Roact.Event.Activated] = print,
			},
			[3] = {
				Disabled = true,
				Text = 'Disabled',
				Style = 'Standard',
				[Roact.Event.Activated] = print,
			},
		},
		-- ButtonStackProps = {
		-- 	StackWidth = UDim.new(0, 300),
		-- },
		TitleBarProps = {
			Icon = 'images/roblox/icons/logo/studiologo_small/1x',
			Text = 'App name',
			ReleaseText = 'Preview',
			OnClose = print,
		},
		WindowProps = {
			FooterHeight = 80,
		}
	}, self.props.Props))

	if self.props.Wireframe then
		return new(FrameVisualizer, {
			Size = UDim2.new(1, 0, 1, 0),
		}, Dialog)
	else
		return Dialog
	end
end

return {
	controls = {
		Wireframe = false,
		Buttons = true,
		BodyText = [[This is body text. Windows 11 marks a visual evolution of the operating system. We have evolved our design language alongside with Fluent to create a design which is human, universal and truly feels like Windows.

The design principles below have guided us throughout the journey of making Windows the best-in-class implementation of Fluent.]]
	},
	stories = {
		Dialog = function(props)
			return new(DialogStory, props.controls)
		end
	}
}


-- CaptionClose: The TitleBar close button

local Winro = script.Parent.Parent.Parent.Parent
local Packages = Winro.Parent

local Theme = require(Winro.Theme)
local WithTheme = Theme.WithTheme
local RegisterStateAction = Theme.RegisterStateAction

local Validators = Winro.Validators
local StyleValidator = require(Validators.StyleValidator)

local t = require(Packages.t)
local Roact = require(Packages.Roact)
local new = Roact.createElement

local RoundedSurface = require(Winro.App.Surface.RoundedSurface)

local CAPTIONCLOSE_TEXT_REST = 'colors/Fill_Color/Text/Primary'
local CAPTIONCLOSE_TEXT_PRIMARY = 'colors/Shell/Fill_Color/Caption_Close_Text/Primary'
local CAPTIONCLOSE_TEXT_SECONDARY = 'colors/Shell/Fill_Color/Caption_Close_Text/Secondary'
local CAPTIONCLOSE_FILL_REST = 'colors/Fill_Color/Subtle/Transparent'
local CAPTIONCLOSE_FILL_PRIMARY = 'colors/Shell/Fill_Color/Caption_Control_Close_Fill/Primary'
local CAPTIONCLOSE_FILL_SECONDARY = 'colors/Shell/Fill_Color/Caption_Control_Close_Fill/Secondary'
local CAPTIONCLOSE_ICON = 'images/roblox/icons/navigation/close/1x'

local CaptionClose = Roact.PureComponent:extend(script.Name)

CaptionClose.defaultProps = {
	Width = 48, --- @defaultProp
}

CaptionClose.validateProps = t.strictInterface({

	--- @prop @optional @style TextColor string|table X icon color
	TextColor = t.optional(StyleValidator),

	--- @prop @optional AlwaysShow boolean Determines if the caption close button is always shown
	AlwaysShow = t.optional(t.boolean),

	--- @prop @optional Width number positive The Button's width in pixels
	Width = t.optional(t.numberPositive),

	--- @prop @optional [Roact.Event.Activated] function Roact.Event.Activated
	[Roact.Event.Activated] = t.optional(t.callback),

	--- @prop @optional [Roact.Event.MouseButton1Down] function Roact.Event.MouseButton1Down
	[Roact.Event.MouseButton1Down] = t.optional(t.callback),

	--- @prop @optional [Roact.Event.MouseButton1Up] function Roact.Event.MouseButton1Up
	[Roact.Event.MouseButton1Up] = t.optional(t.callback),

	--- @prop @optional [Roact.Event.MouseEnter] function Roact.Event.MouseEnter
	[Roact.Event.MouseEnter] = t.optional(t.callback),

	--- @prop @optional [Roact.Event.MouseLeave] function Roact.Event.MouseLeave
	[Roact.Event.MouseLeave] = t.optional(t.callback),
})

function CaptionClose:init()

	-- Actions
	RegisterStateAction(self, Roact.Event.Activated, nil)
	RegisterStateAction(self, Roact.Event.MouseButton1Down, 'Pressed')
	RegisterStateAction(self, Roact.Event.MouseButton1Up, 'Hover')
	RegisterStateAction(self, Roact.Event.MouseEnter, 'Hover')
	RegisterStateAction(self, Roact.Event.MouseLeave, 'Rest')

	-- Initial state
	self:setState({
		State = 'Rest'
	})
end

function CaptionClose:render()
	local props = self.props
	local state = self.state

	return WithTheme(function(Theme)

		-- ////////// Button

		local FillStyle = nil
		local TextStyle = nil

		if state.State == 'Rest' then

			if props.AlwaysShow then
				TextStyle = Theme[CAPTIONCLOSE_TEXT_PRIMARY]
				FillStyle = Theme[CAPTIONCLOSE_FILL_PRIMARY]

			else
				TextStyle = Theme[props.TextColor or CAPTIONCLOSE_TEXT_REST]
				FillStyle = Theme[CAPTIONCLOSE_FILL_REST]
			end

		elseif state.State == 'Hover' then
			TextStyle = Theme[CAPTIONCLOSE_TEXT_PRIMARY]
			FillStyle = Theme[CAPTIONCLOSE_FILL_PRIMARY]

		else
			TextStyle = Theme[CAPTIONCLOSE_TEXT_SECONDARY]
			FillStyle = Theme[CAPTIONCLOSE_FILL_SECONDARY]
		end

		return new(RoundedSurface, {
			AnchorPoint = Vector2.new(1, 0),
			BackgroundColor = FillStyle,
			CornerRadius = UDim.new(0, Theme['styles/CornerRadius/Default/Outer']),
			Position = UDim2.fromScale(1, 0),
			Size = UDim2.new(0, props.Width, 1, 0),
			ShowTopRightCorner = true,
		}, {
			Button = new('ImageButton', {
				BackgroundTransparency = 1,
				Size = UDim2.fromScale(1, 1),

				[Roact.Event.Activated] = self[Roact.Event.Activated],
				[Roact.Event.MouseButton1Down] = self[Roact.Event.MouseButton1Down],
				[Roact.Event.MouseButton1Up] = self[Roact.Event.MouseButton1Up],
				[Roact.Event.MouseEnter] = self[Roact.Event.MouseEnter],
				[Roact.Event.MouseLeave] = self[Roact.Event.MouseLeave],
			}),
			Icon = new('ImageLabel', {
				AnchorPoint = Vector2.new(0.5, 0.5),
				BackgroundTransparency = 1,
				Position = UDim2.fromScale(0.5, 0.5),
				Size = UDim2.fromOffset(18, 18),
				ImageColor3 = TextStyle.Color,
				ImageTransparency = TextStyle.Transparency,
				Image = Theme[CAPTIONCLOSE_ICON].Image,
				ImageRectSize = Theme[CAPTIONCLOSE_ICON].ImageRectSize,
				ImageRectOffset = Theme[CAPTIONCLOSE_ICON].ImageRectOffset,
				ScaleType = Enum.ScaleType.Fit,
				--ResampleMode = Enum.ResamplerMode.Pixelated,
			})
		})
	end)
end

return CaptionClose


-- TitleBar: The top bar of a window component

local Winro = script.Parent.Parent.Parent.Parent
local Packages = Winro.Parent

local Theme = require(Winro.Theme)
local WithTheme = Theme.WithTheme

local Validators = Winro.Validators
local StyleValidator = require(Validators.StyleValidator)

local t = require(Packages.t)
local Roact = require(Packages.Roact)
local new = Roact.createElement

local GetTextSize = require(Winro.Utility.GetTextSize)
local RoundedSurface = require(Winro.App.Surface.RoundedSurface)

local TitleBarRoot = script.Parent
local CaptionClose = require(TitleBarRoot.CaptionClose)

local TITLEBAR_LABEL_FONT_STYLE = 'fonts/Caption'
local TITLEBAR_LABEL_TEXT_STYLE = 'colors/Fill_Color/Text/Primary'
local TITLEBAR_RELEASE_TEXT_STYLE = 'colors/Fill_Color/Text/Secondary'

local TitleBar = Roact.PureComponent:extend(script.Name)

TitleBar.defaultProps = {
	Height = 32, --- @defaultProp
	Text = 'TitleBar', --- @defaultProp
	CaptionButtonWidth = 48, --- @defaultProp

	BackgroundColor = {
		Color = Color3.new(),
		Transparency = 1,
	}, --- @defaultProp
}

TitleBar.validateProps = t.strictInterface({

	--- @prop @optional AlwaysShowClose boolean Always show the close button
	AlwaysShowClose = t.optional(t.boolean),

	--- @prop @optional CaptionButtonWidth number Caption Button's width
	CaptionButtonWidth = t.optional(t.number),

	--- @prop @optional Text string The TitleBar's text
	Text = t.optional(t.string),

	--- @prop @optional LayoutOrder number The TitleBar's layout order
	LayoutOrder = t.optional(t.number),

	--- @prop @optional Icon string|table The TitleBar's icon
	Icon = t.optional(StyleValidator),

	--- @prop @optional ReleaseText string The TitleBar's release text
	ReleaseText = t.optional(t.string),

	--- @prop @optional @style TextColor string|table The Label's text fill
	TextColor = t.optional(StyleValidator),

	--- @prop @optional @style BackgroundColor string|table The TitleBars's background fill
	BackgroundColor = t.optional(StyleValidator),

	--- @prop @optional Height number positive The TitleBar's height, in pixels
	Height = t.optional(t.numberPositive),

	--- @prop @optional OnClose function The function to call when the close button is pressed
	OnClose = t.optional(t.callback),

	--- @prop @optional Native table Native props
	Native = t.optional(t.table)
})

function TitleBar:render()
	local props = self.props

	return WithTheme(function(Theme)

		-- ////////// Label

		local LabelFontStyle = Theme[TITLEBAR_LABEL_FONT_STYLE]
		local LabelTextStyle = Theme[props.TextColor or TITLEBAR_LABEL_TEXT_STYLE]

		local GotLabelTextSize, LabelTextSize = GetTextSize(props.Text, LabelFontStyle.Font, LabelFontStyle.Size)

		local Label = new('TextLabel', {
			AutomaticSize = (not GotLabelTextSize) and Enum.AutomaticSize.X or nil, -- Fallback
			BackgroundTransparency = 1,
			FontFace = LabelFontStyle.Font,
			LayoutOrder = 1,
			Size = UDim2.new(0, GotLabelTextSize and LabelTextSize.X or 0, 1, 0),
			Text = props.Text,
			TextColor3 = LabelTextStyle.Color,
			TextSize = LabelFontStyle.Size,
			TextTransparency = LabelTextStyle.Transparency,
		})

		-- ////////// Release Label

		local ReleaseLabelTextStyle = Theme[TITLEBAR_RELEASE_TEXT_STYLE]

		local GotReleaseLabelTextSize, ReleaseLabelTextSize = nil, nil

		if props.ReleaseText then
			GotReleaseLabelTextSize, ReleaseLabelTextSize = GetTextSize(props.ReleaseText, LabelFontStyle.Font, LabelFontStyle.Size)
		end

		local ReleaseLabel = props.ReleaseText and new('TextLabel', {
			AutomaticSize = (not GotReleaseLabelTextSize) and Enum.AutomaticSize.X or nil, -- Fallback
			BackgroundTransparency = 1,
			FontFace = LabelFontStyle.Font,
			LayoutOrder = 2,
			Size = UDim2.new(0, GotReleaseLabelTextSize and ReleaseLabelTextSize.X or 0, 1, 0),
			Text = props.ReleaseText,
			TextColor3 = ReleaseLabelTextStyle.Color,
			TextSize = LabelFontStyle.Size,
			TextTransparency = ReleaseLabelTextStyle.Transparency,
		}) or nil

		-- ////////// Text Container

		local TextContainerWidth = LabelTextSize.X

		if GotReleaseLabelTextSize then
			TextContainerWidth += ReleaseLabelTextSize.X + 8 -- Account for 8px layout padding
		end

		local TextContainer = new('Frame', {
			BackgroundTransparency = 1,
			LayoutOrder = 2,
			Size = UDim2.new(0, TextContainerWidth, 1, 0),
		}, {
			Label = Label,
			ReleaseLabel = ReleaseLabel,

			Layout = new('UIListLayout', {
				FillDirection = Enum.FillDirection.Horizontal,
				Padding = UDim.new(0, 8),
			}),
		})

		-- ////////// Icon

		local IconImage = props.Icon and Theme[props.Icon]
		local IconImageSize = nil

		if IconImage then
			local IconImageRectSize = IconImage.ImageRectSize == Vector2.new() and Vector2.new(16, 16) or IconImage.ImageRectSize
			IconImageSize = UDim2.fromOffset(
				math.clamp(IconImageRectSize.X, 0, 9*4),
				math.clamp(IconImageRectSize.Y, 0, 9*4)
			)
		else
			IconImageSize = UDim2.fromOffset(0, 0)
		end

		local IconImage = IconImage and new('ImageLabel', {
			AnchorPoint = Vector2.new(0.5, 0.5),
			BackgroundTransparency = 1,
			Image = IconImage.Image,
			ImageRectOffset = IconImage.ImageRectOffset,
			ImageRectSize = IconImage.ImageRectSize,
			Position = UDim2.fromScale(0.5, 0.5),
			ResampleMode = IconImage.ResampleMode,
			Size = IconImageSize,
			ImageColor3 = IconImage.ImageColor3,
			ImageTransparency = IconImage.ImageTransparency,
		})

		local Icon = IconImage and new('Frame', {
			AnchorPoint = Vector2.new(0.5, 0.5),
			BackgroundTransparency = 1,
			Position = UDim2.new(0, 16 + 8, 0.5, 0),
			Size = UDim2.new(0, 16, 1, 0),
		}, IconImage)

		-- ////////// Icon and Title

		local TotalPartsSize = UDim2.new(0, TextContainerWidth + (IconImage and 16 * 2 or 0) + 12, 1, 0) -- Account for 12px left padding, Account for additional 16px padding if an icon is present

		local IconAndTitle = new('Frame', {
			BackgroundTransparency = 1,
			LayoutOrder = 2,
			Size = TotalPartsSize,
		}, {
			Icon = Icon,
			TextConatainer = TextContainer,

			Layout = new('UIListLayout', {
				FillDirection = Enum.FillDirection.Horizontal,
				Padding = UDim.new(0, 16),
			}),
			Padding = new('UIPadding', {
				PaddingLeft = UDim.new(0, 12),
			}),
		})

		-- ////////// TitleBar parts

		local Parts = new('Frame', {
			BackgroundTransparency = 1,
			Size = TotalPartsSize + UDim2.fromOffset(4, 0), -- Account for 4px left padding
		}, {
			IconAndTitle = IconAndTitle,

			Padding = new('UIPadding', {
				PaddingLeft = UDim.new(0, 4),
			}),
		})

		-- ////////// Caption buttons

		local CaptionContainerWidth = 0
		local CaptionButtons = {}

		if props.OnClose then
			CaptionButtons.Close = new(CaptionClose, {
				AlwaysShow = props.AlwaysShowClose,
				Width = props.CaptionButtonWidth,
				[Roact.Event.Activated] = props.OnClose,
			})
		end

		local CaptionButtonContainer = new('Frame', {
			AnchorPoint = Vector2.new(1, 0),
			BackgroundTransparency = 1,
			Position = UDim2.fromScale(1, 0),
			Size = UDim2.new(0, CaptionContainerWidth, 1, 0),
		}, CaptionButtons)

		-- ////////// TitleBar
		return new(RoundedSurface, {
			BackgroundColor = Theme[props.BackgroundColor],
			CornerRadius = UDim.new(0, Theme['styles/CornerRadius/Default/Outer']),
			LayoutOrder = props.LayoutOrder,
			Size = UDim2.new(1, 0, 0, props.Height),
			ShowTopLeftCorner = true,
			ShowTopRightCorner = true,
			Native = props.Native,
		}, {
			Parts = Parts,
			CaptionButtonContainer = CaptionButtonContainer,
		})
	end)
end

return TitleBar


-- TitleBar: The top bar of a window component

local Winro = script.Parent.Parent.Parent.Parent
local Packages = Winro.Parent

local FrameVisualizer = require(Winro.Utility.FrameVisualizer)

local Sift = require(Packages.Sift)
local Roact = require(Packages.Roact)
local new = Roact.createElement

local TitleBar = require(script.Parent.TitleBar)

local TitleBarStory = Roact.PureComponent:extend(script.Name)

function TitleBarStory:render()

	local TitleBar = new(TitleBar, Sift.Dictionary.join({
		Icon = self.props.Icon and 'images/roblox/icons/logo/studiologo_small/1x' or nil,
		ReleaseText = 'Story',
		AlwaysShowClose = self.props.AlwaysShowClose,
		BackgroundColor = 'colors/Background/Fill_Color/Solid_Background/Base',
		Height = self.props.Size == 'Standard' and 32 or self.props.Size == 'Large' and 48 or 29,
		OnClose = print,
		CaptionButtonWidth = self.props.Size == 'Small' and 29 or 32
	}, self.props.Props))

	if self.props.Wireframe then
		return new(FrameVisualizer, {
			Size = UDim2.new(1, 0, 1, 0),
		}, TitleBar)
	else
		return TitleBar
	end
end

return {
	controls = {
		AlwaysShowClose = false,
		Wireframe = false,
		Icon = false,
		Size = {'Standard', 'Large', 'Small'},
	},
	stories = {
		TitleBar = function(props)
			return new(TitleBarStory, props.controls)
		end
	}
}


-- Window: A component that is the base structure for a UI Window

local Winro = script.Parent.Parent.Parent
local Packages = Winro.Parent

local Theme = require(Winro.Theme)
local WithTheme = Theme.WithTheme

local Validators = Winro.Validators
local StyleValidator = require(Validators.StyleValidator)

local Sift = require(Packages.Sift)
local t = require(Packages.t)
local Roact = require(Packages.Roact)
local new = Roact.createElement

local UserInputService = game:GetService('UserInputService')

local DropShadow = require(Winro.App.Effect.DropShadow)
local RoundedSurface = require(Winro.App.Surface.RoundedSurface)

local WindowRoot = script.Parent
local TitleBar = require(WindowRoot.TitleBar.TitleBar)

local Window = Roact.PureComponent:extend(script.Name)

Window.defaultProps = {
	AnchorPoint = Vector2.new(0.5, 0.5), --- @defaultProp
	BackgroundColor = 'colors/Background/Fill_Color/Solid_Background/Base', --- @defaultProp
	ContentBackgroundColor = {
		Color = Color3.new(),
		Transparency = 1,
	}, --- @defaultProp
	DropShadowEnabled = true, --- @defaultProp
	Draggable = true, --- @defaultProp
	FooterHeight = 0, --- @defaultProp
	Position = UDim2.fromScale(0.5, 0.5), --- @defaultProp
	Size = UDim2.fromOffset(300, 300), --- @defaultProp
	TitleBarProps = {}, --- @defaultProp
}

Window.validateProps = t.strictInterface({

	--- @prop @optional AnchorPoint Vector2 The Window's anchor point
	AnchorPoint = t.optional(t.Vector2),

	--- @prop @optional @style BackgroundColor string|table The Window's background color
	BackgroundColor = t.optional(StyleValidator),

	--- @prop @optional @style ContentBackgroundColor string|table The Content's background color
	ContentBackgroundColor = t.optional(StyleValidator),

	--- @prop @optional DropShadowEnabled boolean Determines if a drop shadow is shown
	DropShadowEnabled = t.optional(t.boolean),

	--- @prop @optional Draggable boolean Determines if the window can be dragged via the TopBar
	Draggable = t.optional(t.boolean),

	--- @prop @optional AutomaticSize Enum.AutomaticSize Auto sizing
	AutomaticSize = t.optional(t.EnumItem),

	--- @prop @optional FooterHeight number The Footer's height, in pixels
	FooterHeight = t.optional(t.number),

	--- @prop @optional FooterContents table The contents to display in the footer
	FooterContents = t.optional(t.table),

	--- @prop @optional Position UDim2 The Window's position
	Position = t.optional(t.UDim2),

	--- @prop @optional Size UDim2 The Window's size
	Size = t.optional(t.UDim2),

	--- @prop @optional TitleBarProps table The props to be provided to the Title Bar
	TitleBarProps = t.optional(t.table),

	--- @prop @optional [Roact.Children] table The contents to display in the window area
	[Roact.Children] = t.optional(t.table),

	--- @prop @optional Native table Native props
	Native = t.optional(t.table),
})

function Window:init()

	-- Size binding, for FitContents
	self.Size, self.SetSize = Roact.createBinding(self.props.Size)

	-- TitleBar ref, for dragging and for height sizing
	self.TitleBarRef = Roact.createRef()

	-- Window ref, for dragging
	self.WindowRef = Roact.createRef()

	-- Connection, for dragging
	if self.props.Draggable then

		self.DragConnection = UserInputService.InputChanged:Connect(function(Input)

			-- Get the window
			local Window = self.WindowRef:getValue()

			-- Validate that this is drag input
			if Window and Input == self.DragInput and self.Dragging then

				local Delta = Input.Position - self.DragStart

				-- Set the position
				Window.Position = UDim2.new(self.StartPos.X.Scale, self.StartPos.X.Offset + Delta.X, self.StartPos.Y.Scale, self.StartPos.Y.Offset + Delta.Y)
			end
		end)
	end
end

function Window:willUnmount()

	if self.DragConnection then
		self.DragConnection:Disconnect()
	end
end

function Window:didMount()

	local TitleBar = self.TitleBarRef:getValue()
	local Window = self.WindowRef:getValue()

	-- Sizing
	if TitleBar then
		TitleBar:GetPropertyChangedSignal('AbsoluteSize'):Connect(function()
			local AbsoluteSize = TitleBar.AbsoluteSize
			self.TitleBarHeight = AbsoluteSize.Y
		end)
	end

	if TitleBar and Window and self.props.Draggable then
		TitleBar.InputBegan:Connect(function(Input)
			if Input.UserInputType == Enum.UserInputType.MouseButton1 or Input.UserInputType == Enum.UserInputType.Touch then
				self.Dragging = true
				self.DragStart = Input.Position
				self.StartPos = Window.Position

				local Connection = nil
				Connection = Input.Changed:Connect(function()
					if Input.UserInputState == Enum.UserInputState.End then
						self.Dragging = nil
						Connection:Disconnect()
					end
				end)
			end
		end)

		TitleBar.InputChanged:Connect(function(Input)
			if Input.UserInputType == Enum.UserInputType.MouseMovement or Input.UserInputType == Enum.UserInputType.Touch then
				self.DragInput = Input
			end
		end)
	end
end

function Window:render()
	local props = self.props

	return WithTheme(function(Theme)

		-- ////////// Title Bar

		local TitleBar = new(TitleBar, Sift.Dictionary.join({
			LayoutOrder = 1,
			Height = 32,--28,
			CaptionButtonWidth = 45,
			Native = {
				[Roact.Ref] = self.TitleBarRef,
			}
		}, props.TitleBarProps))

		-- ////////// Content Wrapper

		local ContentWrapperFillStyle = Theme[props.ContentBackgroundColor]

		local ContentWrapper = new(RoundedSurface, {
			AutomaticSize = props.AutomaticSize,
			BackgroundColor3 = ContentWrapperFillStyle.Color,
			BackgroundTransparency = ContentWrapperFillStyle.Transparency,
			BorderSizePixel = 0,
			CornerRadius = UDim.new(0, Theme['styles/CornerRadius/Default/Outer']),
			ShowBottomLeftCorner = props.FooterHeight < Theme['styles/CornerRadius/Default/Outer'] / 2,
			ShowBottomRightCorner = props.FooterHeight < Theme['styles/CornerRadius/Default/Outer'] / 2,
			LayoutOrder = 2,
			Size = props.Size,

			[Roact.Change.AbsoluteSize] = function (rbx)
				local AbsoluteSize = rbx.AbsoluteSize
				self.SetSize(UDim2.fromOffset(AbsoluteSize.X, AbsoluteSize.Y))
			end
		}, self.props[Roact.Children])

		-- ////////// Footer

		local Footer = new('Frame', {
			BackgroundTransparency = 1,
			LayoutOrder = 3,
			Size = UDim2.new(1, 0, 0, props.FooterHeight),
		}, props.FooterContents)

		-- ////////// Window

		local WindowFillStyle = Theme[props.BackgroundColor]
		local StrokeStyle = Theme['colors/Stroke_Color/Surface_Stroke/Default']

		local Window = new('Frame', Sift.Dictionary.join({
			AnchorPoint = props.DropShadowEnabled and Vector2.new(0.5, 0.5) or props.AnchorPoint,
			Position = props.DropShadowEnabled and UDim2.fromScale(0.5, 0.5) or props.Position,
			BackgroundColor3 = WindowFillStyle.Color,
			BackgroundTransparency = WindowFillStyle.Transparency,

			[Roact.Ref] = (not props.Draggable) and self.WindowRef or nil,

			Size = self.Size:map(function(Size)
				return Size + UDim2.fromOffset(0, (self.TitleBarHeight or 0) + props.FooterHeight)
			end),
		}, props.Native), {
			TitleBar = TitleBar,
			ContentWrapper = ContentWrapper,
			Footer = Footer,

			Stroke = new('UIStroke', {
				Color = StrokeStyle.Color,
				Transparency = StrokeStyle.Transparency,
			}),
			Corners = new('UICorner', {
				CornerRadius = UDim.new(0, Theme['styles/CornerRadius/Default/Outer']),
			}),
			Layout = new('UIListLayout', {
				SortOrder = Enum.SortOrder.LayoutOrder,
			})
		})

		if props.DropShadowEnabled then

			-- ////////// Drop Shadow

			return new(DropShadow, {
				AnchorPoint = props.AnchorPoint,
				Position = props.Position,
				CornerRadius = UDim.new(0, Theme['styles/CornerRadius/Default/Outer']),

				Size = self.Size:map(function(Size)
					return Size + UDim2.fromOffset(0, (self.TitleBarHeight or 0) + props.FooterHeight) + UDim2.new(0, 50, 0, 50)
				end),

				Native = {
					[Roact.Ref] = self.WindowRef,
				},
			}, Window)
		else
			return Window
		end
	end)
end

return Window


-- TitleBar: The top bar of a window component

local Winro = script.Parent.Parent.Parent
local Packages = Winro.Parent

local FrameVisualizer = require(Winro.Utility.FrameVisualizer)

local Sift = require(Packages.Sift)
local Roact = require(Packages.Roact)
local new = Roact.createElement

local Flyout = require(Winro.App.Flyout.Flyout)
local Window = require(script.Parent.Window)

local WindowStory = Roact.PureComponent:extend(script.Name)

function WindowStory:render()
	local props = self.props

	local Window = new(Window, Sift.Dictionary.join({
		AutomaticSize = Enum.AutomaticSize.XY,
		Size = UDim2.fromOffset(400, 200),
		ContentBackgroundColor = 'colors/Background/Fill_Color/Layer/Default',
		FooterHeight = props.FooterHeight,
		TitleBarProps = {
			Icon = 'images/roblox/icons/logo/studiologo_small/1x',
			-- BackgroundColor = 'colors/Background/Fill_Color/Layer/Alt',
			Text = 'Window',
			ReleaseText = 'Story',
			OnClose = props.CanClose and print or nil,
		},
		FooterContents = {
			Label = new('TextLabel', {
				BackgroundTransparency = 1,
				Size = UDim2.fromScale(1, 1),
				Text = '`FooterContents` goes here',
				TextColor3 = Color3.new(1, 1, 1),
				TextStrokeTransparency = 0,
			})
		}
	}, self.props.Props), {
		Label = new('TextLabel', {
			BackgroundTransparency = 1,
			Size = UDim2.fromScale(1, 1),
			Text = '\n\n\n\n\n\n\n\n\n`[Roact.Children]` goes here',
			TextColor3 = Color3.new(1, 1, 1),
			TextStrokeTransparency = 0,
			ZIndex = 2,
		}),
		Flyout = new(Flyout, {
			AnchorPoint = Vector2.new(0.5, 0),
			Position = UDim2.new(0.5, 0, 0, 25),
			RichText = true,
			Text = '<b>Note:</b>\nWindow dragging will not work while inside a plugin widget window.'
		}),
	})

	if self.props.Wireframe then
		return new(FrameVisualizer, {
			Size = UDim2.new(1, 0, 1, 0),
		}, Window)
	else
		return Window
	end
end

return {
	controls = {
		Wireframe = false,
		CanClose = true,
		FooterHeight = 80,
	},
	stories = {
		Window = function(props)
			return new(WindowStory, props.controls)
		end
	}
}


local Packages = script.Parent.Parent.Parent
local Flipper = require(Packages.Flipper)

local function CollectKeypoints(Sequence)

	if typeof(Sequence) == 'ColorSequence' then

		-- Extract each keypoint
		local Keypoints = {}

		for Index, Keypoint in pairs(Sequence.Keypoints) do
			local Color = Keypoint.Value
			Keypoints[Index] = {
				T = Keypoint.Time,
				V = {
					R = Color.R,
					G = Color.G,
					B = Color.B,
				}
			}
		end

		return Keypoints
	else

		-- Extract each keypoint
		local Keypoints = {}

		for Index, Keypoint in pairs(Sequence.Keypoints) do
			Keypoints[Index] = {
				T = Keypoint.Time,
				V = Keypoint.Value
			}
		end

		return Keypoints
	end
end

local function SpringKeypoints(Keypoints, SpringOptions)

	-- Get springed keypoints
	local SpringedKeypoints = {}

	for Index, Keypoint in pairs(Keypoints) do

		SpringedKeypoints[Index] = {
			T = Flipper.Spring.new(Keypoint.T, SpringOptions)
		}

		-- Color keypoints
		if typeof(Keypoint.V) == 'table' then
			local Color = Keypoint.V

			SpringedKeypoints[Index].V = {
				R = Flipper.Spring.new(Color.R, SpringOptions),
				G = Flipper.Spring.new(Color.G, SpringOptions),
				B = Flipper.Spring.new(Color.B, SpringOptions)
			}

		-- Number keypoints
		else
			SpringedKeypoints[Index].V = Flipper.Spring.new(Keypoint.V, SpringOptions)
		end
	end

	return SpringedKeypoints
end

return function (self, Description, Theme, ColorAnimationSettings, TransparencyAnimationSettings)

	--- todo: Add a way to determine if the theme wash changed
	-- -- Skip if our current description is the same
	-- if self.Description and (Description.Name == self.Description.Name) then
	-- 	return
	-- end

	-- -- Register
	-- self.Description = Description

	-- Update each style binding
	for _, StyleBinding in pairs(self.StyleBindings) do

		-- Get the style key
		local StyleKey = Description[StyleBinding]

		-- Get the style
		local Style = Theme[StyleKey]

		-- Extract initial style, for animation
		local InitialStyle = self[StyleBinding]:getValue()

		-- If no initial, animation isn't noticeable
		if not (InitialStyle and InitialStyle.Color) then
			self['Set' .. StyleBinding](Style)
			continue
		end

		local InitialColor = InitialStyle.Color
		local R, G, B = InitialColor.R, InitialColor.G, InitialColor.B

		-- Remove existing motor, if found
		local ExistingMotor = self[StyleBinding .. 'Motor']
		if ExistingMotor then
			pcall(ExistingMotor.destroy, ExistingMotor)
		end

		-- Extract initial values for motor
		local InitialValues = {
			R = R,
			G = G,
			B = B,
			T = InitialStyle.Transparency,
		}

		-- Color and Transparency sequences
		if InitialStyle.ColorSequence then
			InitialValues.CS = CollectKeypoints(InitialStyle.ColorSequence)
		end

		if InitialStyle.TransparencySequence then
			InitialValues.TS = CollectKeypoints(InitialStyle.TransparencySequence)
		end

		-- Create animation motor
		local Motor = Flipper.GroupMotor.new(InitialValues)

		self[StyleBinding .. 'Motor'] = Motor

		-- Bind motor
		Motor:onStep(function(Values)
			local CS, TS = nil, nil

			-- Build ColorSequence
			if Values.CS then

				-- Build keypoints
				local Keypoints = {}

				for Index, KeypointData in pairs(Values.CS) do
					local Color = KeypointData.V

					Keypoints[Index] = ColorSequenceKeypoint.new(KeypointData.T, Color3.new(Color.R, Color.G, Color.B))
				end

				-- Create sequence
				CS = ColorSequence.new(Keypoints)
			end

			-- Build TransparencySequence
			if Values.TS then

				-- Build keypoints
				local Keypoints = {}

				for Index, KeypointData in pairs(Values.TS) do
					Keypoints[Index] = NumberSequenceKeypoint.new(KeypointData.T, KeypointData.V)
				end

				-- Create sequence
				TS = NumberSequence.new(Keypoints)
			end

			-- Update style
			self['Set' .. StyleBinding]({
				Color = Color3.new(Values.R, Values.G, Values.B),
				Transparency = Values.T,
				ColorSequence = Style.ColorSequence, -- todo: fix CS
				TransparencySequence = Style.TransparencySequence, -- todo: fix TS
			})
		end)

		Motor:onComplete(function()
			Motor:destroy()
			self[StyleBinding .. 'Motor'] = nil
		end)

		-- Gather goals
		local Color = Style.Color
		local R, G, B = Color.R, Color.G, Color.B
		local Goals = {
			R = Flipper.Spring.new(R, ColorAnimationSettings),
			G = Flipper.Spring.new(G, ColorAnimationSettings),
			B = Flipper.Spring.new(B, ColorAnimationSettings),
			T = Flipper.Spring.new(Style.Transparency, TransparencyAnimationSettings),
		}

		-- Color and Transparency sequences
		if Style.ColorSequence then
			--Goals.CS = SpringKeypoints(CollectKeypoints(Style.ColorSequence), ColorAnimationSettings)
		end

		if Style.TransparencySequence then
			--Goals.TS = SpringKeypoints(CollectKeypoints(Style.TransparencySequence), TransparencyAnimationSettings)
		end

		-- Play animation
		Motor:setGoal(Goals)
	end
end


return function (self, Event, State)

	self[Event] = function(...)

		-- Set state
		self:setState({
			State = State
		})

		-- Custom callback
		local Callback = self.props[Event]
		if Callback then
			Callback(...)
		end
	end
end


local Theme = script.Parent
local Winro = Theme.Parent
local Roact = require(Winro.parent.Roact)

return Roact.createContext(nil)


local StarterGui = game:GetService("StarterGui")
local Theme = script.Parent
local Winro = Theme.Parent
local Packages = Winro.Parent

local Roact = require(Packages.Roact)
local StyleContext = require(Theme.StyleContext)

local StyleProvider = Roact.Component:extend("StyleProvider")

-- // UIBlox theme provider //

function StyleProvider:init()
	-- This is typically considered an anti-pattern, but it's the simplest
	-- way to preserve the behavior that these context solutions employed

	self.UpdateConnection = StarterGui:GetAttributeChangedSignal('Theme'):Connect(function()

		-- If provided as a prop, ignore override
		if self.props.Theme then
			return
		end

		self.ThemeObject:Update(require(Theme).Themes[StarterGui:GetAttribute('Theme')])
	end)

	self:setState({
		Theme = self.props.Theme or require(Theme).Themes[StarterGui:GetAttribute('Theme')],
	})
end

function StyleProvider:render()

	local ThemeObject = {
		Theme = self.state.Theme,
		Update = function(_self, NewTheme)
			if self.mounted then
				_self.Theme = NewTheme
				self:setState({ Theme = NewTheme })
			end
		end,
	}

	self.ThemeObject = ThemeObject

	return Roact.createElement(StyleContext.Provider, {
		value = ThemeObject,
	}, Roact.createFragment(self.props[Roact.Children]))
end

function StyleProvider:didMount()
	self.mounted = true
end

function StyleProvider:willUnmount()
	self.UpdateConnection:Disconnect()
	self.mounted = false
end

return StyleProvider


local AccentColor = Color3.fromRGB(118, 185, 237) -- Color3.fromRGB(96, 205, 255)
return {
	["colors/Fill_Color/Text/Primary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0,
	},
	["colors/Fill_Color/Text/Secondary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.21568627450980393,
	},
	["colors/Fill_Color/Text/Tertiary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.4549019607843138,
	},
	["colors/Fill_Color/Text/Disabled"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.6352941176470588,
	},
	["colors/Fill_Color/Accent_Text/Primary"] = {
		Color = Color3.fromRGB(153, 235, 255),
		Transparency = 0,
	},
	["colors/Fill_Color/Accent_Text/Secondary"] = {
		Color = Color3.fromRGB(153, 235, 255),
		Transparency = 0,
	},
	["colors/Fill_Color/Accent_Text/Tertiary"] = {
		Color = AccentColor,
		Transparency = 0,
	},
	["colors/Fill_Color/Accent_Text/Disabled"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.6352941176470588,
	},
	["colors/Fill_Color/Text_On_Accent/Primary"] = {
		Color = Color3.fromRGB(0, 0, 0),
		Transparency = 0,
	},
	["colors/Fill_Color/Text_On_Accent/Secondary"] = {
		Color = Color3.fromRGB(0, 0, 0),
		Transparency = 0.4980392156862745,
	},
	["colors/Fill_Color/Text_On_Accent/Disabled"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.47058823529411764,
	},
	["colors/Fill_Color/Text_On_Accent/Selected_Text"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0,
	},
	["colors/Fill_Color/Control/Transparent"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 1,
	},
	["colors/Fill_Color/Control/Default"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9411764705882353,
	},
	["colors/Fill_Color/Control/Secondary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9176470588235294,
	},
	["colors/Fill_Color/Control/Tertiary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9686274509803922,
	},
	["colors/Fill_Color/Control/Quarternary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9411764705882353,
	},
	["colors/Fill_Color/Control/Disabled"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9568627450980393,
	},
	["colors/Fill_Color/Control/Input_Active"] = {
		Color = Color3.fromRGB(30, 30, 30),
		Transparency = 0.3019607843137255,
	},
	["colors/Fill_Color/Control_Strong/Default"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.4549019607843138,
	},
	["colors/Fill_Color/Control_Strong/Disabled"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.7529411764705882,
	},
	["colors/Fill_Color/Control_Alt/Transparent"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 1,
	},
	["colors/Fill_Color/Control_Alt/Secondary"] = {
		Color = Color3.fromRGB(0, 0, 0),
		Transparency = 0.8980392156862745,
	},
	["colors/Fill_Color/Control_Alt/Tertiary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9568627450980393,
	},
	["colors/Fill_Color/Control_Alt/Quarternary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9294117647058824,
	},
	["colors/Fill_Color/Control_Alt/Disabled"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 1,
	},
	["colors/Fill_Color/Subtle/Transparent"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 1,
	},
	["colors/Fill_Color/Subtle/Secondary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9411764705882353,
	},
	["colors/Fill_Color/Subtle/Tertiary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9568627450980393,
	},
	["colors/Fill_Color/Subtle/Disabled"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 1,
	},
	["colors/Fill_Color/Accent/Default"] = {
		Color = AccentColor,
		Transparency = 0,
	},
	["colors/Fill_Color/Accent/Secondary"] = {
		Color = AccentColor,
		Transparency = 0.10196078431372546,
	},
	["colors/Fill_Color/Accent/Tertiary"] = {
		Color = AccentColor,
		Transparency = 0.19999999999999996,
	},
	["colors/Fill_Color/Accent/Disabled"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.8431372549019608,
	},
	["colors/Fill_Color/Accent/Selected_Text_Background"] = {
		Color = Color3.fromRGB(0, 120, 212),
		Transparency = 0,
	},
	["colors/Fill_Color/Control_Solid/Default"] = {
		Color = Color3.fromRGB(69, 69, 69),
		Transparency = 0,
	},
	["colors/Fill_Color/System/Critical"] = {
		Color = Color3.fromRGB(255, 153, 164),
		Transparency = 0,
	},
	["colors/Fill_Color/System/Success"] = {
		Color = Color3.fromRGB(108, 203, 95),
		Transparency = 0,
	},
	["colors/Fill_Color/System/Attention"] = {
		Color = AccentColor,
		Transparency = 0,
	},
	["colors/Fill_Color/System/Caution"] = {
		Color = Color3.fromRGB(252, 225, 0),
		Transparency = 0,
	},
	["colors/Fill_Color/System/Attention_Background"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9686274509803922,
	},
	["colors/Fill_Color/System/Success_Background"] = {
		Color = Color3.fromRGB(57, 61, 27),
		Transparency = 0,
	},
	["colors/Fill_Color/System/Caution_Background"] = {
		Color = Color3.fromRGB(67, 53, 25),
		Transparency = 0,
	},
	["colors/Fill_Color/System/Critical_Background"] = {
		Color = Color3.fromRGB(68, 39, 38),
		Transparency = 0,
	},
	["colors/Fill_Color/System/Neutral"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.4549019607843138,
	},
	["colors/Fill_Color/System/Neutral_Background"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9686274509803922,
	},
	["colors/Fill_Color/System/Solid_Attention_Background"] = {
		Color = Color3.fromRGB(46, 46, 46),
		Transparency = 0,
	},
	["colors/Fill_Color/System/Solid_Neutral"] = {
		Color = Color3.fromRGB(157, 157, 157),
		Transparency = 0,
	},
	["colors/Fill_Color/System/Solid_Neutral_Background"] = {
		Color = Color3.fromRGB(46, 46, 46),
		Transparency = 0,
	},
	["colors/Fill_Color/Control_On_Image/Default"] = {
		Color = Color3.fromRGB(28, 28, 28),
		Transparency = 0.3019607843137255,
	},
	["colors/Fill_Color/Control_On_Image/Secondary"] = {
		Color = Color3.fromRGB(26, 26, 26),
		Transparency = 0,
	},
	["colors/Fill_Color/Control_On_Image/Tertiary"] = {
		Color = Color3.fromRGB(19, 19, 19),
		Transparency = 0,
	},
	["colors/Fill_Color/Control_On_Image/Disabled"] = {
		Color = Color3.fromRGB(30, 30, 30),
		Transparency = 1,
	},
	["colors/Stroke_Color/Control_Stroke/Default"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9294117647058824,
	},
	["colors/Stroke_Color/Control_Stroke/On_Accent_Default"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9215686274509804,
	},
	["colors/Stroke_Color/Control_Stroke/Secondary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9058823529411765,
	},
	["colors/Stroke_Color/Control_Stroke/On_Accent_Secondary"] = {
		Color = Color3.fromRGB(0, 0, 0),
		Transparency = 0.8588235294117648,
	},
	["colors/Stroke_Color/Control_Stroke/On_Accent_Tertiary"] = {
		Color = Color3.fromRGB(0, 0, 0),
		Transparency = 0.7843137254901961,
	},
	["colors/Stroke_Color/Control_Stroke/On_Accent_Disabled"] = {
		Color = Color3.fromRGB(0, 0, 0),
		Transparency = 0.8,
	},
	["colors/Stroke_Color/Control_Stroke/For_Strong_Fill_When_On_Image"] = {
		Color = Color3.fromRGB(0, 0, 0),
		Transparency = 0.580392156862745,
	},
	["colors/Stroke_Color/Control_Strong_Stroke/Default"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.39607843137254906,
	},
	["colors/Stroke_Color/Control_Strong_Stroke/Disabled"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.8431372549019608,
	},
	["colors/Stroke_Color/Divider_Stroke/Default"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9176470588235294,
	},
	["colors/Stroke_Color/Surface_Stroke/Default"] = {
		Color = Color3.fromRGB(117, 117, 117),
		Transparency = 0.6,
	},
	["colors/Stroke_Color/Surface_Stroke/Flyout"] = {
		Color = Color3.fromRGB(0, 0, 0),
		Transparency = 0.8,
	},
	["colors/Stroke_Color/Card_Stroke/Default"] = {
		Color = Color3.fromRGB(0, 0, 0),
		Transparency = 0.8980392156862745,
	},
	["colors/Stroke_Color/Card_Stroke/Default_Solid"] = {
		Color = Color3.fromRGB(28, 28, 28),
		Transparency = 0,
	},
	["colors/Stroke_Color/Focus_Stroke/Outer"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0,
	},
	["colors/Stroke_Color/Focus_Stroke/Inner"] = {
		Color = Color3.fromRGB(0, 0, 0),
		Transparency = 0.3019607843137255,
	},
	["colors/Background/Fill_Color/Card_Background/Default"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9490196078431372,
	},
	["colors/Background/Fill_Color/Card_Background/Secondary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9686274509803922,
	},
	["colors/Background/Fill_Color/Card_Background/Tertiary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9294117647058824,
	},
	["colors/Background/Fill_Color/Smoke/Default"] = {
		Color = Color3.fromRGB(0, 0, 0),
		Transparency = 0.6980392156862745,
	},
	["colors/Background/Fill_Color/Layer/Default"] = {
		Color = Color3.fromRGB(58, 58, 58),
		Transparency = 0.6980392156862745,
	},
	["colors/Background/Fill_Color/Layer/Alt"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9450980392156862,
	},
	["colors/Background/Fill_Color/Layer_On_Acrylic/Default"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9647058823529412,
	},
	["colors/Background/Fill_Color/Layer_on_Accent_Acrylic/Default"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9647058823529412,
	},
	["colors/Background/Fill_Color/Acrylic_Background/Default"] = {
		Color = Color3.fromRGB(44, 44, 44),
		Transparency = 0.039215686274509776,
	},
	["colors/Background/Fill_Color/Acrylic_Background/Base"] = {
		Color = Color3.fromRGB(32, 32, 32),
		Transparency = 0.039215686274509776,
	},
	["colors/Background/Fill_Color/Accent_Acrylic_Background/Base"] = {
		Color = Color3.fromRGB(0, 63, 146),
		Transparency = 0.19999999999999996,
	},
	["colors/Background/Fill_Color/Accent_Acrylic_Background/Default"] = {
		Color = Color3.fromRGB(0, 120, 212),
		Transparency = 0.19999999999999996,
	},
	["colors/Background/Fill_Color/Layer_On_Mica_Base_Alt/Default"] = {
		Color = Color3.fromRGB(58, 58, 58),
		Transparency = 0.5490196078431373,
	},
	["colors/Background/Fill_Color/Layer_On_Mica_Base_Alt/Transparent"] = {
		Color = Color3.fromRGB(0, 0, 0),
		Transparency = 1,
	},
	["colors/Background/Fill_Color/Layer_On_Mica_Base_Alt/Secondary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9411764705882353,
	},
	["colors/Background/Fill_Color/Layer_On_Mica_Base_Alt/Tertiary"] = {
		Color = Color3.fromRGB(44, 44, 44),
		Transparency = 0,
	},
	["colors/Background/Fill_Color/Mica_Background/Base"] = {
		Color = Color3.fromRGB(32, 32, 32),
		Transparency = 0,
	},
	["colors/Background/Fill_Color/Mica_Background/Base_Alt"] = {
		Color = Color3.fromRGB(10, 10, 10),
		Transparency = 0,
	},
	["colors/Background/Fill_Color/Solid_Background/Base"] = {
		Color = Color3.fromRGB(32, 32, 32),
		Transparency = 0,
	},
	["colors/Background/Fill_Color/Solid_Background/Base_Alt"] = {
		Color = Color3.fromRGB(10, 10, 10),
		Transparency = 0,
	},
	["colors/Background/Fill_Color/Solid_Background/Secondary"] = {
		Color = Color3.fromRGB(28, 28, 28),
		Transparency = 0,
	},
	["colors/Background/Fill_Color/Solid_Background/Tertiary"] = {
		Color = Color3.fromRGB(40, 40, 40),
		Transparency = 0,
	},
	["colors/Background/Fill_Color/Solid_Background/Quarternary"] = {
		Color = Color3.fromRGB(44, 44, 44),
		Transparency = 0,
	},
	["colors/Background/Fill_Color/Solid_Background/Quinary"] = {
		Color = Color3.fromRGB(51, 51, 51),
		Transparency = 0,
	},
	["colors/Background/Fill_Color/Solid_Background/Senary"] = {
		Color = Color3.fromRGB(55, 55, 55),
		Transparency = 0,
	},
	["colors/Shell/Fill_Color/Caption_Close_Text/Primary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0,
	},
	["colors/Shell/Fill_Color/Caption_Close_Text/Secondary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.3019607843137255,
	},
	["colors/Shell/Fill_Color/Caption_Control_Close_Fill/Primary"] = {
		Color = Color3.fromRGB(196, 43, 28),
		Transparency = 0,
	},
	["colors/Shell/Fill_Color/Caption_Control_Close_Fill/Secondary"] = {
		Color = Color3.fromRGB(196, 43, 28),
		Transparency = 0.10196078431372546,
	},
	["colors/Shell/Fill_Color/Keyboard_Button_Alt/Default"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9137254901960784,
	},
	["colors/Shell/Fill_Color/Keyboard_Button_Alt/Secondary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.8745098039215686,
	},
	["colors/Shell/Fill_Color/Keyboard_Button_Alt/Tertiary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9333333333333333,
	},
	["colors/Shell/Fill_Color/Keyboard_Button_Alt/Disabled"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9647058823529412,
	},
	["colors/Shell/Fill_Color/Keyboard_Button/Default"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.8745098039215686,
	},
	["colors/Shell/Fill_Color/Keyboard_Button/Secondary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9137254901960784,
	},
	["colors/Shell/Fill_Color/Keyboard_Button/Tertiary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9333333333333333,
	},
	["colors/Shell/Fill_Color/Keyboard_Button/Disabled"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9647058823529412,
	},
	["colors/Shell/Fill_Color/Taskbar_Item_Fill/Primary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9176470588235294,
	},
	["colors/Shell/Fill_Color/Taskbar_Item_Fill/Secondary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9411764705882353,
	},
	["colors/Shell/Fill_Color/Taskbar_Item_Fill/Tertiary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9568627450980393,
	},
	["colors/Shell/Fill_Color/Taskbar_Item_Fill/Transparent"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 1,
	},
	["colors/Shell/Fill_Color/Taskbar_Item_Indicator/Running"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.611764705882353,
	},
	["colors/Shell/Fill_Color/Subtle_Item_Fill/Transparent"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 1,
	},
	["colors/Shell/Fill_Color/Subtle_Item_Fill/Secondary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9411764705882353,
	},
	["colors/Shell/Fill_Color/Subtle_Item_Fill/Tertiary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9568627450980393,
	},
	["colors/Shell/Fill_Color/Shimmer_Fill/Primary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9411764705882353,
	},
	["colors/Shell/Fill_Color/Shimmer_Fill/Secondary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9686274509803922,
	},
	["colors/Shell/Fill_Color/Illustration_On_Acrylic/Primary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.8392156862745098,
	},
	["colors/Shell/Stroke_Color/Keyboard_Button/Primary"] = {
		Color = Color3.fromRGB(0, 0, 0),
		Transparency = 0.8509803921568627,
	},
	["colors/Shell/Stroke_Color/Keyboard_Button/Secondary"] = {
		Color = Color3.fromRGB(0, 0, 0),
		Transparency = 0.6980392156862745,
	},
	["colors/Shell/Stroke_Color/Taskbar_Item_Stroke/Primary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.8745098039215686,
	},
	["colors/Shell/Stroke_Color/Taskbar_Item_Stroke/Secondary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.8980392156862745,
	},
	["colors/Shell/Stroke_Color/Taskbar_Item_Stroke/Tertiary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9176470588235294,
	},
	["colors/Shell/Stroke_Color/Taskbar_Item_Stroke/Quarternary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9411764705882353,
	},
	["colors/Shell/Stroke_Color/Taskbar_Item_Stroke/Quinary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.9568627450980393,
	},
	["colors/Shell/Stroke_Color/Illustration_On_Acrylic_Strong/Primary"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.580392156862745,
	},
	["colors/Shell/Background/Fill_Color/Card_Background_On_Thin_Acrylic/Default"] = {
		Color = Color3.fromRGB(0, 0, 0),
		Transparency = 0.34901960784313724,
	},
	["colors/Shell/Background/Fill_Color/Card_Background_On_Thin_Acrylic/Secondary"] = {
		Color = Color3.fromRGB(0, 0, 0),
		Transparency = 0.4745098039215686,
	},
	["colors/Shell/Background/Fill_Color/Layer_On_Thin_Acrylic/Default"] = {
		Color = Color3.fromRGB(0, 0, 0),
		Transparency = 0.8,
	},
	["colors/Shell/Background/Fill_Color/Acrylic/Thin_Acrylic"] = {
		Color = Color3.fromRGB(84, 84, 84),
		Transparency = 0.36078431372549025,
	},
	["colors/Contrast/Aquatic/Window_Text"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0,
	},
	["colors/Contrast/Aquatic/Window"] = {
		Color = Color3.fromRGB(32, 32, 32),
		Transparency = 0,
	},
	["colors/Contrast/Aquatic/Highlight_Text"] = {
		Color = Color3.fromRGB(38, 59, 80),
		Transparency = 0,
	},
	["colors/Contrast/Aquatic/Highlight"] = {
		Color = Color3.fromRGB(142, 227, 240),
		Transparency = 0,
	},
	["colors/Contrast/Aquatic/Button_Text"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0,
	},
	["colors/Contrast/Aquatic/Button"] = {
		Color = Color3.fromRGB(32, 32, 32),
		Transparency = 0,
	},
	["colors/Contrast/Aquatic/Hotlight"] = {
		Color = Color3.fromRGB(117, 233, 252),
		Transparency = 0,
	},
	["colors/Contrast/Aquatic/Gray_Text"] = {
		Color = Color3.fromRGB(166, 166, 166),
		Transparency = 0,
	},
	["colors/Contrast/Desert/Window_Text"] = {
		Color = Color3.fromRGB(61, 61, 61),
		Transparency = 0,
	},
	["colors/Contrast/Desert/WIndow"] = {
		Color = Color3.fromRGB(255, 250, 239),
		Transparency = 0,
	},
	["colors/Contrast/Desert/Highlight_Text"] = {
		Color = Color3.fromRGB(255, 245, 227),
		Transparency = 0,
	},
	["colors/Contrast/Desert/Highlight"] = {
		Color = Color3.fromRGB(144, 57, 9),
		Transparency = 0,
	},
	["colors/Contrast/Desert/Button_Text"] = {
		Color = Color3.fromRGB(32, 32, 32),
		Transparency = 0,
	},
	["colors/Contrast/Desert/Button"] = {
		Color = Color3.fromRGB(255, 250, 239),
		Transparency = 0,
	},
	["colors/Contrast/Desert/Hotlight"] = {
		Color = Color3.fromRGB(28, 94, 117),
		Transparency = 0,
	},
	["colors/Contrast/Desert/Gray_Text"] = {
		Color = Color3.fromRGB(103, 103, 103),
		Transparency = 0,
	},
	["colors/Contrast/Dusk/Window_Text"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0,
	},
	["colors/Contrast/Dusk/Window"] = {
		Color = Color3.fromRGB(45, 50, 54),
		Transparency = 0,
	},
	["colors/Contrast/Dusk/Highlight_Text"] = {
		Color = Color3.fromRGB(33, 45, 59),
		Transparency = 0,
	},
	["colors/Contrast/Dusk/Highlight"] = {
		Color = Color3.fromRGB(171, 207, 242),
		Transparency = 0,
	},
	["colors/Contrast/Dusk/Button_Text"] = {
		Color = Color3.fromRGB(182, 246, 240),
		Transparency = 0,
	},
	["colors/Contrast/Dusk/Button"] = {
		Color = Color3.fromRGB(45, 50, 54),
		Transparency = 0,
	},
	["colors/Contrast/Dusk/Hotlight"] = {
		Color = Color3.fromRGB(112, 235, 222),
		Transparency = 0,
	},
	["colors/Contrast/Dusk/Gray_Text"] = {
		Color = Color3.fromRGB(166, 166, 166),
		Transparency = 0,
	},
	["colors/Contrast/Night_Sky/Window_Text"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0,
	},
	["colors/Contrast/Night_Sky/Window"] = {
		Color = Color3.fromRGB(0, 0, 0),
		Transparency = 0,
	},
	["colors/Contrast/Night_Sky/Highlight_Text"] = {
		Color = Color3.fromRGB(43, 43, 43),
		Transparency = 0,
	},
	["colors/Contrast/Night_Sky/Highlight"] = {
		Color = Color3.fromRGB(214, 180, 253),
		Transparency = 0,
	},
	["colors/Contrast/Night_Sky/Button_Text"] = {
		Color = Color3.fromRGB(255, 238, 50),
		Transparency = 0,
	},
	["colors/Contrast/Night_Sky/Button"] = {
		Color = Color3.fromRGB(0, 0, 0),
		Transparency = 0,
	},
	["colors/Contrast/Night_Sky/Hotlight"] = {
		Color = Color3.fromRGB(128, 128, 255),
		Transparency = 0,
	},
	["colors/Contrast/Night_Sky/Gray_Text"] = {
		Color = Color3.fromRGB(166, 166, 166),
		Transparency = 0,
	},

	-- Custom
	["colors/Elevation/Accent_Control/Border"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.08,
		ColorSequence = ColorSequence.new({
			[1] = ColorSequenceKeypoint.new(0, Color3.fromRGB(255, 255, 255)),
			[2] = ColorSequenceKeypoint.new(0.6, Color3.fromRGB(255, 255, 255)),
			[3] = ColorSequenceKeypoint.new(1, Color3.fromRGB(0, 0, 0)),
		}),
		TransparencySequence = NumberSequence.new({
			[1] = NumberSequenceKeypoint.new(0, 1 - 0.08),
			[2] = NumberSequenceKeypoint.new(0.6, 1 - 0.08),
			[3] = NumberSequenceKeypoint.new(1, 1 - 0.14),
		}),
	},
	["colors/Elevation/Control/Border"] = {
		Color = Color3.fromRGB(255, 255, 255),
		Transparency = 0.07,
		ColorSequence = ColorSequence.new({
			[1] = ColorSequenceKeypoint.new(0, Color3.fromRGB(255, 255, 255)),
			[2] = ColorSequenceKeypoint.new(0.1, Color3.fromRGB(255, 255, 255)),
			[3] = ColorSequenceKeypoint.new(1, Color3.fromRGB(255, 255, 255)),
		}),
		TransparencySequence = NumberSequence.new({
			[1] = NumberSequenceKeypoint.new(0, 1 - 0.093),
			[2] = NumberSequenceKeypoint.new(0.1, 1 - 0.0698),
			[3] = NumberSequenceKeypoint.new(1, 1 - 0.0698),
		}),
	},
}