Refactor subtree highlight handling in PatchVisualizer and DomLabel components

- Replaced subtreeHighlightBinding with subtreeHighlightInfo for improved clarity and functionality.
- Updated transparency logic in SelectionOption to utilize the new subtree highlight structure.
- Adjusted state management in PatchVisualizer to accommodate the new highlight callback mechanism.
This commit is contained in:
Joe 2026-02-07 18:48:41 -06:00
parent 7a40839f91
commit 76d4e6aff0
2 changed files with 49 additions and 70 deletions

View file

@ -80,66 +80,35 @@ function SelectionOption:render()
-- Use wider button for "Studio" text (6 chars vs 4 for others) -- Use wider button for "Studio" text (6 chars vs 4 for others)
local buttonWidth = if props.text == "Studio" then 44 else 36 local buttonWidth = if props.text == "Studio" then 44 else 36
-- Transparency logic with hover effect -- Check if this button is subtree-highlighted (parent's matching button is hovered)
-- Combines real hover state with subtree highlight binding so the matching local subtreeInfo = props.subtreeHighlightInfo
-- button on child nodes looks hovered when a parent's button is hovered.
local bgTransparency, txtTransparency
local subtreeBinding = props.subtreeHighlightBinding
local ancestorIds = props.ancestorIds local ancestorIds = props.ancestorIds
local subtreeHov = subtreeInfo ~= nil
and ancestorIds ~= nil
and ancestorIds[subtreeInfo.nodeId] == true
and subtreeInfo.optionType == props.optionType
local effectiveHovered = isHovered or subtreeHov
if subtreeBinding and ancestorIds then -- Transparency logic with hover effect
local optionType = props.optionType local bgTransparency, txtTransparency
local joined = Roact.joinBindings({ if isParentOnly then
transparency = props.transparency, -- Parent-only: partially transparent, less so when hovering the button
highlight = subtreeBinding, bgTransparency = props.transparency:map(function(t)
}) return if effectiveHovered then 0.2 + (0.8 * t) else 0.5 + (0.5 * t)
bgTransparency = joined:map(function(values)
local t = values.transparency
local info = values.highlight
local subtreeHov = info ~= nil and ancestorIds[info.nodeId] == true and info.optionType == optionType
local hov = isHovered or subtreeHov
if isParentOnly then
return if hov then 0.2 + (0.8 * t) else 0.5 + (0.5 * t)
elseif isSelected then
return if hov then 0 + (1 * t) else 0.1 + (0.9 * t)
else
return if hov then 0.5 + (0.5 * t) else 0.7 + (0.3 * t)
end
end) end)
txtTransparency = props.transparency:map(function(t)
txtTransparency = joined:map(function(values) return if effectiveHovered then 0 + t else 0.3 + (0.7 * t)
local t = values.transparency
local info = values.highlight
local subtreeHov = info ~= nil and ancestorIds[info.nodeId] == true and info.optionType == optionType
local hov = isHovered or subtreeHov
if isParentOnly then
return if hov then 0 + t else 0.3 + (0.7 * t)
else
return t
end
end) end)
else else
-- Fallback: no subtree highlight available -- Normal buttons: show hover effect by reducing transparency
if isParentOnly then bgTransparency = props.transparency:map(function(t)
bgTransparency = props.transparency:map(function(t) if isSelected then
return if isHovered then 0.2 + (0.8 * t) else 0.5 + (0.5 * t) return if effectiveHovered then 0 + (1 * t) else 0.1 + (0.9 * t)
end) else
txtTransparency = props.transparency:map(function(t) return if effectiveHovered then 0.5 + (0.5 * t) else 0.7 + (0.3 * t)
return if isHovered then 0 + t else 0.3 + (0.7 * t) end
end) end)
else txtTransparency = props.transparency
bgTransparency = props.transparency:map(function(t)
if isSelected then
return if isHovered then 0 + (1 * t) else 0.1 + (0.9 * t)
else
return if isHovered then 0.5 + (0.5 * t) else 0.7 + (0.3 * t)
end
end)
txtTransparency = props.transparency
end
end end
return e("TextButton", { return e("TextButton", {
@ -212,7 +181,7 @@ local function SelectionRadio(props)
SortOrder = Enum.SortOrder.LayoutOrder, SortOrder = Enum.SortOrder.LayoutOrder,
Padding = UDim.new(0, 4), Padding = UDim.new(0, 4),
}), }),
Studio = e(SelectionOption, { Studio = e(SelectionOption, {
text = "Studio", text = "Studio",
optionType = "pull", optionType = "pull",
isSelected = props.selection == "pull", isSelected = props.selection == "pull",
@ -220,7 +189,7 @@ local function SelectionRadio(props)
layoutOrder = 1, layoutOrder = 1,
hasChildren = hasChildren, hasChildren = hasChildren,
isParentOnly = isParentOnly, isParentOnly = isParentOnly,
subtreeHighlightBinding = props.subtreeHighlightBinding, subtreeHighlightInfo = props.subtreeHighlightInfo,
ancestorIds = props.ancestorIds, ancestorIds = props.ancestorIds,
onSubtreeHoverStart = props.onSubtreeHoverStart, onSubtreeHoverStart = props.onSubtreeHoverStart,
onSubtreeHoverEnd = props.onSubtreeHoverEnd, onSubtreeHoverEnd = props.onSubtreeHoverEnd,
@ -243,7 +212,7 @@ local function SelectionRadio(props)
layoutOrder = 2, layoutOrder = 2,
hasChildren = hasChildren, hasChildren = hasChildren,
isParentOnly = isParentOnly, isParentOnly = isParentOnly,
subtreeHighlightBinding = props.subtreeHighlightBinding, subtreeHighlightInfo = props.subtreeHighlightInfo,
ancestorIds = props.ancestorIds, ancestorIds = props.ancestorIds,
onSubtreeHoverStart = props.onSubtreeHoverStart, onSubtreeHoverStart = props.onSubtreeHoverStart,
onSubtreeHoverEnd = props.onSubtreeHoverEnd, onSubtreeHoverEnd = props.onSubtreeHoverEnd,
@ -266,7 +235,7 @@ local function SelectionRadio(props)
layoutOrder = 3, layoutOrder = 3,
hasChildren = hasChildren, hasChildren = hasChildren,
isParentOnly = isParentOnly, isParentOnly = isParentOnly,
subtreeHighlightBinding = props.subtreeHighlightBinding, subtreeHighlightInfo = props.subtreeHighlightInfo,
ancestorIds = props.ancestorIds, ancestorIds = props.ancestorIds,
onSubtreeHoverStart = props.onSubtreeHoverStart, onSubtreeHoverStart = props.onSubtreeHoverStart,
onSubtreeHoverEnd = props.onSubtreeHoverEnd, onSubtreeHoverEnd = props.onSubtreeHoverEnd,
@ -596,17 +565,17 @@ function DomLabel:render()
isParentOnly = props.patchType == nil, isParentOnly = props.patchType == nil,
onSelectionChange = props.onSelectionChange, onSelectionChange = props.onSelectionChange,
onSubtreeSelectionChange = props.onSubtreeSelectionChange, onSubtreeSelectionChange = props.onSubtreeSelectionChange,
-- Subtree hover highlight: pass binding and ancestors to child buttons -- Subtree hover highlight: pass info and ancestors to child buttons
subtreeHighlightBinding = props.subtreeHighlightNodeId, subtreeHighlightInfo = props.subtreeHighlightInfo,
ancestorIds = props.ancestorIds, ancestorIds = props.ancestorIds,
onSubtreeHoverStart = function(optionType) onSubtreeHoverStart = function(optionType)
if props.setSubtreeHighlightNodeId then if props.onSubtreeHighlightChange then
props.setSubtreeHighlightNodeId({ nodeId = props.nodeId, optionType = optionType }) props.onSubtreeHighlightChange({ nodeId = props.nodeId, optionType = optionType })
end end
end, end,
onSubtreeHoverEnd = function() onSubtreeHoverEnd = function()
if props.setSubtreeHighlightNodeId then if props.onSubtreeHighlightChange then
props.setSubtreeHighlightNodeId(nil) props.onSubtreeHighlightChange(nil)
end end
end, end,
}), }),

View file

@ -61,15 +61,25 @@ function PatchVisualizer:init()
-- causing expanded rows to visually glitch when unrelated props change. -- causing expanded rows to visually glitch when unrelated props change.
self.nodeHeightBindings = {} self.nodeHeightBindings = {}
-- Binding for subtree hover preview: stores the nodeId whose children should highlight self:setState({
self.subtreeHighlightNodeId, self.setSubtreeHighlightNodeId = Roact.createBinding(nil) subtreeHighlightInfo = nil,
})
-- Callback for subtree hover preview: stores { nodeId, optionType } or nil
self.onSubtreeHighlightChange = function(info)
self:setState({ subtreeHighlightInfo = info })
end
end end
function PatchVisualizer:willUnmount() function PatchVisualizer:willUnmount()
self.updateEvent:Destroy() self.updateEvent:Destroy()
end end
function PatchVisualizer:shouldUpdate(nextProps) function PatchVisualizer:shouldUpdate(nextProps, nextState)
if self.state.subtreeHighlightInfo ~= nextState.subtreeHighlightInfo then
return true
end
if self.props.patchTree ~= nextProps.patchTree then if self.props.patchTree ~= nextProps.patchTree then
return true return true
end end
@ -220,8 +230,8 @@ function PatchVisualizer:render()
onSubtreeSelectionChange = self.props.onSubtreeSelectionChange, onSubtreeSelectionChange = self.props.onSubtreeSelectionChange,
-- Subtree hover highlight props -- Subtree hover highlight props
ancestorIds = ancestorIds, ancestorIds = ancestorIds,
subtreeHighlightNodeId = self.subtreeHighlightNodeId, subtreeHighlightInfo = self.state.subtreeHighlightInfo,
setSubtreeHighlightNodeId = self.setSubtreeHighlightNodeId, onSubtreeHighlightChange = self.onSubtreeHighlightChange,
}) })
if isFinalChild then if isFinalChild then