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:
parent
1a6921f6c7
commit
eb9ff990ac
|
@ -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 }) => (
|
||||
|
|
|
@ -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, []);
|
||||
}
|
|
@ -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}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
|
|
Reference in New Issue