rojo 7.6.1

Enables professional-grade development tools for Roblox developers
Documentation
local Rojo = script:FindFirstAncestor("Rojo")
local Plugin = Rojo.Plugin
local Packages = Rojo.Packages

local Roact = require(Packages.Roact)
local Flipper = require(Packages.Flipper)

local Assets = require(Plugin.Assets)
local Theme = require(Plugin.App.Theme)
local bindingUtil = require(Plugin.App.bindingUtil)
local getTextBoundsAsync = require(Plugin.App.getTextBoundsAsync)

local SlicedImage = require(script.Parent.SlicedImage)
local ScrollingFrame = require(script.Parent.ScrollingFrame)
local Tooltip = require(script.Parent.Tooltip)

local e = Roact.createElement

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

function Dropdown:init()
	self.openMotor = Flipper.SingleMotor.new(0)
	self.openBinding = bindingUtil.fromMotor(self.openMotor)

	self.contentSize, self.setContentSize = Roact.createBinding(Vector2.new(0, 0))

	self:setState({
		open = false,
	})
end

function Dropdown:didUpdate(prevProps)
	if self.props.locked and not prevProps.locked then
		self:setState({
			open = false,
		})
	end

	self.openMotor:setGoal(Flipper.Spring.new(self.state.open and 1 or 0, {
		frequency = 6,
		dampingRatio = 1.1,
	}))
end

function Dropdown:render()
	return Theme.with(function(theme)
		local dropdownTheme = theme.Dropdown

		local optionButtons = {}
		local width = -1
		for i, option in self.props.options do
			local text = tostring(option or "")
			local textBounds = getTextBoundsAsync(text, theme.Font.Main, theme.TextSize.Body, math.huge)
			if textBounds.X > width then
				width = textBounds.X
			end

			optionButtons[text] = e("TextButton", {
				Text = text,
				LayoutOrder = i,
				Size = UDim2.new(1, 0, 0, 24),
				BackgroundColor3 = dropdownTheme.BackgroundColor,
				TextTransparency = self.props.transparency,
				BackgroundTransparency = self.props.transparency,
				BorderSizePixel = 0,
				TextColor3 = dropdownTheme.TextColor,
				TextXAlignment = Enum.TextXAlignment.Left,
				TextSize = theme.TextSize.Body,
				FontFace = theme.Font.Main,

				[Roact.Event.Activated] = function()
					if self.props.locked then
						return
					end
					self:setState({
						open = false,
					})
					self.props.onClick(option)
				end,
			}, {
				Padding = e("UIPadding", {
					PaddingLeft = UDim.new(0, 6),
				}),
			})
		end

		return e("ImageButton", {
			Size = UDim2.new(0, width + 50, 0, 28),
			Position = self.props.position,
			AnchorPoint = self.props.anchorPoint,
			LayoutOrder = self.props.layoutOrder,
			ZIndex = self.props.zIndex,
			BackgroundTransparency = 1,

			[Roact.Event.Activated] = function()
				if self.props.locked then
					return
				end
				self:setState({
					open = not self.state.open,
				})
			end,
		}, {
			Border = e(SlicedImage, {
				slice = Assets.Slices.RoundedBorder,
				color = dropdownTheme.BorderColor,
				transparency = self.props.transparency,
				size = UDim2.new(1, 0, 1, 0),
			}, {
				DropArrow = e("ImageLabel", {
					Image = if self.props.locked then Assets.Images.Dropdown.Locked else Assets.Images.Dropdown.Arrow,
					ImageColor3 = dropdownTheme.IconColor,
					ImageTransparency = self.props.transparency,

					Size = UDim2.new(0, 18, 0, 18),
					Position = UDim2.new(1, -6, 0.5, 0),
					AnchorPoint = Vector2.new(1, 0.5),
					Rotation = self.openBinding:map(function(a)
						return a * 180
					end),

					BackgroundTransparency = 1,
				}, {
					StateTip = if self.props.locked
						then e(Tooltip.Trigger, {
							text = self.props.lockedTooltip or "(Cannot be changed right now)",
						})
						else nil,
				}),
				Active = e("TextLabel", {
					Size = UDim2.new(1, -30, 1, 0),
					Position = UDim2.new(0, 6, 0, 0),
					BackgroundTransparency = 1,
					Text = self.props.active,
					FontFace = theme.Font.Main,
					TextSize = theme.TextSize.Body,
					TextColor3 = dropdownTheme.TextColor,
					TextXAlignment = Enum.TextXAlignment.Left,
					TextTransparency = self.props.transparency,
				}),
			}),
			Options = if self.state.open
				then e(SlicedImage, {
					slice = Assets.Slices.RoundedBackground,
					color = dropdownTheme.BackgroundColor,
					position = UDim2.new(1, 0, 1, 3),
					size = self.openBinding:map(function(a)
						return UDim2.new(1, 0, a * math.min(3, #self.props.options), 0)
					end),
					anchorPoint = Vector2.new(1, 0),
				}, {
					Border = e(SlicedImage, {
						slice = Assets.Slices.RoundedBorder,
						color = dropdownTheme.BorderColor,
						transparency = self.props.transparency,
						size = UDim2.new(1, 0, 1, 0),
					}),
					ScrollingFrame = e(ScrollingFrame, {
						size = UDim2.new(1, -4, 1, -4),
						position = UDim2.new(0, 2, 0, 2),
						transparency = self.props.transparency,
						contentSize = self.contentSize,
					}, {
						Layout = e("UIListLayout", {
							VerticalAlignment = Enum.VerticalAlignment.Top,
							FillDirection = Enum.FillDirection.Vertical,
							SortOrder = Enum.SortOrder.LayoutOrder,
							Padding = UDim.new(0, 0),

							[Roact.Change.AbsoluteContentSize] = function(object)
								self.setContentSize(object.AbsoluteContentSize)
							end,
						}),
						Options = Roact.createFragment(optionButtons),
					}),
				})
				else nil,
		})
	end)
end

return Dropdown