diff --git a/demo/src/components/Avatar.tsx b/demo/src/components/Avatar.tsx index c9d84ab0..ee9afcd5 100644 --- a/demo/src/components/Avatar.tsx +++ b/demo/src/components/Avatar.tsx @@ -40,8 +40,11 @@ export const Avatar = ({
diff --git a/demo/src/components/Image.tsx b/demo/src/components/Image.tsx index 3a91253b..95d36be0 100644 --- a/demo/src/components/Image.tsx +++ b/demo/src/components/Image.tsx @@ -1,6 +1,8 @@ import cn from 'classnames'; -import { useElementSelect, useMembers } from '../hooks'; -import { findActiveMember, getMemberFirstName, getOutlineClasses } from '../utils'; +import { useClickOutside, useElementSelect, useMembers } from '../hooks'; +import { findActiveMembers, getMemberFirstName, getOutlineClasses } from '../utils'; +import { useRef } from 'react'; +import { usePreview } from './PreviewContext.tsx'; interface Props extends React.HTMLAttributes { src: string; @@ -12,19 +14,26 @@ interface Props extends React.HTMLAttributes { } export const Image = ({ src, children, className, id, slide, locatable = true }: Props) => { + const containerRef = useRef(null); + const preview = usePreview(); const { members, self } = useMembers(); const { handleSelect } = useElementSelect(id, false); - const activeMember = findActiveMember(id, slide, members); - const { outlineClasses, stickyLabelClasses } = getOutlineClasses(activeMember); - const memberName = getMemberFirstName(activeMember); - const label = self?.connectionId === activeMember?.connectionId ? 'You' : memberName; + const activeMembers = findActiveMembers(id, slide, members); + const occupiedByMe = activeMembers.some((member) => member.connectionId === self?.connectionId); + const [firstMember] = activeMembers; + const { outlineClasses, stickyLabelClasses } = getOutlineClasses(firstMember); + const memberName = getMemberFirstName(firstMember); + const name = occupiedByMe ? 'You' : memberName; + const label = activeMembers.length > 1 ? `${name} +${activeMembers.length - 1}` : name; + + useClickOutside(containerRef, self, occupiedByMe && !preview); return (
; } + export const useTextComponentLock = ({ id, slide, defaultText, containerRef }: UseTextComponentLockArgs) => { const spaceName = getSpaceNameFromUrl(); const { members, self } = useMembers(); @@ -32,7 +34,8 @@ export const useTextComponentLock = ({ id, slide, defaultText, containerRef }: U const { channel } = useChannel(channelName, (message) => { if (message.connectionId === self?.connectionId) return; - updateContent(message.data); + const sanitizedValue = sanitize(message.data, { allowedTags: [] }); + updateContent(sanitizedValue); }); const optimisticallyLocked = !!activeMember; diff --git a/demo/src/utils/active-member.ts b/demo/src/utils/active-member.ts index e636d4b8..f860f327 100644 --- a/demo/src/utils/active-member.ts +++ b/demo/src/utils/active-member.ts @@ -5,6 +5,10 @@ export const findActiveMember = (id: string, slide: string, members?: Member[]) return members.find((member) => member.location?.element === id && member.location?.slide === slide); }; +export const findActiveMembers = (id: string, slide: string, members?: Member[]) => { + return (members ?? []).filter((member) => member.location?.element === id && member.location?.slide === slide); +}; + export const getMemberFirstName = (member?: Member) => { if (!member) return ''; return member.profileData.name.split(' ')[0];