-
Notifications
You must be signed in to change notification settings - Fork 69
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[Storybook v8] Add file for Participant List (#4818)
* Add files for ParticipantList
- Loading branch information
Showing
8 changed files
with
381 additions
and
4 deletions.
There are no files selected for viewing
46 changes: 46 additions & 0 deletions
46
packages/storybook8/stories/Components/ParticipantList/Docs.mdx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import { ParticipantList } from '@azure/communication-react'; | ||
import { Canvas, Meta } from '@storybook/blocks'; | ||
import * as ParticipantStories from './index.stories'; | ||
|
||
import DefaultCallParticipantListExampleText from '!!raw-loader!./snippets/DefaultCall.snippet.tsx'; | ||
import DefaultChatParticipantListExampleText from '!!raw-loader!./snippets/DefaultChat.snippet.tsx'; | ||
import InteractiveCallParticipantListExampleText from '!!raw-loader!./snippets/InteractiveCall.snippet.tsx'; | ||
import ParticipantListWithExcludedUserExampleText from '!!raw-loader!./snippets/WithExcludedUser.snippet.tsx'; | ||
|
||
<Meta of={ParticipantStories} component={ParticipantList} /> | ||
|
||
# ParticipantList | ||
|
||
ParticipantList renders a list of all calling or chat participants. | ||
|
||
## Default example for Chat | ||
|
||
The ParticipantList for chat is by default a list of [ParticipantItem](./?path=/docs/ui-components-participantitem--participant-item) components linked with state around each chat participant. | ||
|
||
<Canvas of={ParticipantStories.DefaultChatParticipantListDocsOnly} source={{ code: DefaultChatParticipantListExampleText }} /> | ||
|
||
## Default example for Calling | ||
|
||
ParticipantList for calling is by default a list of [ParticipantItem](./?path=/docs/ui-components-participantitem--participant-item) components with presence linked to the participant call state, as well as icons for microphone and screen sharing states. | ||
|
||
<Canvas of={ParticipantStories.DefaultCallParticipantListDocsOnly} source={{ code: DefaultCallParticipantListExampleText }} /> | ||
|
||
## ParticipantList with local user excluded from the list | ||
|
||
Local user can be excluded from the participant list as shown in the example below. | ||
|
||
<Canvas of={ParticipantStories.ParticipantListWithExcludedUserDocsOnly} source={{ code: ParticipantListWithExcludedUserExampleText }} /> | ||
|
||
## Interactive Call example | ||
|
||
ParticipantList is designed with a rendering override, `onRenderParticipant`, which allows you to have your own design or use your own [ParticipantItem](./?path=/docs/ui-components-participantitem--participant-item) components with their context menu style enabling interaction with this participant. For example, you can add menu items and icons to the participants using `menuItems` and `onRenderIcon` properties of [ParticipantItem](./?path=/docs/ui-components-participantitem--participant-item#props) like in the code below. | ||
|
||
For simplicity, React `useState` is used to keep the state of every participant to decide which menu items and icons to show. You can now mute and unmute by clicking a participant in the rendered example below. | ||
|
||
Note: Each `ParticipantItem` needs a unique key to avoid warnings for children in a list. | ||
|
||
<Canvas of={ParticipantStories.InteractiveCallParticipantListDocsOnly} source={{ code: InteractiveCallParticipantListExampleText }} /> | ||
|
||
## Props | ||
|
||
tbd.. |
41 changes: 41 additions & 0 deletions
41
packages/storybook8/stories/Components/ParticipantList/ParticipantList.story.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
|
||
import { ParticipantList as ParticipantListComponent, ParticipantListParticipant } from '@azure/communication-react'; | ||
import { Stack } from '@fluentui/react'; | ||
import React from 'react'; | ||
|
||
const ParticipantListStory: (args) => JSX.Element = (args) => { | ||
const participantsControls = [...args.remoteParticipants, ...args.localParticipant]; | ||
|
||
const mockParticipants: ParticipantListParticipant[] = participantsControls.map((p, i) => { | ||
return { | ||
userId: `userId ${i}`, | ||
displayName: p.name, | ||
state: p.status, | ||
isMuted: p.isMuted, | ||
isScreenSharing: p.isScreenSharing, | ||
isRemovable: true | ||
}; | ||
}); | ||
|
||
const myUserId = mockParticipants[mockParticipants.length - 1].userId; | ||
|
||
// eslint-disable-next-line @typescript-eslint/no-unused-vars | ||
const onParticipantRemove = (_userId: string): void => { | ||
// Do something when remove a participant from list | ||
}; | ||
|
||
return ( | ||
<Stack> | ||
<ParticipantListComponent | ||
participants={mockParticipants} | ||
myUserId={myUserId} | ||
excludeMe={args.excludeMe} | ||
onRemoveParticipant={onParticipantRemove} | ||
/> | ||
</Stack> | ||
); | ||
}; | ||
|
||
export const ParticipantList = ParticipantListStory.bind({}); |
53 changes: 53 additions & 0 deletions
53
packages/storybook8/stories/Components/ParticipantList/index.stories.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
// Copyright (c) Microsoft Corporation. | ||
// Licensed under the MIT License. | ||
|
||
import { ParticipantList as ParticipantListComponent } from '@azure/communication-react'; | ||
import { Meta } from '@storybook/react'; | ||
import { controlsToAdd, defaultLocalParticipant, defaultRemoteParticipants, hiddenControl } from '../../controlsUtils'; | ||
import { DefaultCallParticipantListExample } from './snippets/DefaultCall.snippet'; | ||
import { DefaultChatParticipantListExample } from './snippets/DefaultChat.snippet'; | ||
import { InteractiveCallParticipantListExample } from './snippets/InteractiveCall.snippet'; | ||
import { ParticipantListWithExcludedUserExample } from './snippets/WithExcludedUser.snippet'; | ||
export { ParticipantList } from './ParticipantList.story'; | ||
|
||
export const DefaultCallParticipantListDocsOnly = { | ||
render: DefaultCallParticipantListExample | ||
}; | ||
|
||
export const DefaultChatParticipantListDocsOnly = { | ||
render: DefaultChatParticipantListExample | ||
}; | ||
|
||
export const InteractiveCallParticipantListDocsOnly = { | ||
render: InteractiveCallParticipantListExample | ||
}; | ||
|
||
export const ParticipantListWithExcludedUserDocsOnly = { | ||
render: ParticipantListWithExcludedUserExample | ||
}; | ||
|
||
const meta: Meta = { | ||
title: 'Components/Participant List', | ||
component: ParticipantListComponent, | ||
argTypes: { | ||
excludeMe: controlsToAdd.excludeMeFromList, | ||
localParticipant: controlsToAdd.localParticipant, | ||
remoteParticipants: controlsToAdd.remoteParticipants, | ||
// Hiding auto-generated controls | ||
participants: hiddenControl, | ||
myUserId: hiddenControl, | ||
onRenderParticipant: hiddenControl, | ||
onRenderAvatar: hiddenControl, | ||
onParticipantRemove: hiddenControl, | ||
onRemoveParticipant: hiddenControl, | ||
onFetchParticipantMenuItems: hiddenControl, | ||
styles: hiddenControl | ||
}, | ||
args: { | ||
excludeMe: false, | ||
localParticipant: defaultLocalParticipant, | ||
remoteParticipants: defaultRemoteParticipants | ||
} | ||
} as Meta; | ||
|
||
export default meta; |
50 changes: 50 additions & 0 deletions
50
packages/storybook8/stories/Components/ParticipantList/snippets/DefaultCall.snippet.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
import { CallParticipantListParticipant, FluentThemeProvider, ParticipantList } from '@azure/communication-react'; | ||
import { Stack } from '@fluentui/react'; | ||
import React from 'react'; | ||
|
||
export const DefaultCallParticipantListExample: () => JSX.Element = () => { | ||
const mockParticipants: CallParticipantListParticipant[] = [ | ||
{ | ||
userId: 'user1', | ||
displayName: 'You', | ||
state: 'Connected', | ||
isMuted: true, | ||
isScreenSharing: false, | ||
isRemovable: true | ||
}, | ||
{ | ||
userId: 'user2', | ||
displayName: 'Hal Jordan', | ||
state: 'Connected', | ||
isMuted: true, | ||
isScreenSharing: true, | ||
isRemovable: true | ||
}, | ||
{ | ||
userId: 'user3', | ||
displayName: 'Barry Allen', | ||
state: 'Idle', | ||
isMuted: false, | ||
isScreenSharing: false, | ||
isRemovable: true, | ||
raisedHand: { raisedHandOrderPosition: 1 } | ||
}, | ||
{ | ||
userId: 'user4', | ||
displayName: 'Bruce Wayne', | ||
state: 'Connecting', | ||
isMuted: false, | ||
isScreenSharing: false, | ||
isRemovable: false | ||
} | ||
]; | ||
|
||
return ( | ||
<FluentThemeProvider> | ||
<Stack> | ||
<div style={{ fontSize: '1.5rem', marginBottom: '1rem', fontFamily: 'Segoe UI' }}>Participants</div> | ||
<ParticipantList participants={mockParticipants} myUserId={'user1'} /> | ||
</Stack> | ||
</FluentThemeProvider> | ||
); | ||
}; |
35 changes: 35 additions & 0 deletions
35
packages/storybook8/stories/Components/ParticipantList/snippets/DefaultChat.snippet.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { ParticipantListParticipant, ParticipantList } from '@azure/communication-react'; | ||
import { Stack } from '@fluentui/react'; | ||
import React from 'react'; | ||
|
||
export const DefaultChatParticipantListExample: () => JSX.Element = () => { | ||
const mockParticipants: ParticipantListParticipant[] = [ | ||
{ | ||
userId: 'user 1', | ||
displayName: 'You', | ||
isRemovable: true | ||
}, | ||
{ | ||
userId: 'user 2', | ||
displayName: 'Hal Jordan', | ||
isRemovable: true | ||
}, | ||
{ | ||
userId: 'user 3', | ||
displayName: 'Barry Allen', | ||
isRemovable: true | ||
}, | ||
{ | ||
userId: 'user 4', | ||
displayName: 'Bruce Wayne', | ||
isRemovable: true | ||
} | ||
]; | ||
|
||
return ( | ||
<Stack> | ||
<div style={{ fontSize: '1.5rem', marginBottom: '1rem', fontFamily: 'Segoe UI' }}>Participants</div> | ||
<ParticipantList participants={mockParticipants} /> | ||
</Stack> | ||
); | ||
}; |
103 changes: 103 additions & 0 deletions
103
packages/storybook8/stories/Components/ParticipantList/snippets/InteractiveCall.snippet.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,103 @@ | ||
import { | ||
CallParticipantListParticipant, | ||
FluentThemeProvider, | ||
ParticipantList, | ||
ParticipantItem, | ||
ParticipantListParticipant | ||
} from '@azure/communication-react'; | ||
import { Icon, IContextualMenuItem, PersonaPresence, Stack } from '@fluentui/react'; | ||
import React, { useState } from 'react'; | ||
|
||
const mockParticipants: CallParticipantListParticipant[] = [ | ||
{ | ||
userId: 'user1', | ||
displayName: 'You', | ||
state: 'Connected', | ||
isMuted: true, | ||
isRemovable: true | ||
}, | ||
{ | ||
userId: 'user2', | ||
displayName: 'Peter Parker', | ||
state: 'Connected', | ||
isMuted: false, | ||
isRemovable: true | ||
}, | ||
{ | ||
userId: 'user3', | ||
displayName: 'Matthew Murdock', | ||
state: 'Idle', | ||
isMuted: false, | ||
isRemovable: true | ||
}, | ||
{ | ||
userId: 'user4', | ||
displayName: 'Frank Castiglione', | ||
state: 'Connecting', | ||
isMuted: false, | ||
isRemovable: false | ||
} | ||
]; | ||
|
||
export const InteractiveCallParticipantListExample: () => JSX.Element = () => { | ||
const [participants, setParticpants] = useState<any[]>(mockParticipants); | ||
|
||
const mockMyUserId = 'user1'; | ||
|
||
const onRenderParticipant = (participant: ParticipantListParticipant): JSX.Element => { | ||
const participantIndex = participants.map((p) => p.userId).indexOf(participant.userId); | ||
|
||
const callingParticipant = participants[participantIndex] as CallParticipantListParticipant; | ||
|
||
let presence: PersonaPresence | undefined = undefined; | ||
if (callingParticipant) { | ||
if (callingParticipant.state === 'Connected') { | ||
presence = PersonaPresence.online; | ||
} else if (callingParticipant.state === 'Idle') { | ||
presence = PersonaPresence.away; | ||
} else if (callingParticipant.state === 'Connecting') { | ||
presence = PersonaPresence.offline; | ||
} | ||
} | ||
|
||
const menuItems: IContextualMenuItem[] = [ | ||
{ | ||
key: 'mute', | ||
text: callingParticipant.isMuted ? 'Unmute' : 'Mute', | ||
onClick: () => { | ||
const newParticipants = [...participants]; | ||
newParticipants[participantIndex].isMuted = !participants[participantIndex].isMuted; | ||
setParticpants(newParticipants); | ||
} | ||
} | ||
]; | ||
|
||
const onRenderIcon = callingParticipant?.isMuted ? () => <Icon iconName="MicOff2" /> : () => <></>; | ||
|
||
if (participant.displayName) { | ||
return ( | ||
<ParticipantItem | ||
displayName={participant.displayName} | ||
me={participant.userId === mockMyUserId} | ||
menuItems={menuItems} | ||
presence={presence} | ||
onRenderIcon={onRenderIcon} | ||
/> | ||
); | ||
} | ||
return <></>; | ||
}; | ||
|
||
return ( | ||
<FluentThemeProvider> | ||
<Stack> | ||
<div style={{ fontSize: '1.5rem', marginBottom: '1rem', fontFamily: 'Segoe UI' }}>Participants</div> | ||
<ParticipantList | ||
participants={participants} | ||
myUserId={mockMyUserId} | ||
onRenderParticipant={onRenderParticipant} | ||
/> | ||
</Stack> | ||
</FluentThemeProvider> | ||
); | ||
}; |
49 changes: 49 additions & 0 deletions
49
packages/storybook8/stories/Components/ParticipantList/snippets/WithExcludedUser.snippet.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import { CallParticipantListParticipant, FluentThemeProvider, ParticipantList } from '@azure/communication-react'; | ||
import { Stack } from '@fluentui/react'; | ||
import React from 'react'; | ||
|
||
const mockParticipants: CallParticipantListParticipant[] = [ | ||
{ | ||
userId: 'user1', | ||
displayName: 'You', | ||
state: 'Connected', | ||
isMuted: true, | ||
isScreenSharing: false, | ||
isRemovable: true | ||
}, | ||
{ | ||
userId: 'user2', | ||
displayName: 'Hal Jordan', | ||
state: 'Connected', | ||
isMuted: true, | ||
isScreenSharing: true, | ||
isRemovable: true | ||
}, | ||
{ | ||
userId: 'user3', | ||
displayName: 'Barry Allen', | ||
state: 'Idle', | ||
isMuted: false, | ||
isScreenSharing: false, | ||
isRemovable: true | ||
}, | ||
{ | ||
userId: 'user4', | ||
displayName: 'Bruce Wayne', | ||
state: 'Connecting', | ||
isMuted: false, | ||
isScreenSharing: false, | ||
isRemovable: false | ||
} | ||
]; | ||
|
||
export const ParticipantListWithExcludedUserExample: () => JSX.Element = () => { | ||
return ( | ||
<FluentThemeProvider> | ||
<Stack> | ||
<div style={{ fontSize: '1.5rem', marginBottom: '1rem', fontFamily: 'Segoe UI' }}>Participants</div> | ||
<ParticipantList participants={mockParticipants} myUserId={'user1'} excludeMe={true} /> | ||
</Stack> | ||
</FluentThemeProvider> | ||
); | ||
}; |
Oops, something went wrong.