Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
147 changes: 116 additions & 31 deletions src/libs/gui.luau
Original file line number Diff line number Diff line change
Expand Up @@ -395,7 +395,7 @@ function createInputArea(parent: Instance)
ZIndex = 4,
FontFace = Font.fromEnum(Enum.Font.Code),
TextSize = 15,
PlaceholderText = "Search...",
PlaceholderText = "",
Text = "",
PlaceholderColor3 = guiModule.colorPalette[guiModule.selectedPalette].Subtext0,
TextColor3 = guiModule.colorPalette[guiModule.selectedPalette].Subtext0,
Expand All @@ -404,6 +404,23 @@ function createInputArea(parent: Instance)
ClearTextOnFocus = false,
})

-- Create the placeholder label (sits behind the TextBox)
createInstance("TextLabel", {
Name = "TextLabel",
Parent = input,
BackgroundTransparency = 1,

Position = UDim2.new(0, 10, 0, 0),
Size = UDim2.new(0.942, 16, 1, 0),

ZIndex = 3,
FontFace = Font.fromEnum(Enum.Font.Code),
TextSize = 15,
Text = "Search...",
TextColor3 = guiModule.colorPalette[guiModule.selectedPalette].Subtext0,
TextXAlignment = Enum.TextXAlignment.Left,
})

-- Register the input frame in the table
guiModule.guiElements.Gui.Input = input

Expand Down Expand Up @@ -605,7 +622,7 @@ function guiModule:rebuildUI()
removeAllCommands()

-- add all commands back w/ selection.
for i, cmd in filtered do
for i, cmd in ipairs(filtered) do
local isSelected = (i == guiModule.selectedCommand)
createCommandPreview(guiModule.guiElements.Gui.CommandsScrolling, cmd.title, cmd.callback, isSelected)
end
Expand Down Expand Up @@ -658,18 +675,74 @@ function guiModule:activateSelected()
-- Fire our entry!
local entry = guiModule.guiElements.Gui.Commands[idx]
if entry then
-- The Enter that got us here is spent, so it can't leak into whatever
-- the callback opens (an input prompt, a pushed page, ...)
guiModule._inputSubmitGuardUntil = os.clock() + 0.14

entry.callback()
end
end

--// Hides the placeholder label whenever the user has typed something
function updatePlaceholder()
local input = guiModule.guiElements.Gui.Input
if not input then
return
end

local textBox = input:FindFirstChild("TextBox")
local placeholder = input:FindFirstChild("TextLabel")

if not textBox or not placeholder then
return
end

-- The box is single line, so a newline is always Roblox leaking the Enter
-- that opened it: strip it, which re-runs this with the clean text.
local text = (textBox.Text:gsub("[\r\n]", ""))
if text ~= textBox.Text then
textBox.Text = text
return
end

placeholder.Visible = text == ""
end

--// Focuses the input box, but only once the Enter that opened it is gone
function focusInputBox(textBox: TextBox, token: number)
task.delay(math.max(0, guiModule._inputSubmitGuardUntil - os.clock()), function()
-- Is this still the active request?
if guiModule._inputModeToken ~= token or not textBox.Parent then
return
end

textBox.Text = ""
textBox:CaptureFocus()

-- Hard clear in case Roblox injected a stray character
task.defer(function()
if guiModule._inputModeToken ~= token or not textBox.Parent then
return
end

textBox.Text = ""
updatePlaceholder()
end)
end)
end

--// Setup the search feature on the palette
function setupSearch()
-- Input setup!
local inputBox: TextBox = guiModule.guiElements.Gui.Input:WaitForChild("TextBox")
inputBox:GetPropertyChangedSignal("Text"):Connect(function()
updatePlaceholder()
guiModule:rebuildUI()
end)

-- Sync once for the initial (empty) state
updatePlaceholder()

-- Capture focus
inputBox:CaptureFocus()

Expand All @@ -693,7 +766,7 @@ function guiModule:addCommands(commands: { { title: string, callback: () -> () }
guiModule.registeredCommands = {}

-- Insert commands into registered
for _, cmd in commands do
for _, cmd in ipairs(commands) do

-- Is test & developer mode enabled?
if cmd.isTest and not _G.developerMode then
Expand All @@ -713,20 +786,26 @@ function guiModule:pushCommands(commands)
guiModule._inputSubmitGuardUntil = os.clock() + 0.14

local textBox = guiModule.guiElements.Gui.Input and guiModule.guiElements.Gui.Input:FindFirstChild("TextBox")
local placeholder = guiModule.guiElements.Gui.Input and guiModule.guiElements.Gui.Input:FindFirstChild("TextLabel")

if textBox then
textBox:ReleaseFocus()
textBox.Text = ""
end

-- Remember this level's placeholder so popping back restores it
if placeholder then
guiModule.registeredCommands.placeholder = placeholder.Text
end

-- Insert registered commands into the stack
table.insert(guiModule.navigationStack, guiModule.registeredCommands)

-- reset registered commands
guiModule.registeredCommands = {}

-- loop through commands
for _, cmd in commands do
for _, cmd in ipairs(commands) do
table.insert(guiModule.registeredCommands, cmd)
end

Expand Down Expand Up @@ -766,11 +845,16 @@ function guiModule:popCommands()
guiModule._inputModeToken += 1

local textBox = guiModule.guiElements.Gui.Input:FindFirstChild("TextBox")
local placeholder = guiModule.guiElements.Gui.Input:FindFirstChild("TextLabel")
if placeholder then
placeholder.Text = guiModule._inputModePrevPlaceholder or "Search..."
end
if textBox then
textBox.PlaceholderText = guiModule._inputModePrevPlaceholder or "Search..."
textBox.Text = ""
end

updatePlaceholder()

guiModule.inputMode = false
guiModule:rebuildUI()
return
Expand All @@ -782,9 +866,9 @@ function guiModule:popCommands()
-- does previous exist?
if prev then
-- restore placeholder
local textBox = guiModule.guiElements.Gui.Input:FindFirstChild("TextBox")
if textBox and prev.placeholder then
textBox.PlaceholderText = prev.placeholder
local placeholder = guiModule.guiElements.Gui.Input:FindFirstChild("TextLabel")
if placeholder and prev.placeholder then
placeholder.Text = prev.placeholder
end

guiModule.registeredCommands = prev
Expand All @@ -795,6 +879,8 @@ function guiModule:popCommands()
if guiModule.guiElements.Gui.Input:FindFirstChild("TextBox") then
guiModule.guiElements.Gui.Input:FindFirstChild("TextBox").Text = ""
end

updatePlaceholder()
else
guiModule:closePalette()
end
Expand All @@ -811,6 +897,7 @@ just be warned!
--// Cancel input mode system
function guiModule:cancelInputMode(returnedValue : string, callback:(string) -> (any), token : number)
local textBox : TextBox = guiModule.guiElements.Gui.Input:WaitForChild("TextBox")
local placeholder: TextLabel = guiModule.guiElements.Gui.Input:WaitForChild("TextLabel")
local thisToken = token or guiModule._inputModeToken

-- Guard against return leaking
Expand All @@ -823,8 +910,9 @@ function guiModule:cancelInputMode(returnedValue : string, callback:(string) ->
end

guiModule.inputMode = false
textBox.PlaceholderText = guiModule._inputModePrevPlaceholder or "Search..."
placeholder.Text = guiModule._inputModePrevPlaceholder or "Search..."
textBox.Text = ""
updatePlaceholder()
guiModule:rebuildUI()
end)

Expand All @@ -835,13 +923,14 @@ end

function guiModule:requestUserInput(textPrompt : string, callback: (string) -> (any))
local textBox : TextBox = guiModule.guiElements.Gui.Input:WaitForChild("TextBox")
local placeholder: TextLabel = guiModule.guiElements.Gui.Input:WaitForChild("TextLabel")

-- Generation/token for req
guiModule._inputModeToken += 1
local myToken = guiModule._inputModeToken

-- Get old before replacement
local oldPlaceholderText = textBox.PlaceholderText
local oldPlaceholderText = placeholder.Text

-- Value the user inputs (input string)
local returnedValue = ""
Expand All @@ -855,31 +944,16 @@ function guiModule:requestUserInput(textPrompt : string, callback: (string) -> (
end

-- TextBox!
textBox.PlaceholderText = textPrompt
placeholder.Text = textPrompt
textBox.Text = ""
updatePlaceholder()

-- More setup
removeAllCommands()
resizePalette(0)

-- Defer focus so the previous Enter press doesn't bleed into this box
task.defer(function()
-- Is this still the active request?
if guiModule._inputModeToken ~= myToken then
return
end

textBox:CaptureFocus()

-- Hard reset again after focus in case Roblox injects junk
task.defer(function()
if guiModule._inputModeToken ~= myToken then
return
end

textBox.Text = ""
end)
end)
-- Delay focus so the Enter press that opened this doesn't bleed into the box
focusInputBox(textBox, myToken)

local conn
conn = textBox.FocusLost:Connect(function(enterPressed)
Expand All @@ -888,6 +962,13 @@ function guiModule:requestUserInput(textPrompt : string, callback: (string) -> (
return
end

-- The Enter that opened this request drops focus on the box we just
-- took over; that isn't a submission, so keep the prompt up & refocus.
if os.clock() < guiModule._inputSubmitGuardUntil then
focusInputBox(textBox, myToken)
return
end

if conn then
conn:Disconnect()
conn = nil
Expand Down Expand Up @@ -916,9 +997,10 @@ function guiModule:requestUserInput(textPrompt : string, callback: (string) -> (
end

guiModule.inputMode = false
textBox.PlaceholderText = guiModule._inputModePrevPlaceholder or "Search..."
placeholder.Text = guiModule._inputModePrevPlaceholder or "Search..."
textBox.Text = ""
guiModule._inputModePrevPlaceholder = nil
updatePlaceholder()
guiModule:rebuildUI()
end)
end)
Expand All @@ -942,8 +1024,11 @@ function guiModule:rebuildTheme()
if gui.Input then
gui.Input.BackgroundColor3 = guiModule.colorPalette[guiModule.selectedPalette].Surface0
local textBox : TextBox = gui.Input:FindFirstChild("TextBox")
local placeholder: TextLabel = gui.Input:FindFirstChild("TextLabel")
if placeholder then
placeholder.TextColor3 = guiModule.colorPalette[guiModule.selectedPalette].Subtext0
end
if textBox then
textBox.PlaceholderColor3 = guiModule.colorPalette[guiModule.selectedPalette].Subtext0
textBox.TextColor3 = guiModule.colorPalette[guiModule.selectedPalette].Subtext0
end
end
Expand Down
2 changes: 1 addition & 1 deletion src/libs/search.luau
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ function searchModule:search(query : string, commandList : {{title : string, cal
local sorted = {}

-- fuzzy search through all the commands based on query
for _, cmd in commandList do
for _, cmd in ipairs(commandList) do
local matched, score = utilityModule:fuzzySearch(query, cmd.title)
if matched then
table.insert(results, { cmd = cmd, score = score })
Expand Down