Closed raineorshine closed 2 weeks ago
When trying to render a downward arrow for a context such as above States
, there is an issue with DropHover
placement. All the thoughts are not rendered until we scroll down so for a thought that will be placed at the very bottom will not have any DropHover
rendered until we scroll down. Is there any way to detect the position of the DropHover
on large context when its rendering at the bottom?
This isn't so much about the position of the DropHover
component. As you pointed out, it is not actually rendered at all in this case. Instead, we need to find where in the list it would be rendered if it were within view. It's a function of the Redux state and hover position.
The logic for positioning within a sorted list is somewhat buried in one of the hooks, but it is ultimately just a function of the Redux state (i.e. it is a selector), so it should be easily extractable. However, determining whether that position is in view or not is trickier, as that depends on which VirtualThoughts are shimmed (i.e. virtualized). I'm not sure off the top of my head the best way to expose this to an indicator arrow like this issue requires. I would suggest identifying and formulating this before beginning an implementation so that we confirm a satisfying approach, i.e. not introducing a bunch of additional state to make this happen.
I tried rendering the arrow by comparing the top value of DropHover
with window.innerHeight
, it works for the upward arrow but for the downward as you mention it does not render at all.
Yeah. VirtualThought is responsible for which thoughts are in the viewport, so I would look there.
Right, and I believe getSortedRank
is the selector that returns the sorted rank to position the thought but it does not seem to be setting any position for the hover or thought.
One thing that comes to my mind is to get all the children of the context, assuming it only returns the children that are currently rendered, and calculate the rank using getSortedRank
. By comparing the rank with the rank of the last thought of context we might be able to identify the need to render the arrow. At least for rendering the downward arrow.
There isn't a straightforward function to get a list of children that are contained within the viewport, but that information is indirectly accessible within the LayoutTree
. Five thoughts are rendered below the bottom of the viewport to avoid rendering gaps as thoughts are virtualized/unvirtualized during scrolling:
The render loop in LayoutTree short circuits as soon as viewportBottom
is exceeded:
LayoutTree seems like the right place for the arrow logic since it is the component that is aware of the overall layout and rendering of all the visible thoughts. The challenge is that the sorted context hover logic is buried in the DropHover components which is only rendered in visible thoughts.
In the LayoutTree
component, the arrow positioning was not remaining sticky to the top and bottom, I first tried doing it in LayoutTree
but it didn't work probably because of the containers height. It seems to be placed fine in Content
component but it does not have the awareness of LayoutTree
component.
Yes, the sorted context hover logic is what I need instead of using the DropHover
position which is not reliable.
In the
LayoutTree
component, the arrow positioning was not remaining sticky to the top and bottom, I first tried doing it inLayoutTree
but it didn't work probably because of the containers height. It seems to be placed fine inContent
component but it does not have the awareness ofLayoutTree
component.
It shouldn't matter which component it goes in since it is rendered position: fixed
(or position: absolute
+ scrollTop to make it work on iPhone when the keyboard is up).
I have examined the DropHover
and indeed it only works for the rendered thoughts, and the moveThought action actually moves the thought by setting the new rank using getSortedRank
, but in this I do not understand how for example a thought that will go to the bottom of the entire list is placed, is there a condition that checks if it is going below the rendered items? Maybe I am missing something but without knowing where in the list the DropHover
would render this is tricky.
If getSortedRank
is less than the rank of the first thought in the viewport, then the drop location is above the top of the viewport.
If getSortedRank
is more than the rank of the last thought in the viewport, then the drop location is below the bottom of the viewport.
Right, so that brings us to finding out the first and last thought in the viewport.
In this screenshot,
Colorado
is being dragged and hovered over the sortedStates
context, but the drop target is not visible.Render an upward pointing blue triangle at the top of screen to communicate to the user that the thought will be inserted above the top of the screeen.
Render a downward pointing blue triangle at the bottom of the screen when the insertion point is below the bottom of the screen (not pictured).
Animate the arrows with a gentle up-and-down bobbing motion.