--[[
	Renderless component used to detect when a user clicks/taps anywhere
	outside of another component.

	Users commonly expect that a modal will be hidden when clicking anywhere
	outside of it, so this component allows you to set up that functionality.

	Usage:

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

		function FocusLostTest:init()
			self.frame = Roact.createRef()
		end

		function FocusLostTest:render()
			return Roact.createFragment({
				Frame = Roact.createElement("Frame", {
					Size = UDim2.fromOffset(100, 100),
					[Roact.Ref] = self.frame,
				}),

				FocusLost = Roact.createElement(FocusLost, {
					ref = self.frame,
					callback = self.props.callback,
				}),
			})
		end
]]

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

local defaultProps = {
	UserInputService = UserInputService,
}

export type Props = typeof(defaultProps) & {
	ref: any, -- Roact ref
	callback: () -> (),
}

FocusLost.defaultProps = defaultProps

function FocusLost:init()
	self.wasRefClicked = function(input: InputObject)
		local props: Props = self.props
		local ref = props.ref:getValue()

		if ref then
			local playerGui: BasePlayerGui = ref:FindFirstAncestorWhichIsA("BasePlayerGui")

			if playerGui then
				for _, gui in ipairs(playerGui:GetGuiObjectsAtPosition(input.Position.X, input.Position.Y)) do
					if gui == ref or gui:IsDescendantOf(ref) then
						return true
					end
				end
			end
		end

		return false
	end

	self.handleFocusLost = function(input: InputObject)
		local props: Props = self.props

		if
			input.UserInputType == Enum.UserInputType.MouseButton1
			or input.UserInputType == Enum.UserInputType.Touch
		then
			if not self.wasRefClicked(input) then
				props.callback()
			end
		end
	end
end

function FocusLost:render()
	local props: Props = self.props

	return Roact.createFragment({
		InputEnded = Roact.createElement(ExternalEventConnection, {
			callback = self.handleFocusLost,
			event = props.UserInputService.InputEnded,
		}),

		TouchTap = Roact.createElement(ExternalEventConnection, {
			callback = self.handleFocusLost,
			event = props.UserInputService.TouchTap,
		}),
	})
end

return FocusLost
