feat: Show collab cursor names upon loading document. (#2732)

Second attempt, adds a class to the editor for a couple of seconds when the awareness is loaded to force cursors to display
This commit is contained in:
Tom Moor 2021-11-04 17:24:23 -07:00 committed by GitHub
parent 1a6921f6c7
commit eb9ff990ac
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 43 additions and 1 deletions

View File

@ -40,6 +40,7 @@ export type Props = {|
maxLength?: number,
scrollTo?: string,
theme?: Theme,
className?: string,
handleDOMEvents?: Object,
readOnlyWriteCheckboxes?: boolean,
onBlur?: (event: SyntheticEvent<>) => any,
@ -276,6 +277,7 @@ const StyledEditor = styled(RichMarkdownEditor)`
}
> div {
opacity: 0;
transition: opacity 100ms ease-in-out;
position: absolute;
top: -1.8em;
font-size: 13px;
@ -295,11 +297,14 @@ const StyledEditor = styled(RichMarkdownEditor)`
&:hover {
> div {
opacity: 1;
transition: opacity 100ms ease-in-out;
}
}
}
}
&.show-cursor-names .ProseMirror-yjs-cursor > div {
opacity: 1;
}
`;
const EditorTooltip = ({ children, ...props }) => (

21
app/hooks/useIsMounted.js Normal file
View File

@ -0,0 +1,21 @@
// @flow
import * as React from "react";
/**
* Hook to check if component is still mounted
*
* @returns {boolean} true if the component is mounted, false otherwise
*/
export default function useIsMounted() {
const isMounted = React.useRef(false);
React.useEffect(() => {
isMounted.current = true;
return () => {
isMounted.current = false;
};
}, []);
return React.useCallback(() => isMounted.current, []);
}

View File

@ -10,6 +10,7 @@ import env from "env";
import useCurrentToken from "hooks/useCurrentToken";
import useCurrentUser from "hooks/useCurrentUser";
import useIdle from "hooks/useIdle";
import useIsMounted from "hooks/useIsMounted";
import usePageVisibility from "hooks/usePageVisibility";
import useStores from "hooks/useStores";
import useToasts from "hooks/useToasts";
@ -28,6 +29,7 @@ function MultiplayerEditor({ ...props }: Props, ref: any) {
const currentUser = useCurrentUser();
const { presence, ui } = useStores();
const token = useCurrentToken();
const [showCursorNames, setShowCursorNames] = React.useState(false);
const [remoteProvider, setRemoteProvider] = React.useState();
const [isLocalSynced, setLocalSynced] = React.useState(false);
const [isRemoteSynced, setRemoteSynced] = React.useState(false);
@ -35,6 +37,7 @@ function MultiplayerEditor({ ...props }: Props, ref: any) {
const { showToast } = useToasts();
const isIdle = useIdle();
const isVisible = usePageVisibility();
const isMounted = useIsMounted();
// Provider initialization must be within useLayoutEffect rather than useState
// or useMemo as both of these are ran twice in React StrictMode resulting in
@ -75,6 +78,18 @@ function MultiplayerEditor({ ...props }: Props, ref: any) {
});
});
const showCursorNames = () => {
setShowCursorNames(true);
setTimeout(() => {
if (isMounted()) {
setShowCursorNames(false);
}
}, 2000);
provider.off("awarenessChange", showCursorNames);
};
provider.on("awarenessChange", showCursorNames);
localProvider.on("synced", () =>
// only set local storage to "synced" if it's loaded a non-empty doc
setLocalSynced(!!ydoc.get("default")._start)
@ -180,6 +195,7 @@ function MultiplayerEditor({ ...props }: Props, ref: any) {
extensions={extensions}
ref={showCache ? undefined : ref}
style={showCache ? { display: "none" } : undefined}
className={showCursorNames ? "show-cursor-names" : undefined}
/>
</>
);