local D=game:GetService("\084\101\120\116\083\101\114\118\105\099\101")local o=script:FindFirstAncestor("\084\101\120\116\069\100\105\116\111\114")local m=require(o.Packages.Roact)local c=require(script.Parent.StudioThemeContext)local f=m.Component:extend("\084\101\120\116\068\114\111\112\100\111\119\110")local R=require(script.Parent.TextBox)local K=require(script.DropdownItem)local C=20 local B=5 f.defaultProps={AutoSize=true;Size=UDim2.new(0,50,0,20);Font=Enum.Font.SourceSans;TextSize=14;options={},OnOptionSelect=function() end}function f.init(D)D.notTyped=false D.lastTyped=""D.dropdownCanvasSize,D.setDropdownCanvasSize=m.createBinding(0)D:setState({open=false})end function f.render(o)return m.createElement(c.Consumer,{render=function(c)local f={}local t=o.props.Size if o.props.AutoSize then local m=0 for c,f in pairs(o.props.options)do local R=D:GetTextSize(f,o.props.TextSize,o.props.Font,Vector2.new(math.huge,math.huge))if m<R.X then m=R.X end end t=UDim2.new(UDim.new(0,((m+2)+C)+B),t.Y)end f.ListLayout=m.createElement("\085\073\076\105\115\116\076\097\121\111\117\116",{SortOrder=Enum.SortOrder.Name,[m.Change.AbsoluteContentSize]=function(D)o.setDropdownCanvasSize(D.AbsoluteContentSize.Y)end})f.Padding=m.createElement("\085\073\080\097\100\100\105\110\103",{PaddingLeft=UDim.new(0,B)})for D,c in pairs(o.props.options)do f[c]=m.createElement(K,{Text=c,TextSize=o.props.TextSize;selected=o.props.currentOption==c;OnSelected=function()o:setState({open=false})o.props.OnOptionSelect(c)end})end return m.createElement("\070\114\097\109\101",{LayoutOrder=o.props.LayoutOrder,Size=t;BackgroundColor3=c:GetColor(Enum.StudioStyleGuideColor.Dropdown),BorderColor3=c:GetColor(Enum.StudioStyleGuideColor.InputFieldBorder)},{Holder=m.createElement("\070\114\097\109\101",{BackgroundTransparency=1,Size=UDim2.fromScale(1,1)},{Padding=m.createElement("\085\073\080\097\100\100\105\110\103",{PaddingLeft=UDim.new(0,B)}),ListLayout=m.createElement("\085\073\076\105\115\116\076\097\121\111\117\116",{SortOrder=Enum.SortOrder.LayoutOrder;FillDirection=Enum.FillDirection.Horizontal});TextBox=m.createElement(R,{Text=o.props.currentOption;TextSize=o.props.TextSize;BackgroundTransparency=1,Size=UDim2.new(1,-C,1,0);ClearTextOnFocus=false;[m.Change.Text]=function(D)if o.notTyped then o.notTyped=false return end local m=D.Text local c=m:len()if c<o.lastTyped:len()and m==o.lastTyped:sub(1,c)or o.lastTyped==m then o.lastTyped=m return end o.lastTyped=m if c>0 then for f,R in pairs(o.props.options)do if(R:lower()):sub(1,c)==m:lower()then o.notTyped=true D.Text=R D.CursorPosition=c+1 D.SelectionStart=R:len()+1 break end end end end,[m.Event.Focused]=function(D)D.CursorPosition=0 D.SelectionStart=D.Text:len()+1 end;[m.Event.FocusLost]=function(D)local m=nil for o,c in pairs(o.props.options)do if D.Text:lower()==c:lower()then m=c break end end if m then o.props.OnOptionSelect(m)else D.Text=o.props.currentOption end end}),OpenClose=m.createElement("\073\109\097\103\101\066\117\116\116\111\110",{Size=UDim2.fromOffset(C,C),BackgroundColor3=c:GetColor(Enum.StudioStyleGuideColor.Button);BorderColor3=c:GetColor(Enum.StudioStyleGuideColor.ButtonBorder),Image="\114\098\120\097\115\115\101\116\058\047\047\116\101\120\116\117\114\101\115\047\083\116\117\100\105\111\084\111\111\108\098\111\120\047\065\114\114\111\119\068\111\119\110\073\099\111\110\087\104\105\116\101\046\112\110\103";ImageColor3=c:GetColor(Enum.StudioStyleGuideColor.MainText),Rotation=o.state.open and 180 or 0,[m.Event.Activated]=function()o:setState({open=not o.state.open})end})}),OptionsFrame=m.createElement("\083\099\114\111\108\108\105\110\103\070\114\097\109\101",{Visible=o.state.open;Size=UDim2.new(1,0,0,100);Position=UDim2.new(0,0,1,2),BackgroundColor3=c:GetColor(Enum.StudioStyleGuideColor.Dropdown);BorderSizePixel=0;CanvasSize=o.dropdownCanvasSize:map(function(D)return UDim2.fromOffset(0,D)end);ScrollBarThickness=8,TopImage="\114\098\120\097\115\115\101\116\058\047\047\116\101\120\116\117\114\101\115\047\083\116\117\100\105\111\084\111\111\108\098\111\120\047\083\099\114\111\108\108\066\097\114\084\111\112\046\112\110\103";MidImage="\114\098\120\097\115\115\101\116\058\047\047\116\101\120\116\117\114\101\115\047\083\116\117\100\105\111\084\111\111\108\098\111\120\047\083\099\114\111\108\108\066\097\114\077\105\100\100\108\101\046\112\110\103";BottomImage="\114\098\120\097\115\115\101\116\058\047\047\116\101\120\116\117\114\101\115\047\083\116\117\100\105\111\084\111\111\108\098\111\120\047\083\099\114\111\108\108\066\097\114\066\111\116\116\111\109\046\112\110\103";VerticalScrollBarInset=Enum.ScrollBarInset.ScrollBar},f)})end})end return f
-- Dropdown with an editable TextBox to type option
local TextService = game:GetService("TextService")
local TextEditor = script:FindFirstAncestor("TextEditor")
local Roact = require(TextEditor.Packages.Roact)

local StudioThemeContext = require(script.Parent.StudioThemeContext)
local TextDropdown = Roact.Component:extend("TextDropdown")
local TextBox = require(script.Parent.TextBox)
local DropdownItem = require(script.DropdownItem)

local BUTTON_SIZE = 20
local TEXT_FIELD_PADDING = 5

TextDropdown.defaultProps = {
  AutoSize = true,
  Size = UDim2.new(0, 50, 0, 20),
  Font = Enum.Font.SourceSans,
  TextSize = 14,

  options = {},
  OnOptionSelect = function() end,
}

function TextDropdown:init()
  self.notTyped = false
  self.lastTyped = ""

  self.dropdownCanvasSize, self.setDropdownCanvasSize = Roact.createBinding(0) 

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

function TextDropdown:render()
  return Roact.createElement(StudioThemeContext.Consumer, {
    render = function(theme)
      local DropdownChildren = {}

      -- Determine X Size
      local size = self.props.Size
      if self.props.AutoSize then
        local textXSize = 0
        for _, option in pairs(self.props.options) do
          local textBounds = TextService:GetTextSize(option, self.props.TextSize, self.props.Font, Vector2.new(math.huge, math.huge))
          if textXSize < textBounds.X then
            textXSize = textBounds.X
          end
        end
        size = UDim2.new(UDim.new(0, textXSize + 2 + BUTTON_SIZE + TEXT_FIELD_PADDING), size.Y)
      end

      -- Get Children
      DropdownChildren.ListLayout = Roact.createElement("UIListLayout", {
        SortOrder = Enum.SortOrder.Name,

        [Roact.Change.AbsoluteContentSize] = function(rbx)
          self.setDropdownCanvasSize(rbx.AbsoluteContentSize.Y)
        end,
      })

      DropdownChildren.Padding = Roact.createElement("UIPadding", {
        PaddingLeft = UDim.new(0, TEXT_FIELD_PADDING)
      })

      for _, option in pairs(self.props.options) do
        DropdownChildren[option] = Roact.createElement(DropdownItem, {
          Text = option,
          TextSize = self.props.TextSize,
          selected = self.props.currentOption == option,
          OnSelected = function()
            self:setState({ open = false })
            self.props.OnOptionSelect(option)
          end,
        })
      end

      return Roact.createElement("Frame", {
        LayoutOrder = self.props.LayoutOrder,
        Size = size,
        BackgroundColor3 = theme:GetColor(Enum.StudioStyleGuideColor.Dropdown),
        BorderColor3 = theme:GetColor(Enum.StudioStyleGuideColor.InputFieldBorder),
      }, {
        Holder = Roact.createElement("Frame", {
          BackgroundTransparency = 1,
          Size = UDim2.fromScale(1, 1),
        }, {
          Padding = Roact.createElement("UIPadding", {
            PaddingLeft = UDim.new(0, TEXT_FIELD_PADDING)
          }),
  
          ListLayout = Roact.createElement("UIListLayout", {
            SortOrder = Enum.SortOrder.LayoutOrder,
            FillDirection = Enum.FillDirection.Horizontal,
          }),
  
          TextBox = Roact.createElement(TextBox, {
            Text = self.props.currentOption,
            TextSize = self.props.TextSize,
            BackgroundTransparency = 1,
            Size = UDim2.new(1, -BUTTON_SIZE, 1, 0), -- Addition includes the UIPadding
            ClearTextOnFocus = false,
  
            [Roact.Change.Text] = function(rbx)
              if self.notTyped then 
                self.notTyped = false
                return
              end 
  
              local text = rbx.Text
              local length = text:len()
  
              -- See if the user is deleting
              if (length < self.lastTyped:len() and text == self.lastTyped:sub(1, length)) or self.lastTyped == text then
                self.lastTyped = text
                return
              end
              self.lastTyped = text
  
              -- Find first option which begins with text, if any
              if length > 0 then
                for _, option in pairs(self.props.options) do
                  if option:lower():sub(1, length) == text:lower() then
                    self.notTyped = true -- used as the Roact.Change.Text will fire again
                    rbx.Text = option
                    rbx.CursorPosition = length + 1
                    rbx.SelectionStart = option:len() + 1
                    break
                  end
                end
              end
            end,
  
            [Roact.Event.Focused] = function(rbx)
              rbx.CursorPosition = 0
              rbx.SelectionStart = rbx.Text:len() + 1
            end,
  
            [Roact.Event.FocusLost] = function(rbx)
              local actualOption = nil
              for _, option in pairs(self.props.options) do
                if rbx.Text:lower() == option:lower() then
                  actualOption = option
                  break
                end
              end
              if actualOption then
                self.props.OnOptionSelect(actualOption)
              else
                rbx.Text = self.props.currentOption
              end
            end,
          }),
  
          OpenClose = Roact.createElement("ImageButton", {
            Size = UDim2.fromOffset(BUTTON_SIZE, BUTTON_SIZE),
            BackgroundColor3 = theme:GetColor(Enum.StudioStyleGuideColor.Button),
            BorderColor3 = theme:GetColor(Enum.StudioStyleGuideColor.ButtonBorder),
            Image = "rbxasset://textures/StudioToolbox/ArrowDownIconWhite.png",
            ImageColor3 = theme:GetColor(Enum.StudioStyleGuideColor.MainText),
            Rotation = self.state.open and 180 or 0,
            [Roact.Event.Activated] = function()
              self:setState({ open = not self.state.open })
            end,
          }),
        }),

        OptionsFrame = Roact.createElement("ScrollingFrame", {
          Visible = self.state.open,
          Size = UDim2.new(1, 0, 0, 100),
          Position = UDim2.new(0, 0, 1, 2),
          BackgroundColor3 = theme:GetColor(Enum.StudioStyleGuideColor.Dropdown),
          BorderSizePixel = 0,
          CanvasSize = self.dropdownCanvasSize:map(function(value)
            return UDim2.fromOffset(0, value)
          end),

          ScrollBarThickness = 8,
          TopImage = "rbxasset://textures/StudioToolbox/ScrollBarTop.png",
          MidImage = "rbxasset://textures/StudioToolbox/ScrollBarMiddle.png",
          BottomImage = "rbxasset://textures/StudioToolbox/ScrollBarBottom.png",
          -- ScrollBarImageColor3 = theme:GetColor(Enum.StudioStyleGuideColor.ScrollBar), TODO: this colour is really bad...
          VerticalScrollBarInset = Enum.ScrollBarInset.ScrollBar,
        }, DropdownChildren)
      })
    end
  })
end

return TextDropdown
