-
Notifications
You must be signed in to change notification settings - Fork 126
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
joinThoughts: Multiline not updated #2501
Comments
This comment was marked as outdated.
This comment was marked as outdated.
Hey, I really fear sounding stupid here, but isn't In const updateMultiline = useCallback(() => {
if (!contentRef.current) return
const height = contentRef.current.getBoundingClientRect().height
// must match line-height as defined in thought-container
const singleLineHeight = fontSize * 2
// .editable.multiline gets 5px of padding-top to offset the collapsed line-height
// we need to account for padding-top, otherwise it can cause a false positive
const style = window.getComputedStyle(contentRef.current)
const paddingTop = parseInt(style.paddingTop)
const paddingBottom = parseInt(style.paddingBottom)
// 2x the single line height would indicate that the thought was multiline if it weren't for the change in line-height and padding.
// 1.2x is used for a more forgiving condition.
// 1.5x can cause multiline to alternate in Safari for some reason. There may be a mistake in the height calculation or the inclusion of padding that is causing this. Padding was added to the calculation in commit 113c692. Further investigation is needed.
// See: https://github.com/cybersemics/em/issues/2778#issuecomment-2605083798
setMultiline(height - paddingTop - paddingBottom > singleLineHeight * 1.2)
}, [contentRef, fontSize]) anyways, I've attached a draft pr, you can see it works fine that way |
https://react.dev/reference/react/useLayoutEffect If changing This actually used to be |
yeah, I did sound stupid hahaha OK, I'll see why it's having the delay. it's sure important to have it as a layout effect, yeah |
I don't think it was stupid. Thanks, let me know if you figure out anything! |
I now think that problem is this: // While editing, watch the current Value and trigger the layout effect
const editingValue = editingValueStore.useSelector(state => (isEditing ? state : null))
// Recalculate multiline on mount, when the font size changes, edit, split view resize, value changes, and when the
// cursor changes to or from the element.
useLayoutEffect(updateMultiline, [
contentRef, <----- this does not change when you do a join
fontSize,
isEditing,
showSplitView,
simplePath,
splitPosition,
editingValue, <---- this is the thing that is triggering on join
updateMultiline,
]) const updateMultiline = useCallback(() => {
if (!contentRef.current) return
. . .. . . . . . . . . .
setMultiline(height - paddingTop - paddingBottom > singleLineHeight * 1.2)
}, [contentRef, fontSize]) <---- depends on `contentRef`, but not on `editingValue` the |
Hi, thanks for the update. I don't see how |
but it is.
|
Fair enough, that would demonstrate it! It's not clicking for me yet, but I look forward to seeing it in action. I didn't think callbacks needed to update refs, since |
It's stale, it uses the ref from the previous render: or even simpler, logging the contentRef in the It's like we don't really wanna memoize the em/src/components/Editable/useMultiline.ts Lines 21 to 22 in f87b263
like if to think, what is the sense of memoizing a function that measures the element's rect? should it be memoized in the first place? why do we need a clojure with an arbitrary state of so I'd suggest just dropping the memo part, or adding the same |
Thank you for the additional explanation, that's helpful. I'm now wondering if this behavior could be related to the React We could this theory out be rewriting
That's a good point. I'm really not sure why its memoized, now that you point it out. Perhaps to avoid re-defining the function on every render, but that's insignificant. Memoizing probably uses up extra memory anyway. Aside: The videos are super helpful, but it would be even more useful if they were uploaded as .mp4 or .mov so that the playback controls appear. Animated gifs aren't great for close review since I can't easily move forward or backward, or frame by frame. Something to consider. Thanks! |
Yes, modifying the join indeed does work, as we get a new thought. But to alter that to change this, won't be wise imo xd So let's stick with a function that is recreated?(attaching it as a pr) p.s. |
Okay! Removing the Great work, thanks. |
Background
Single-line and multiline thoughts use different line-heights* for aesthetic reasons. Because there is no CSS-only method of applying a style to multiline thoughts only, we have to use Javascript. Detecting if a thought is multiline is not the hard part; it's knowing when to re-trigger the calculation. ResizeObservers are too expensive, so we manually define all the conditions in various useLayoutEffects. There are a lot of conditions to keep track of, and it's easy to miss new ones.
The first question for this issue is, why is
multiline
not updated correctly on join? A value change should trigger a recalculation. It may be a timing issue, or it may be that there is some other piece of state that needs to be included in the effect dependencies.See: useMultiline
(*Completely different approaches such as using padding instead of line-height have been explored, and are currently untenable. See #2551. If you can think of a better alternative, please post it there.)
Steps to Reproduce
a
.Current Behavior
Line height is incorrect because thought is not re-rendered with multiline: true
Expected Behavior
The text was updated successfully, but these errors were encountered: