-
Notifications
You must be signed in to change notification settings - Fork 580
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
Teacher tool: notes area auto resizing on enter, more text entered #9920
Conversation
@@ -11,6 +11,8 @@ export interface DebouncedTextareaProps extends TextareaProps { | |||
export const DebouncedTextarea: React.FC<DebouncedTextareaProps> = ({ intervalMs = 500, ...props }) => { | |||
const timerId = useRef<NodeJS.Timeout | undefined>(undefined); | |||
const latestValue = useRef<string>(""); | |||
const textareaRef = useRef<HTMLTextAreaElement>(null); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just a note of caution about the use of useRef
here: if these refs change for any reason, the values captured in the useEffect
below will go stale (even adding the refs as dependencies won't change this). If this happens, control resizing will break.
It's probably unlikely to happen in the current use case, but wanted to note it. A safer way to allocate the state the ref slot is to use useState
, and then add the value as a dependency to the useEffect
.
@@ -21,11 +23,28 @@ export const DebouncedTextarea: React.FC<DebouncedTextareaProps> = ({ intervalMs | |||
// If the timer is pending and the component unmounts, | |||
// clear the timer and fire the onChange event immediately. | |||
useEffect(() => { | |||
const resizeObserver = new ResizeObserver(() => { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think I quite follow why this is necessary in addition to the text area resizing. Could you break it down for me?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It also assumes (I think) that all instances of the DebouncedTextarea will want autoResize, which may not be the case. So if this is necessary, we should probably make it optional just like we did in textarea.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nope, you're right, this isn't needed. I thought I needed this for the resizing to work nicely with the parent component, but it was just css stuff that I needed to change, and since I changed the css stuff after I added the logic to DebouncedTextarea
, I thought they were both needed. Removed!
@@ -57,6 +61,10 @@ export const Textarea = (props: TextareaProps) => { | |||
if (onChange) { | |||
onChange(newValue); | |||
} | |||
if (autoResize && resizeRef.current) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What happens if someone says autoResize = true but doesn't pass in a resizeRef?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I was thinking about this, too. It felt weird to me, though, that just passing a resizeRef
would just immediately make the textarea resizable. As I'm typing this, though, I think I was just being a bit overcautious. I think just having the resizeRef
is fine, and that can be the source of truth for knowing that a we want the textarea to auto-resize.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I do not think we should have resizeRef implicitly cause resizing to start happening. I actually think we should rename resizeRef to just textareaRef (or get rid of the parameter if possible). But what happens if autoResize is true and the ref is not passed in? Nothing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh, I hadn't tested that, but just did. If you don't pass in a ref, you get a bunch of errors. I think I see what you're saying, though. We shouldn't need to pass in a ref, and should only need the flag because the ref is just the HTML textarea. Let me play with it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got rid of it as a prop, now just defining the ref in the component.
@@ -38,6 +40,8 @@ export const Textarea = (props: TextareaProps) => { | |||
readOnly, | |||
resize, | |||
wrap, | |||
autoResize, | |||
resizeRef, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe just textareaRef
? People could use this for all sorts of things, not just resizing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice. One more nitpick, and I still would like if we could reduce the bottom padding a bit, but nothing blocking.
@@ -39,5 +39,5 @@ export const DebouncedTextarea: React.FC<DebouncedTextareaProps> = ({ intervalMs | |||
timerId.current = setTimeout(sendChange, intervalMs); | |||
}; | |||
|
|||
return <Textarea {...props} onChange={onChangeDebounce} />; | |||
return <Textarea {...props} autoResize={true} onChange={onChangeDebounce} /> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Since DebouncedTextareaProps
extends TextareaProps
, someone can actually set autoResize
when specifying a DebouncedTextarea
component (i.e. <DebouncedTextarea autoResize={true} ... />
), which I think is a good thing.
So instead of hardcoding this to true for all DebouncedTextAreas
, could we let it pass-through as a part of the {...props}
and just set autoResize
to true in the Notes component?
…textarea for notes
Would setting a min-height in the css solve this problem? |
Yep, that's what it needed. Thank you! |
While a user is typing in the notes field, we want the textarea to grow with the text input so they don't have to deal with cropping and scrolling.
The kind of interesting thing that happens right now is that when you change tabs, the expanded style of the text box goes away, but once you make changes in it, the expanded style of the textarea returns. I kind of like this effect, but if others think it feels like a bug, I can investigate persisting the style changes between state changes.
Also, right now, I am getting an error from the iframe driver seemingly from a
setHighContrast
event with trying to turn something into a string when it's undefined. I stepped through it in the debugger, and couldn't find anything wrong in the first run-through, but there might be something happening because of strict mode. This error doesn't cause any problems for interacting with the app, but is something we should fix. I can look into it more on Monday.Upload target: https://makecode.microbit.org/app/c75e983d88131448e2408ef0f2839596db1eff2e-3521ca26a9--eval