Skip to content

Commit 143555b

Browse files
committed
feat: use own anchor root for DialogAnchor
1 parent eb6ab99 commit 143555b

File tree

4 files changed

+109
-94
lines changed

4 files changed

+109
-94
lines changed

src/components/Dialog/DialogAnchor.tsx

+6-2
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import clsx from 'clsx';
12
import { Placement } from '@popperjs/core';
23
import React, { ComponentProps, PropsWithChildren, useEffect, useRef } from 'react';
34
import { usePopper } from 'react-popper';
@@ -48,14 +49,15 @@ export function useDialogAnchor<T extends HTMLElement>({
4849

4950
type DialogAnchorProps = PropsWithChildren<Partial<DialogAnchorOptions>> & {
5051
id: string;
51-
} & ComponentProps<'div' | 'span'>;
52+
} & ComponentProps<'div'>;
5253

5354
export const DialogAnchor = ({
5455
children,
5556
className,
5657
id,
5758
placement = 'auto',
5859
referenceElement = null,
60+
...restDivProps
5961
}: DialogAnchorProps) => {
6062
const open = useDialogIsOpen(id);
6163
const { attributes, popperElementRef, styles } = useDialogAnchor<HTMLDivElement>({
@@ -67,8 +69,10 @@ export const DialogAnchor = ({
6769
return (
6870
<DialogPortalEntry dialogId={id}>
6971
<div
72+
{...restDivProps}
7073
{...attributes.popper}
71-
className={className}
74+
className={clsx('str-chat__dialog-contents', className)}
75+
data-testid='str-chat__dialog-contents'
7276
ref={popperElementRef}
7377
style={styles.popper}
7478
>

src/components/Dialog/DialogPortal.tsx

+11-16
Original file line numberDiff line numberDiff line change
@@ -18,22 +18,17 @@ export const DialogPortalDestination = () => {
1818
);
1919

2020
return (
21-
<>
22-
<div
23-
className='str-chat__dialog-overlay'
24-
onClick={() => dialogsManager.closeAll()}
25-
style={{
26-
height: '100%',
27-
inset: '0',
28-
overflow: 'hidden',
29-
position: 'absolute',
30-
width: '100%',
31-
zIndex: shouldRender ? '2' : '-1',
32-
}}
33-
>
34-
<div data-str-chat__portal-id={dialogsManager.id} />
35-
</div>
36-
</>
21+
<div
22+
className='str-chat__dialog-overlay'
23+
data-str-chat__portal-id={dialogsManager.id}
24+
data-testid='str-chat__dialog-overlay'
25+
onClick={() => dialogsManager.closeAll()}
26+
style={
27+
{
28+
'--str-chat__dialog-overlay-height': shouldRender ? '100%' : '0',
29+
} as React.CSSProperties
30+
}
31+
></div>
3732
);
3833
};
3934

src/components/MessageActions/MessageActions.tsx

+2-3
Original file line numberDiff line numberDiff line change
@@ -146,9 +146,6 @@ export const MessageActions = <
146146
toggleOpen={dialog?.toggleSingle}
147147
>
148148
<DialogAnchor
149-
className={clsx('str-chat__message-actions-box', {
150-
'str-chat__message-actions-box--open': dialogIsOpen,
151-
})}
152149
id={dialogId}
153150
placement={isMine ? 'top-end' : 'top-start'}
154151
referenceElement={actionsBoxButtonRef.current}
@@ -162,6 +159,8 @@ export const MessageActions = <
162159
handleMute={handleMute}
163160
handlePin={handlePin}
164161
isUserMuted={isMuted}
162+
mine={isMine}
163+
open={dialogIsOpen}
165164
/>
166165
</DialogAnchor>
167166
<button

src/components/MessageActions/MessageActionsBox.tsx

+90-73
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
1-
import React from 'react';
1+
import clsx from 'clsx';
2+
import React, { ComponentProps } from 'react';
23

34
import { MESSAGE_ACTIONS } from '../Message/utils';
45

@@ -27,14 +28,17 @@ export type MessageActionsBoxProps<
2728
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics
2829
> = Pick<MessageContextValue<StreamChatGenerics>, PropsDrilledToMessageActionsBox> & {
2930
isUserMuted: () => boolean;
30-
};
31+
mine: boolean;
32+
open: boolean;
33+
} & ComponentProps<'div'>;
3134

3235
const UnMemoizedMessageActionsBox = <
3336
StreamChatGenerics extends DefaultStreamChatGenerics = DefaultStreamChatGenerics
3437
>(
3538
props: MessageActionsBoxProps<StreamChatGenerics>,
3639
) => {
3740
const {
41+
className,
3842
getMessageActions,
3943
handleDelete,
4044
handleEdit,
@@ -43,6 +47,8 @@ const UnMemoizedMessageActionsBox = <
4347
handleMute,
4448
handlePin,
4549
isUserMuted,
50+
open,
51+
...restDivProps
4652
} = props;
4753

4854
const {
@@ -70,81 +76,92 @@ const UnMemoizedMessageActionsBox = <
7076
}
7177
};
7278

79+
const rootClassName = clsx('str-chat__message-actions-box', className, {
80+
'str-chat__message-actions-box--open': open,
81+
});
82+
7383
const buttonClassName =
7484
'str-chat__message-actions-list-item str-chat__message-actions-list-item-button';
7585

7686
return (
77-
<div
78-
aria-label={t('aria/Message Options')}
79-
className='str-chat__message-actions-list'
80-
role='listbox'
81-
>
82-
<CustomMessageActionsList customMessageActions={customMessageActions} message={message} />
83-
{messageActions.indexOf(MESSAGE_ACTIONS.quote) > -1 && (
84-
<button
85-
aria-selected='false'
86-
className={buttonClassName}
87-
onClick={handleQuote}
88-
role='option'
89-
>
90-
{t<string>('Reply')}
91-
</button>
92-
)}
93-
{messageActions.indexOf(MESSAGE_ACTIONS.pin) > -1 && !message.parent_id && (
94-
<button aria-selected='false' className={buttonClassName} onClick={handlePin} role='option'>
95-
{!message.pinned ? t<string>('Pin') : t<string>('Unpin')}
96-
</button>
97-
)}
98-
{messageActions.indexOf(MESSAGE_ACTIONS.markUnread) > -1 && !threadList && !!message.id && (
99-
<button
100-
aria-selected='false'
101-
className={buttonClassName}
102-
onClick={handleMarkUnread}
103-
role='option'
104-
>
105-
{t<string>('Mark as unread')}
106-
</button>
107-
)}
108-
{messageActions.indexOf(MESSAGE_ACTIONS.flag) > -1 && (
109-
<button
110-
aria-selected='false'
111-
className={buttonClassName}
112-
onClick={handleFlag}
113-
role='option'
114-
>
115-
{t<string>('Flag')}
116-
</button>
117-
)}
118-
{messageActions.indexOf(MESSAGE_ACTIONS.mute) > -1 && (
119-
<button
120-
aria-selected='false'
121-
className={buttonClassName}
122-
onClick={handleMute}
123-
role='option'
124-
>
125-
{isUserMuted() ? t<string>('Unmute') : t<string>('Mute')}
126-
</button>
127-
)}
128-
{messageActions.indexOf(MESSAGE_ACTIONS.edit) > -1 && (
129-
<button
130-
aria-selected='false'
131-
className={buttonClassName}
132-
onClick={handleEdit}
133-
role='option'
134-
>
135-
{t<string>('Edit Message')}
136-
</button>
137-
)}
138-
{messageActions.indexOf(MESSAGE_ACTIONS.delete) > -1 && (
139-
<button
140-
aria-selected='false'
141-
className={buttonClassName}
142-
onClick={handleDelete}
143-
role='option'
144-
>
145-
{t<string>('Delete')}
146-
</button>
147-
)}
87+
<div {...restDivProps} className={rootClassName} data-testid='message-actions-box'>
88+
<div
89+
aria-label={t('aria/Message Options')}
90+
className='str-chat__message-actions-list'
91+
role='listbox'
92+
>
93+
<CustomMessageActionsList customMessageActions={customMessageActions} message={message} />
94+
{messageActions.indexOf(MESSAGE_ACTIONS.quote) > -1 && (
95+
<button
96+
aria-selected='false'
97+
className={buttonClassName}
98+
onClick={handleQuote}
99+
role='option'
100+
>
101+
{t<string>('Reply')}
102+
</button>
103+
)}
104+
{messageActions.indexOf(MESSAGE_ACTIONS.pin) > -1 && !message.parent_id && (
105+
<button
106+
aria-selected='false'
107+
className={buttonClassName}
108+
onClick={handlePin}
109+
role='option'
110+
>
111+
{!message.pinned ? t<string>('Pin') : t<string>('Unpin')}
112+
</button>
113+
)}
114+
{messageActions.indexOf(MESSAGE_ACTIONS.markUnread) > -1 && !threadList && !!message.id && (
115+
<button
116+
aria-selected='false'
117+
className={buttonClassName}
118+
onClick={handleMarkUnread}
119+
role='option'
120+
>
121+
{t<string>('Mark as unread')}
122+
</button>
123+
)}
124+
{messageActions.indexOf(MESSAGE_ACTIONS.flag) > -1 && (
125+
<button
126+
aria-selected='false'
127+
className={buttonClassName}
128+
onClick={handleFlag}
129+
role='option'
130+
>
131+
{t<string>('Flag')}
132+
</button>
133+
)}
134+
{messageActions.indexOf(MESSAGE_ACTIONS.mute) > -1 && (
135+
<button
136+
aria-selected='false'
137+
className={buttonClassName}
138+
onClick={handleMute}
139+
role='option'
140+
>
141+
{isUserMuted() ? t<string>('Unmute') : t<string>('Mute')}
142+
</button>
143+
)}
144+
{messageActions.indexOf(MESSAGE_ACTIONS.edit) > -1 && (
145+
<button
146+
aria-selected='false'
147+
className={buttonClassName}
148+
onClick={handleEdit}
149+
role='option'
150+
>
151+
{t<string>('Edit Message')}
152+
</button>
153+
)}
154+
{messageActions.indexOf(MESSAGE_ACTIONS.delete) > -1 && (
155+
<button
156+
aria-selected='false'
157+
className={buttonClassName}
158+
onClick={handleDelete}
159+
role='option'
160+
>
161+
{t<string>('Delete')}
162+
</button>
163+
)}
164+
</div>
148165
</div>
149166
);
150167
};

0 commit comments

Comments
 (0)