diff --git a/CHANGELOG.md b/CHANGELOG.md index 675db7f8..856ed175 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,7 @@ * Fix patch visualizer breaking when instances are removed during sync ([#713]) * Patch visualizer now indicates what changes failed to apply. ([#717]) * Add buttons for navigation on the Connected page ([#722]) +* Improve tooltip behavior ([#723]) [#668]: https://github.com/rojo-rbx/rojo/pull/668 [#674]: https://github.com/rojo-rbx/rojo/pull/674 @@ -26,6 +27,7 @@ [#713]: https://github.com/rojo-rbx/rojo/pull/713 [#717]: https://github.com/rojo-rbx/rojo/pull/717 [#722]: https://github.com/rojo-rbx/rojo/pull/722 +[#723]: https://github.com/rojo-rbx/rojo/pull/723 ## [7.3.0] - April 22, 2023 * Added `$attributes` to project format. ([#574]) diff --git a/plugin/src/App/Components/Tooltip.lua b/plugin/src/App/Components/Tooltip.lua index bc3443d5..aa88d9b6 100644 --- a/plugin/src/App/Components/Tooltip.lua +++ b/plugin/src/App/Components/Tooltip.lua @@ -165,9 +165,11 @@ function Trigger:init() self.id = HttpService:GenerateGUID(false) self.ref = Roact.createRef() self.mousePos = Vector2.zero + self.showingPopup = false self.destroy = function() self.props.context.removeTip(self.id) + self.showingPopup = false end end @@ -180,31 +182,77 @@ function Trigger:willUnmount() end end +function Trigger:didUpdate(prevProps) + if prevProps.text ~= self.props.text then + -- Any existing popup is now invalid + self.props.context.removeTip(self.id) + self.showingPopup = false + + -- Let the new text propagate + self:managePopup() + end +end + +function Trigger:isHovering() + local rbx = self.ref.current + if rbx then + local pos = rbx.AbsolutePosition + local size = rbx.AbsoluteSize + local mousePos = self.mousePos + + return + mousePos.X >= pos.X and mousePos.X <= pos.X + size.X + and mousePos.Y >= pos.Y and mousePos.Y <= pos.Y + size.Y + end + return false +end + +function Trigger:managePopup() + if self:isHovering() then + if self.showingPopup or self.showDelayThread then + -- Don't duplicate popups + return + end + + self.showDelayThread = task.delay(DELAY, function() + self.props.context.addTip(self.id, { + Text = self.props.text, + Position = self.mousePos, + Trigger = self.ref, + }) + self.showDelayThread = nil + self.showingPopup = true + end) + else + if self.showDelayThread then + task.cancel(self.showDelayThread) + self.showDelayThread = nil + end + self.props.context.removeTip(self.id) + self.showingPopup = false + end +end + function Trigger:render() + local function recalculate(rbx) + local widget = rbx:FindFirstAncestorOfClass("DockWidgetPluginGui") + if not widget then return end + self.mousePos = widget:GetRelativeMousePosition() + + self:managePopup() + end + return e("Frame", { Size = UDim2.fromScale(1, 1), BackgroundTransparency = 1, ZIndex = self.props.zIndex or 100, [Roact.Ref] = self.ref, - [Roact.Event.MouseMoved] = function(_rbx, x, y) - self.mousePos = Vector2.new(x, y) - end, - [Roact.Event.MouseEnter] = function() - self.showDelayThread = task.delay(DELAY, function() - self.props.context.addTip(self.id, { - Text = self.props.text, - Position = self.mousePos, - Trigger = self.ref, - }) - end) - end, - [Roact.Event.MouseLeave] = function() - if self.showDelayThread then - task.cancel(self.showDelayThread) - end - self.props.context.removeTip(self.id) - end, + [Roact.Change.AbsolutePosition] = recalculate, + [Roact.Change.AbsoluteSize] = recalculate, + [Roact.Event.MouseMoved] = recalculate, + [Roact.Event.MouseLeave] = recalculate, + [Roact.Event.MouseEnter] = recalculate, }) end