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:
@@ -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
34
app/hooks/useOnScreen.ts
Normal 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;
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user