Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 27 additions & 19 deletions examples/vite/src/App.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
Chat,
ChatView,
createIcon,
DialogManagerProvider,
MessageReactions,
type NotificationListProps,
NotificationList,
Expand Down Expand Up @@ -52,6 +53,7 @@ import {
getSelectedChatViewFromUrl,
} from './ChatLayout/Sync.tsx';
import { LoadingScreen } from './LoadingScreen/LoadingScreen.tsx';
import { SystemNotification } from './SystemNotification/SystemNotification.tsx';
import { chatViewSelectorItemSet } from './Sidebar/ChatViewSelectorItemSet.tsx';
import {
CustomAttachmentActions,
Expand Down Expand Up @@ -206,6 +208,7 @@ const MessageUiOverride = messageUiVariant
const systemMessageVariant = getSystemMessageVariant();
const reactionsVariant = getReactionsVariant();
const attachmentActionsVariant = getAttachmentActionsVariant();
const globalDialogManager = 'globalDialogManager';

const CustomAttachmentWithActions = (props: AttachmentProps) => (
<Attachment {...props} AttachmentActions={CustomAttachmentActions} />
Expand Down Expand Up @@ -411,27 +414,32 @@ const App = () => {
style={initialAppLayoutStyle}
data-variant={messageUiVariant ?? undefined}
>
<PanelLayoutStyleSync layoutRef={appLayoutRef} />
<ChatViewSelectorWidthSync
iconOnly={chatView.iconOnly}
layoutRef={appLayoutRef}
/>
<ChatView>
<ChatStateSync initialChatView={initialChatView} />
<SidebarLayoutSync />
<ChannelsPanels
filters={filters}
<SystemNotification />
<div className='app-chat-layout__body'>
<PanelLayoutStyleSync layoutRef={appLayoutRef} />
<ChatViewSelectorWidthSync
iconOnly={chatView.iconOnly}
initialChannelId={initialChannelId ?? undefined}
itemSet={chatViewSelectorItemSet}
options={options}
sort={sort}
layoutRef={appLayoutRef}
/>
<ThreadsPanels
iconOnly={chatView.iconOnly}
itemSet={chatViewSelectorItemSet}
/>
</ChatView>
<ChatView>
<DialogManagerProvider id={globalDialogManager}>
<ChatStateSync initialChatView={initialChatView} />
<SidebarLayoutSync />
<ChannelsPanels
filters={filters}
iconOnly={chatView.iconOnly}
initialChannelId={initialChannelId ?? undefined}
itemSet={chatViewSelectorItemSet}
options={options}
sort={sort}
/>
<ThreadsPanels
iconOnly={chatView.iconOnly}
itemSet={chatViewSelectorItemSet}
/>
</DialogManagerProvider>
</ChatView>
</div>
</div>
</Chat>
</SidebarProvider>
Expand Down
20 changes: 8 additions & 12 deletions examples/vite/src/AppSettings/ActionsMenu/ActionsMenu.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,13 @@
import { useMemo, useState } from 'react';
import type { ComponentProps } from 'react';
import { useState } from 'react';
import {
Button,
ContextMenu,
ContextMenuButton,
DialogManagerProvider,
IconBolt,
useContextMenuContext,
useDialogIsOpen,
useDialogOnNearestManager,
type ContextMenuItemComponent,
} from 'stream-chat-react';
import {
NotificationPromptDialog,
Expand Down Expand Up @@ -57,23 +55,18 @@ const ActionsMenuButton = ({
);

export const ActionsMenu = ({ iconOnly = true }: { iconOnly?: boolean }) => (
<DialogManagerProvider id='app-actions-menu-dialog-manager'>
<ActionsMenuInner iconOnly={iconOnly} />
</DialogManagerProvider>
<ActionsMenuInner iconOnly={iconOnly} />
);

function TriggerNotification() {
function TriggerNotificationAction({ onTrigger }: { onTrigger: () => void }) {
const { closeMenu } = useContextMenuContext();
const { dialog: notificationDialog } = useDialogOnNearestManager({
id: notificationPromptDialogId,
});

return (
<ContextMenuButton
label='Trigger Notification'
onClick={() => {
closeMenu();
notificationDialog.open();
onTrigger();
}}
/>
);
Expand All @@ -86,6 +79,9 @@ const ActionsMenuInner = ({ iconOnly }: { iconOnly: boolean }) => {
const { dialog: actionsMenuDialog, dialogManager } = useDialogOnNearestManager({
id: actionsMenuDialogId,
});
const { dialog: notificationDialog } = useDialogOnNearestManager({
id: notificationPromptDialogId,
});

const menuIsOpen = useDialogIsOpen(actionsMenuDialogId, dialogManager?.id);

Expand All @@ -108,7 +104,7 @@ const ActionsMenuInner = ({ iconOnly }: { iconOnly: boolean }) => {
tabIndex={-1}
trapFocus
>
<TriggerNotification />
<TriggerNotificationAction onTrigger={notificationDialog.open} />
</ContextMenu>
<NotificationPromptDialog referenceElement={menuButtonElement} />
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import { useCallback, useEffect, useRef, useState } from 'react';
import type { Dispatch, PointerEvent as ReactPointerEvent, SetStateAction } from 'react';
import type { NotificationSeverity } from 'stream-chat';
import {
addNotificationTargetTag,
IconArrowDown,
IconArrowLeft,
IconChevronRight,
Expand All @@ -19,7 +18,7 @@ import {
NumericInput,
Prompt,
TextInput,
useChatContext,
useNotificationApi,
useDialogIsOpen,
useDialogOnNearestManager,
type NotificationListEnterFrom,
Expand Down Expand Up @@ -197,16 +196,17 @@ const NotificationDraftForm = ({
options={severityOptions}
value={draft.severity}
/>
<label className='app__notification-dialog__field'>
<div className='app__notification-dialog__field'>
<span className='app__notification-dialog__field-label'>Duration (ms)</span>
<NumericInput
aria-label='Duration (ms)'
min={0}
onChange={(event) =>
setDraft((current) => ({ ...current, duration: event.target.value }))
}
value={draft.duration}
/>
</label>
</div>
<NotificationEntrySelect
label='Entry Direction'
onChange={(value) =>
Expand Down Expand Up @@ -307,7 +307,7 @@ export const NotificationPromptDialog = ({
const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
const chipIdRef = useRef(0);
const shellRef = useRef<HTMLDivElement | null>(null);
const { client } = useChatContext();
const { addNotification } = useNotificationApi();
const { dialog, dialogManager } = useDialogOnNearestManager({
id: notificationPromptDialogId,
});
Expand Down Expand Up @@ -362,26 +362,22 @@ export const NotificationPromptDialog = ({
dialog.close();
}, [dialog]);

const addNotification = useCallback(
const publishNotification = useCallback(
(notification: QueuedNotification) => {
client.notifications.add({
message: notification.message,
origin: {
context: {
entryDirection: notification.entryDirection,
panel: notification.targetPanel,
},
emitter: 'vite-preview/ActionsMenu',
},
options: {
actions: buildNotificationActions(notification),
duration: notification.duration,
severity: notification.severity,
tags: addNotificationTargetTag(notification.targetPanel),
addNotification({
actions: buildNotificationActions(notification),
context: {
entryDirection: notification.entryDirection,
panel: notification.targetPanel,
},
duration: notification.duration,
emitter: 'vite-preview/ActionsMenu',
message: notification.message,
severity: notification.severity,
targetPanels: [notification.targetPanel],
});
},
[client],
[addNotification],
);

const queueCurrentDraft = useCallback(() => {
Expand All @@ -406,9 +402,9 @@ export const NotificationPromptDialog = ({
}, [draft]);

const registerQueuedNotifications = useCallback(() => {
queuedNotifications.forEach(addNotification);
queuedNotifications.forEach(publishNotification);
closeDialog();
}, [addNotification, closeDialog, queuedNotifications]);
}, [closeDialog, publishNotification, queuedNotifications]);

const removeQueuedNotification = useCallback((id: string) => {
setQueuedNotifications((current) => current.filter((item) => item.id !== id));
Expand Down
10 changes: 5 additions & 5 deletions examples/vite/src/AppSettings/AppSettings.scss
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,8 @@
}
}

.app__actions-menu {
.str-chat__dialog-contents.app__actions-menu,
.str-chat__context-menu.app__actions-menu {
min-width: min(320px, calc(100vw - 32px));
max-width: min(320px, calc(100vw - 32px));
}
Expand Down Expand Up @@ -249,8 +250,7 @@
display: flex;
flex-direction: column;
width: min(920px, 90vw);
max-height: min(80vh, 760px);
min-height: min(520px, 72vh);
height: min(80vh, 760px);
background: var(--background-core-elevation-2);
color: var(--text-primary);
border: 1px solid var(--border-core-default);
Expand Down Expand Up @@ -282,7 +282,7 @@
.app__settings-modal__tabs {
overflow-y: auto;
overscroll-behavior: contain;
border-right: 1px solid var(--border-core-default);
border-inline-end: 1px solid var(--border-core-default);
padding: 10px;
}

Expand Down Expand Up @@ -383,7 +383,7 @@
}

.app__settings-modal__tabs {
border-right: 1px solid var(--border-core-default);
border-inline-end: 1px solid var(--border-core-default);
border-bottom: 0;
display: block;
gap: 0;
Expand Down
10 changes: 6 additions & 4 deletions examples/vite/src/LoadingScreen/LoadingScreen.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,12 @@ export const LoadingScreen = ({
</div>
</div>
<div className='str-chat__channel'>
<div className='str-chat__main-panel'>
<div className='str-chat__main-panel-inner'>
<div className='str-chat__window app-loading-screen__window'>
<LoadingChannel />
<div className='str-chat__container'>
<div className='str-chat__main-panel'>
<div className='str-chat__main-panel-inner'>
<div className='str-chat__window app-loading-screen__window'>
<LoadingChannel />
</div>
</div>
</div>
</div>
Expand Down
84 changes: 84 additions & 0 deletions examples/vite/src/SystemNotification/SystemNotification.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
.str-chat__system-notification {
display: flex;
flex-shrink: 0;
align-items: center;
justify-content: center;
gap: var(--spacing-xs, 8px);
padding-block: var(--spacing-xs, 8px);
padding-inline: var(--spacing-sm, 12px);
background: var(--background-core-surface-default, #ebeef1);
color: var(--chat-text-system, #414552);
font-feature-settings:
'liga' off,
'clig' off;
font-size: var(--typography-font-size-xs, 12px);
font-style: normal;
font-weight: var(--typography-font-weight-semi-bold, 600);
line-height: var(--typography-line-height-tight, 16px);
animation: str-chat__system-notification-slide-in 300ms ease-out both;
overflow: hidden;
width: 100%;
z-index: 2;
}

.str-chat__system-notification--exiting {
animation: str-chat__system-notification-slide-out 300ms ease-in both;
}

.str-chat__system-notification--interactive {
cursor: pointer;
}

.str-chat__system-notification-icon {
align-items: center;
display: inline-flex;
flex-shrink: 0;
}

.str-chat__system-notification-message {
white-space: nowrap;
overflow-y: visible;
overflow-x: hidden;
overflow-x: clip;
text-overflow: ellipsis;
}

.str-chat__system-notification--loading .str-chat__system-notification-icon {
animation: str-chat__system-notification-spin 1.5s linear infinite;
}

@keyframes str-chat__system-notification-slide-in {
from {
max-height: 0;
opacity: 0;
padding-block: 0;
}

to {
max-height: 4rem;
opacity: 1;
}
}

@keyframes str-chat__system-notification-slide-out {
from {
max-height: 4rem;
opacity: 1;
}

to {
max-height: 0;
opacity: 0;
padding-block: 0;
}
}

@keyframes str-chat__system-notification-spin {
from {
transform: rotate(0deg);
}

to {
transform: rotate(360deg);
}
}
Loading
Loading