local C=script.Parent.Parent.Parent.Parent local U=C.Parent local Z=require(C.Theme)local b=Z.WithTheme local p=Z.ApplyDescription local w=Z.RegisterStateAction local m=C.Validators local O=require(m.StyleValidator)local M=require(U.Sift)local r=require(U.t)local W=require(U.Roact)local V=W.createElement local X=script.Parent local i=require(X.Validators.ButtonStyleValidator)local l=require(X.Descriptions.ButtonStateDescriptions)local n="\115\116\121\108\101\115\047\065\110\105\109\097\116\105\111\110\083\112\114\105\110\103\080\097\114\097\109\115\047\067\111\110\116\114\111\108\047\073\110\112\117\116\047\066\117\116\116\111\110\047\067\111\108\111\114"local o="\115\116\121\108\101\115\047\065\110\105\109\097\116\105\111\110\083\112\114\105\110\103\080\097\114\097\109\115\047\067\111\110\116\114\111\108\047\073\110\112\117\116\047\066\117\116\116\111\110\047\084\114\097\110\115\112\097\114\101\110\099\121"local x=W.PureComponent:extend(script.Name)x.StyleBindings={"\070\105\108\108";"\083\116\114\111\107\101";"\084\101\120\116"}x.defaultProps={AnchorPoint=Vector2.new(.5,.5),BorderSizePixel=1;Font="\102\111\110\116\115\047\066\111\100\121",Position=UDim2.fromScale(.5,.5),Size=UDim2.fromOffset(240,30);Style="\083\116\097\110\100\097\114\100",Text="\084\101\120\116"}x.validateProps=r.strictInterface({AnchorPoint=r.optional(r.Vector2),BackgroundColor=r.optional(O);BorderColor=r.optional(O);BorderSizePixel=r.optional(r.numberPositive);CornerRadius=r.optional(r.UDim),Disabled=r.optional(r.boolean),Font=r.optional(O),LayoutOrder=r.optional(r.number);Position=r.optional(r.UDim2);Size=r.optional(r.UDim2);Style=r.optional(i),Text=r.optional(r.string),Native=r.optional(r.table);[W.Children]=r.optional(r.table);[W.Event.Activated]=r.optional(r.callback),[W.Event.MouseButton1Down]=r.optional(r.callback);[W.Event.MouseButton1Up]=r.optional(r.callback),[W.Event.MouseEnter]=r.optional(r.callback);[W.Event.MouseLeave]=r.optional(r.callback)})function x.init(C)for U,Z in pairs(C.StyleBindings)do C[Z],C["\083\101\116"..Z]=W.createBinding({})end w(C,W.Event.Activated,nil)w(C,W.Event.MouseButton1Down,"\080\114\101\115\115\101\100")w(C,W.Event.MouseButton1Up,"\072\111\118\101\114")w(C,W.Event.MouseEnter,"\072\111\118\101\114")w(C,W.Event.MouseLeave,"\082\101\115\116")C:setState({State="\082\101\115\116"})end function x.willUnmount(C)for U,Z in pairs(C.StyleBindings)do local b=C[Z.."\077\111\116\111\114"]if b then pcall(b.destroy,b)C[Z.."\077\111\116\111\114"]=nil end end end function x.ApplyDescription(Z,C,U)local b=Z.props C=M.Dictionary.copy(C)local w=b.BackgroundColor local m=b.BorderColor local O=b.TextColor if w then C.Fill=w end if m then C.Stroke=m end if O then C.Text=O end p(Z,C,U,U[n],U[o])end function x.render(C)local U=C.props local Z=C.state return b(function(b)if U.Style=="\065\099\099\101\110\116"then if U.Disabled then C:ApplyDescription(l.Accent.Disabled,b)elseif Z.State=="\082\101\115\116"then C:ApplyDescription(l.Accent.Rest,b)elseif Z.State=="\072\111\118\101\114"then C:ApplyDescription(l.Accent.Hover,b)elseif Z.State=="\080\114\101\115\115\101\100"then C:ApplyDescription(l.Accent.Pressed,b)end elseif U.Style=="\083\116\097\110\100\097\114\100"or U.Style=="\068\101\102\097\117\108\116"then if U.Disabled then C:ApplyDescription(l.Standard.Disabled,b)elseif Z.State=="\082\101\115\116"then C:ApplyDescription(l.Standard.Rest,b)elseif Z.State=="\072\111\118\101\114"then C:ApplyDescription(l.Standard.Hover,b)elseif Z.State=="\080\114\101\115\115\101\100"then C:ApplyDescription(l.Standard.Pressed,b)end elseif U.Style=="\080\114\105\109\097\114\121"then if U.Disabled then C:ApplyDescription(l.Primary.Disabled,b)elseif Z.State=="\082\101\115\116"then C:ApplyDescription(l.Primary.Rest,b)elseif Z.State=="\072\111\118\101\114"then C:ApplyDescription(l.Primary.Hover,b)elseif Z.State=="\080\114\101\115\115\101\100"then C:ApplyDescription(l.Primary.Pressed,b)end elseif U.Style=="\083\101\099\111\110\100\097\114\121"then if U.Disabled then C:ApplyDescription(l.Secondary.Disabled,b)elseif Z.State=="\082\101\115\116"then C:ApplyDescription(l.Secondary.Rest,b)elseif Z.State=="\072\111\118\101\114"then C:ApplyDescription(l.Secondary.Hover,b)elseif Z.State=="\080\114\101\115\115\101\100"then C:ApplyDescription(l.Secondary.Pressed,b)end end local p=V("\085\073\083\116\114\111\107\101",{Enabled=not U.Disabled;ApplyStrokeMode="\066\111\114\100\101\114",Thickness=U.BorderSizePixel,Color=C.Stroke:map(function(C)return C.Color end)},{Gradient=V("\085\073\071\114\097\100\105\101\110\116",{Rotation=90,Color=C.Stroke:map(function(C)return C.ColorSequence or ColorSequence.new(C.Color)end);Transparency=C.Stroke:map(function(C)return C.TransparencySequence or NumberSequence.new(C.Transparency)end)})})local w=b[U.Font]local m=V("\084\101\120\116\066\117\116\116\111\110",{AutoButtonColor=false;AnchorPoint=Vector2.new(.5,.5);FontFace=w.Font,Position=UDim2.fromScale(.5,.5),Size=UDim2.fromScale(1,1)-UDim2.fromOffset(2,2),Text=U.Text;TextSize=w.Size;BackgroundColor3=C.Fill:map(function(C)return C.Color end);BackgroundTransparency=C.Fill:map(function(C)return C.Transparency end);TextColor3=C.Text:map(function(C)return C.Color end),TextTransparency=C.Text:map(function(C)return C.Transparency end);[W.Event.Activated]=C[W.Event.Activated];[W.Event.MouseButton1Down]=C[W.Event.MouseButton1Down];[W.Event.MouseButton1Up]=C[W.Event.MouseButton1Up],[W.Event.MouseEnter]=C[W.Event.MouseEnter],[W.Event.MouseLeave]=C[W.Event.MouseLeave]},{Stroke=p;Corners=V("\085\073\067\111\114\110\101\114",{CornerRadius=U.CornerRadius or UDim.new(0,b["\115\116\121\108\101\115\047\067\111\114\110\101\114\082\097\100\105\117\115\047\068\101\102\097\117\108\116\047\073\110\110\101\114"])})})local O=U[W.Children]and V("\070\114\097\109\101",{BackgroundTransparency=1,Size=UDim2.fromScale(1,1)},U[W.Children])or nil return V("\070\114\097\109\101",M.Dictionary.join({AnchorPoint=U.AnchorPoint;BackgroundTransparency=1;LayoutOrder=U.LayoutOrder,Position=U.Position;Size=U.Size},U.Native),{Button=m;ContentWrapper=O})end)end return x
-- Button: The basic button component
-- https://www.figma.com/file/uNmIxgdbUT44MZjQCTIMe3/Windows-UI-3-(Community)?node-id=24412%3A121169

local Winro = script.Parent.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 Sift = require(Packages.Sift)
local t = require(Packages.t)
local Roact = require(Packages.Roact)
local new = Roact.createElement

local ButtonRoot = script.Parent
local ButtonStyleValidator = require(ButtonRoot.Validators.ButtonStyleValidator)
local Descriptions = require(ButtonRoot.Descriptions.ButtonStateDescriptions)

local BUTTON_COLOR_ANIMATION_SPRING_SETTINGS = "styles/AnimationSpringParams/Control/Input/Button/Color"
local BUTTON_TRANSPARENCY_ANIMATION_SPRING_SETTINGS = "styles/AnimationSpringParams/Control/Input/Button/Transparency"

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

Button.StyleBindings = {
	'Fill',
	'Stroke',
	'Text',
}

Button.defaultProps = {
	AnchorPoint = Vector2.new(0.5, 0.5), --- @defaultProp
	BorderSizePixel = 1, --- @defaultProp
	Font = "fonts/Body", --- @defaultProp
	Position = UDim2.fromScale(0.5, 0.5), --- @defaultProp
	Size = UDim2.fromOffset(240, 30), --- @defaultProp
	Style = 'Standard', --- @defaultProp
	Text = 'Text', --- @defaultProp
}

Button.validateProps = t.strictInterface({

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

	--- @prop @optional @style BackgroundColor string|table The style to use for the Button's background color
	BackgroundColor = t.optional(StyleValidator),

	--- @prop @optional @style BorderColor string|table The button's border style
	BorderColor = t.optional(StyleValidator),

	--- @prop @optional BorderSizePixel number The size, in pixels, of the border
	BorderSizePixel = t.optional(t.numberPositive),

	--- @prop @optional CornerRadius UDim The radius of the Button's corners
	CornerRadius = t.optional(t.UDim),

	--- @prop @optional Disabled boolean If `true`, the button will appear as disabled
	Disabled = t.optional(t.boolean),

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

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

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

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

	--- @prop @optional Style string The Button's style
	Style = t.optional(ButtonStyleValidator),

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

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

	--- @prop @optional [Roact.Children] table Child contents
	[Roact.Children] = 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 Button:init()

	-- 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 Button: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 Button:ApplyDescription(Description, Theme)
	local props = self.props
	Description = Sift.Dictionary.copy(Description)
	
	-- Prop Overrides
	local FillOverride = props.BackgroundColor
	local StrokeOverride = props.BorderColor
	local TextOverride = props.TextColor

	if FillOverride then
		Description.Fill = FillOverride
	end

	if StrokeOverride then
		Description.Stroke = StrokeOverride
	end

	if TextOverride then
		Description.Text = TextOverride
	end

	ApplyDescription(self, Description, Theme, Theme[BUTTON_COLOR_ANIMATION_SPRING_SETTINGS], Theme[BUTTON_TRANSPARENCY_ANIMATION_SPRING_SETTINGS])
end

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

	return WithTheme(function(Theme)

		-- Apply Description
		if props.Style == 'Accent' then
			if props.Disabled then
				self:ApplyDescription(Descriptions.Accent.Disabled, Theme)
			elseif state.State == 'Rest' then
				self:ApplyDescription(Descriptions.Accent.Rest, Theme)
			elseif state.State == 'Hover' then
				self:ApplyDescription(Descriptions.Accent.Hover, Theme)
			elseif state.State == 'Pressed' then
				self:ApplyDescription(Descriptions.Accent.Pressed, Theme)
			end
		elseif props.Style == 'Standard' or props.Style == 'Default' then
			if props.Disabled then
				self:ApplyDescription(Descriptions.Standard.Disabled, Theme)
			elseif state.State == 'Rest' then
				self:ApplyDescription(Descriptions.Standard.Rest, Theme)
			elseif state.State == 'Hover' then
				self:ApplyDescription(Descriptions.Standard.Hover, Theme)
			elseif state.State == 'Pressed' then
				self:ApplyDescription(Descriptions.Standard.Pressed, Theme)
			end
		elseif props.Style == 'Primary' then
			if props.Disabled then
				self:ApplyDescription(Descriptions.Primary.Disabled, Theme)
			elseif state.State == 'Rest' then
				self:ApplyDescription(Descriptions.Primary.Rest, Theme)
			elseif state.State == 'Hover' then
				self:ApplyDescription(Descriptions.Primary.Hover, Theme)
			elseif state.State == 'Pressed' then
				self:ApplyDescription(Descriptions.Primary.Pressed, Theme)
			end
		elseif props.Style == 'Secondary' then
			if props.Disabled then
				self:ApplyDescription(Descriptions.Secondary.Disabled, Theme)
			elseif state.State == 'Rest' then
				self:ApplyDescription(Descriptions.Secondary.Rest, Theme)
			elseif state.State == 'Hover' then
				self:ApplyDescription(Descriptions.Secondary.Hover, Theme)
			elseif state.State == 'Pressed' then
				self:ApplyDescription(Descriptions.Secondary.Pressed, Theme)
			end
		end

		-- ////////// Button Stroke

		local Stroke = new('UIStroke', {
			Enabled = not props.Disabled,
			ApplyStrokeMode = 'Border',
			Thickness = props.BorderSizePixel,

			Color = self.Stroke:map(function(Style)
				return Style.Color
			end),
		}, {

			Gradient = new('UIGradient', {
				Rotation = 90,

				Color = self.Stroke:map(function(Style)
					return (Style.ColorSequence or ColorSequence.new(Style.Color))
				end),
				Transparency = self.Stroke:map(function(Style)
					return (Style.TransparencySequence or NumberSequence.new(Style.Transparency))
				end),
			})
		})

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

		local ButtonFont = Theme[props.Font]

		local Button = new('TextButton', {
			AutoButtonColor = false,
			AnchorPoint = Vector2.new(0.5, 0.5),
			FontFace = ButtonFont.Font,
			Position = UDim2.fromScale(0.5, 0.5),
			Size = UDim2.fromScale(1, 1) - UDim2.fromOffset(2, 2), -- Account for stroke thickness
			Text = props.Text,
			TextSize = ButtonFont.Size,

			BackgroundColor3 = self.Fill:map(function(Style)
				return Style.Color
			end),
			BackgroundTransparency = self.Fill:map(function(Style)
				return Style.Transparency
			end),
			TextColor3 = self.Text:map(function(Style)
				return Style.Color
			end),
			TextTransparency = self.Text: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],
		}, {
			Stroke = Stroke,

			Corners = new('UICorner', {
				CornerRadius = props.CornerRadius or UDim.new(0, Theme['styles/CornerRadius/Default/Inner']),
			}),
		})

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

		local ContentWrapper = props[Roact.Children] and new('Frame', {
			BackgroundTransparency = 1,
			Size = UDim2.fromScale(1, 1),
		}, props[Roact.Children]) or nil

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

return Button
