fix: Editor title does not autoFocus on first load (#3238)

* fix: Editor title does not autoFocus on first load

* Detect IntersectionObserver for IE support
This commit is contained in:
Tom Moor
2022-03-13 22:08:26 -07:00
committed by GitHub
parent 10cc6ed154
commit 5977fe4caa
3 changed files with 45 additions and 4 deletions

View File

@@ -1,6 +1,7 @@
import isPrintableKeyEvent from "is-printable-key-event"; import isPrintableKeyEvent from "is-printable-key-event";
import * as React from "react"; import * as React from "react";
import styled from "styled-components"; import styled from "styled-components";
import useOnScreen from "~/hooks/useOnScreen";
type Props = Omit<React.HTMLAttributes<HTMLSpanElement>, "ref" | "onChange"> & { type Props = Omit<React.HTMLAttributes<HTMLSpanElement>, "ref" | "onChange"> & {
disabled?: boolean; disabled?: boolean;
@@ -69,11 +70,17 @@ const ContentEditable = React.forwardRef(
callback?.(event); callback?.(event);
}; };
React.useLayoutEffect(() => { // This is to account for being within a React.Suspense boundary, in this
if (autoFocus) { // case the component may be rendered with display: none. React 18 may solve
// this in the future by delaying useEffect hooks:
// https://github.com/facebook/react/issues/14536#issuecomment-861980492
const isVisible = useOnScreen(ref);
React.useEffect(() => {
if (autoFocus && isVisible && !disabled && !readOnly) {
ref.current?.focus(); ref.current?.focus();
} }
}, [autoFocus, ref]); }, [autoFocus, disabled, isVisible, readOnly, ref]);
React.useEffect(() => { React.useEffect(() => {
if (value !== ref.current?.innerText) { if (value !== ref.current?.innerText) {

34
app/hooks/useOnScreen.ts Normal file
View File

@@ -0,0 +1,34 @@
import * as React from "react";
/**
* Hook to return if a given ref is visible on screen.
*
* @returns boolean if the node is visible
*/
export default function useOnScreen(ref: React.RefObject<HTMLElement>) {
const isSupported = "IntersectionObserver" in window;
const [isIntersecting, setIntersecting] = React.useState(!isSupported);
React.useEffect(() => {
const element = ref.current;
let observer: IntersectionObserver | undefined;
if (isSupported) {
observer = new IntersectionObserver(([entry]) => {
// Update our state when observer callback fires
setIntersecting(entry.isIntersecting);
});
}
if (element) {
observer?.observe(element);
}
return () => {
if (element) {
observer?.unobserve(element);
}
};
}, []);
return isIntersecting;
}

View File

@@ -1,10 +1,10 @@
import * as React from "react"; import * as React from "react";
/** /**
* Hook to return page visibility state. * Hook to return page visibility state.
* *
* @returns boolean if the page is visible * @returns boolean if the page is visible
*/ */
export default function usePageVisibility(): boolean { export default function usePageVisibility(): boolean {
const [visible, setVisible] = React.useState(true); const [visible, setVisible] = React.useState(true);