Skip to content

Commit f4730cf

Browse files
committed
fix: presence color compatibility with deeplink
1 parent b384f30 commit f4730cf

1 file changed

Lines changed: 21 additions & 35 deletions

File tree

packages/root-cms/ui/components/DocEditor/DocEditor.tsx

Lines changed: 21 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ import {
4343
IconTriangleFilled,
4444
} from '@tabler/icons-preact';
4545
import {createContext} from 'preact';
46+
import {CSSProperties} from 'preact/compat';
4647
import {
4748
useContext,
4849
useEffect,
@@ -551,6 +552,16 @@ DocEditor.FieldBody = (props: FieldProps) => {
551552
const targeted = deeplink.value === props.deepKey;
552553
const ref = useRef<HTMLDivElement>(null);
553554

555+
// Presence highlight: color the field to match the (first other) viewer
556+
// focused on it, à la Google Docs. Applied declaratively (rather than via
557+
// imperative classList/style mutations) so it survives re-renders such as the
558+
// `deeplink-target` class toggling on/off.
559+
const fieldViewers = useFieldViewers(props.deepKey);
560+
const presenceColor = useMemo(() => {
561+
const other = fieldViewers.find((viewer) => !viewer.isCurrentUser);
562+
return (other || fieldViewers[0])?.color || '';
563+
}, [fieldViewers]);
564+
554565
const showFieldHeader = useMemo(() => {
555566
if (field.type === 'object') {
556567
// Default to the "drawer" variant.
@@ -573,8 +584,14 @@ DocEditor.FieldBody = (props: FieldProps) => {
573584
className={joinClassNames(
574585
'DocEditor__field',
575586
field.deprecated && 'DocEditor__field--deprecated',
576-
targeted && 'deeplink-target'
587+
targeted && 'deeplink-target',
588+
presenceColor && 'DocEditor__field--presence'
577589
)}
590+
style={
591+
presenceColor
592+
? ({'--presence-color': presenceColor} as CSSProperties)
593+
: undefined
594+
}
578595
data-type={field.type}
579596
data-level={level}
580597
id={props.deepKey}
@@ -683,47 +700,16 @@ DocEditor.FieldHeader = (props: FieldProps & {className?: string}) => {
683700
/**
684701
* Renders miniature avatars of other viewers who currently have this field
685702
* focused. Sized to match the translate icon so it never causes layout shift.
686-
*
687-
* Also color-codes the field: the enclosing `.DocEditor__field` gets a colored
688-
* border matching the (first other) viewer focused on it, à la Google Docs, so
689-
* it's easy to tell at a glance who is on which field.
703+
* (The field's colored presence border is applied in `FieldBody`.)
690704
*/
691705
DocEditor.FieldHeaderViewers = (props: {deepKey: string}) => {
692706
const viewers = useFieldViewers(props.deepKey);
693-
const ref = useRef<HTMLDivElement>(null);
694-
695-
// The color to highlight the field with: prefer the first *other* viewer so
696-
// the highlight reflects who else is here (not your own color).
697-
const highlightColor = useMemo(() => {
698-
const other = viewers.find((viewer) => !viewer.isCurrentUser);
699-
return (other || viewers[0])?.color || '';
700-
}, [viewers]);
701-
702-
useEffect(() => {
703-
const fieldEl = ref.current?.closest<HTMLElement>('.DocEditor__field');
704-
if (!fieldEl) {
705-
return;
706-
}
707-
if (highlightColor) {
708-
fieldEl.style.setProperty('--presence-color', highlightColor);
709-
fieldEl.classList.add('DocEditor__field--presence');
710-
} else {
711-
fieldEl.style.removeProperty('--presence-color');
712-
fieldEl.classList.remove('DocEditor__field--presence');
713-
}
714-
return () => {
715-
fieldEl.style.removeProperty('--presence-color');
716-
fieldEl.classList.remove('DocEditor__field--presence');
717-
};
718-
}, [highlightColor]);
719707

720708
if (viewers.length === 0) {
721-
// Keep an (empty) anchor element mounted so the cleanup effect above can
722-
// still find the field and clear the highlight when viewers leave.
723-
return <div ref={ref} className="DocEditor__FieldHeader__viewers" />;
709+
return null;
724710
}
725711
return (
726-
<div ref={ref} className="DocEditor__FieldHeader__viewers">
712+
<div className="DocEditor__FieldHeader__viewers">
727713
{viewers.map((viewer) => (
728714
<UserAvatar
729715
key={viewer.email}

0 commit comments

Comments
 (0)