Changeset View
Standalone View
web/chat/reaction-message-utils.js
Show All 12 Lines | |||||
import { | import { | ||||
useDispatchActionPromise, | useDispatchActionPromise, | ||||
useServerCall, | useServerCall, | ||||
} from 'lib/utils/action-utils.js'; | } from 'lib/utils/action-utils.js'; | ||||
import { cloneError } from 'lib/utils/errors.js'; | import { cloneError } from 'lib/utils/errors.js'; | ||||
import Alert from '../modals/alert.react.js'; | import Alert from '../modals/alert.react.js'; | ||||
import { useSelector } from '../redux/redux-utils.js'; | import { useSelector } from '../redux/redux-utils.js'; | ||||
import { | |||||
type TooltipSize, | |||||
type TooltipPositionStyle, | |||||
} from '../utils/tooltip-utils.js'; | |||||
import { getAppContainerPositionInfo } from '../utils/window-utils.js'; | |||||
function useSendReaction( | function useSendReaction( | ||||
messageID: ?string, | messageID: ?string, | ||||
localID: string, | localID: string, | ||||
threadID: string, | threadID: string, | ||||
): (reaction: string, action: 'add_reaction' | 'remove_reaction') => mixed { | ): (reaction: string, action: 'add_reaction' | 'remove_reaction') => mixed { | ||||
const { pushModal } = useModalContext(); | const { pushModal } = useModalContext(); | ||||
▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | [ | ||||
localID, | localID, | ||||
dispatchActionPromise, | dispatchActionPromise, | ||||
callSendReactionMessage, | callSendReactionMessage, | ||||
pushModal, | pushModal, | ||||
], | ], | ||||
); | ); | ||||
} | } | ||||
export { useSendReaction }; | type EmojiKeyboardPosition = { | ||||
+bottom: number, | |||||
+left: number, | |||||
}; | |||||
function getEmojiKeyboardPosition( | |||||
emojiKeyboard: ?HTMLDivElement, | |||||
tooltipPositionStyle: TooltipPositionStyle, | |||||
tooltipSize: TooltipSize, | |||||
): EmojiKeyboardPosition { | |||||
const { alignment, anchorPoint } = tooltipPositionStyle; | |||||
const tooltipAnchorX = anchorPoint.x; | |||||
const tooltipAnchorY = anchorPoint.y; | |||||
const tooltipWidth = tooltipSize.width; | |||||
const tooltipHeight = tooltipSize.height; | |||||
const appContainerPositionInfo = getAppContainerPositionInfo(); | |||||
invariant(appContainerPositionInfo, 'appContainerPositionInfo must be set'); | |||||
tomek: Do we really have to use an invariant? Can we e.g. replace it with returning `null`? | |||||
ginsuAuthorUnsubmitted Done Inline ActionsWe could replace the invariant with returning null; however, I chose to use an invariant here to add transparency and make it easy to figure out what went wrong if appContainerPositionInfo is not set. If we just return null, the positioning of the emoji keyboard would do the following, and at least to me, is not super clear that this is an error since no red flags were raised. Let me know what you think, and if we think returning null is a better solution, I'll make the necessary changes to address it. ginsu: We could replace the invariant with returning `null`; however, I chose to use an invariant here… | |||||
tomekUnsubmitted Not Done Inline ActionsI think it's better to have some issues with the picker than crashing the app. This might be null only when window is not present - I guess it might happen for example during server side rendering. So I think it is safer to e.g. not render the picker when this is null - it's a lot better than crashing the app. tomek: I think it's better to have some issues with the picker than crashing the app. This might be… | |||||
let emojiKeyboardWidth = 352; | |||||
let emojiKeyboardHeight = 435; | |||||
if (emojiKeyboard) { | |||||
const { width, height } = emojiKeyboard.getBoundingClientRect(); | |||||
emojiKeyboardWidth = width; | |||||
emojiKeyboardHeight = height; | |||||
} | |||||
const { | |||||
top: containerTop, | |||||
left: containerLeft, | |||||
right: containerRight, | |||||
bottom: containerBottom, | |||||
} = appContainerPositionInfo; | |||||
const padding = 16; | |||||
const canBeDisplayedOnRight = | |||||
tooltipAnchorX + tooltipWidth + emojiKeyboardWidth <= containerRight; | |||||
const canBeDisplayedOnLeft = | |||||
tooltipAnchorX - emojiKeyboardWidth >= containerLeft; | |||||
const canBeDisplayedOnTop = | |||||
tooltipAnchorY - emojiKeyboardHeight - padding >= containerTop; | |||||
const canBeDisplayedOnBottom = | |||||
tooltipAnchorY + tooltipHeight + emojiKeyboardHeight + padding <= | |||||
containerBottom; | |||||
const emojiKeyboardOverflowTop = | |||||
containerTop - (tooltipAnchorY + tooltipHeight - emojiKeyboardHeight); | |||||
const emojiKeyboardOverflowTopCorrection = | |||||
emojiKeyboardOverflowTop > 0 ? -emojiKeyboardOverflowTop - padding : 0; | |||||
const emojiKeyboardOverflowRight = | |||||
tooltipAnchorX + emojiKeyboardWidth - containerRight; | |||||
const emojiKeyboardOverflowRightCorrection = | |||||
emojiKeyboardOverflowRight > 0 ? -emojiKeyboardOverflowRight - padding : 0; | |||||
if (alignment === 'left' && canBeDisplayedOnRight) { | |||||
return { | |||||
left: tooltipWidth, | |||||
bottom: emojiKeyboardOverflowTopCorrection, | |||||
}; | |||||
} | |||||
if (alignment === 'right' && canBeDisplayedOnLeft) { | |||||
return { | |||||
left: -emojiKeyboardWidth, | |||||
bottom: emojiKeyboardOverflowTopCorrection, | |||||
}; | |||||
} | |||||
if (canBeDisplayedOnTop) { | |||||
return { | |||||
bottom: tooltipHeight + padding, | |||||
left: emojiKeyboardOverflowRightCorrection, | |||||
}; | |||||
} | |||||
if (canBeDisplayedOnBottom) { | |||||
return { | |||||
bottom: -emojiKeyboardHeight - padding, | |||||
left: emojiKeyboardOverflowRightCorrection, | |||||
}; | |||||
} | |||||
return { | |||||
left: alignment === 'left' ? -emojiKeyboardWidth : tooltipWidth, | |||||
bottom: emojiKeyboardOverflowTopCorrection, | |||||
}; | |||||
} | |||||
export { useSendReaction, getEmojiKeyboardPosition }; |
Do we really have to use an invariant? Can we e.g. replace it with returning null?