Skip to content

Commit

Permalink
Customize icon and avatar examples in SendBox and ParticipantItem docs (
Browse files Browse the repository at this point in the history
#95)

* added customize icon and avatar examples in SendBox and ParticipantItem docs

* updated api.md

* added changelog

* using sharepoint image as custom avatar example

* exporting SendBoxProps

* fixed component name in docs

* updated api.md
  • Loading branch information
mgamis-msft authored Mar 26, 2021
1 parent 057f39c commit cbb60d5
Show file tree
Hide file tree
Showing 8 changed files with 219 additions and 58 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
"type": "prerelease",
"comment": "Added examples for icon and avatar customization for ParticipantItem and SendBox in storybook docs.",
"packageName": "@azure/communication-ui",
"email": "[email protected]",
"dependentChangeType": "patch"
}
19 changes: 11 additions & 8 deletions packages/communication-ui/review/communication-ui.api.md
Original file line number Diff line number Diff line change
Expand Up @@ -222,7 +222,7 @@ export type ChatThreadProps = {
disableLoadPreviousMessage?: boolean;
disableReadReceipt?: boolean;
onSendReadReceipt?: () => Promise<void>;
onRenderReadReceipt?: (readReceiptProps: ReadReceiptProps) => JSX.Element;
onRenderReadReceipt?: (readReceiptProps: ReadReceiptProps) => JSX.Element | null;
onRenderAvatar?: (userId: string) => JSX.Element;
onRenderJumpToNewMessageButton?: (newMessageButtonProps: JumpToNewMessageButtonProps) => JSX.Element;
onLoadPreviousMessages?: () => void;
Expand Down Expand Up @@ -803,14 +803,14 @@ export const PAGE_SIZE = 200;
export const ParticipantItem: (props: ParticipantItemProps & ErrorHandlingProps) => JSX.Element;

// @public
export type ParticipantItemProps = {
name: string;
export interface ParticipantItemProps {
isYou?: boolean;
onRenderAvatar?: (props?: ParticipantItemProps) => JSX.Element | null;
menuItems?: IContextualMenuItem[];
name: string;
onRenderAvatar?: (props?: ParticipantItemProps) => JSX.Element | null;
onRenderIcon?: (props?: ParticipantItemProps) => JSX.Element | null;
presence?: PersonaPresence;
};
}

// @public (undocumented)
export const PARTICIPANTS_THRESHOLD = 20;
Expand Down Expand Up @@ -864,10 +864,9 @@ export const screenShareButtonProps: IButtonProps;
export const SendBox: (props: Pick<{
onRenderSystemMessage?: ((systemMessage: string | undefined) => React_2.ReactElement<any, string | ((props: any) => React_2.ReactElement<any, any> | null) | (new (props: any) => React_2.Component<any, any, any>)>) | undefined;
supportNewline?: boolean | undefined;
} & SendBoxPropsFromContext & ErrorHandlingProps, "onErrorCallback" | "supportNewline" | "onRenderSystemMessage">) => React_2.ReactElement<any, string | ((props: any) => React_2.ReactElement<any, any> | null) | (new (props: any) => React_2.Component<any, any, any>)>;
onRenderIcon?: ((props: SendBoxProps) => JSX.Element | null) | undefined;
} & SendBoxPropsFromContext & ErrorHandlingProps, "onErrorCallback" | "supportNewline" | "onRenderIcon" | "onRenderSystemMessage">) => React_2.ReactElement<any, string | ((props: any) => React_2.ReactElement<any, any> | null) | (new (props: any) => React_2.Component<any, any, any>)>;

// Warning: (ae-forgotten-export) The symbol "SendBoxProps" needs to be exported by the entry point index.d.ts
//
// @public (undocumented)
export const SendBoxComponent: (props: SendBoxProps & ErrorHandlingProps) => JSX.Element;

Expand Down Expand Up @@ -1264,6 +1263,10 @@ export interface VideoTileStylesProps {
export const WithErrorHandling: (Component: (props: any & ErrorHandlingProps) => JSX.Element, props: any & ErrorHandlingProps) => JSX.Element;


// Warnings were encountered during analysis:
//
// src/components/SendBox.tsx:31:3 - (ae-forgotten-export) The symbol "SendBoxProps" needs to be exported by the entry point index.d.ts

// (No @packageDocumentation comment for this package)

```
2 changes: 1 addition & 1 deletion packages/communication-ui/src/components/ChatThread.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ export type ChatThreadProps = {
/**
* onRenderReadReceipt event handler. `(readReceiptProps: ReadReceiptProps) => JSX.Element`
*/
onRenderReadReceipt?: (readReceiptProps: ReadReceiptProps) => JSX.Element;
onRenderReadReceipt?: (readReceiptProps: ReadReceiptProps) => JSX.Element | null;
/**
* onRenderAvatar event handler. `(userId: string) => JSX.Element`
*/
Expand Down
28 changes: 11 additions & 17 deletions packages/communication-ui/src/components/ParticipantItem.tsx
Original file line number Diff line number Diff line change
@@ -1,11 +1,6 @@
// © Microsoft Corporation. All rights reserved.

import {
memberItemContainerStyle,
memberItemIsYouStyle,
memberItemNameStyle,
iconsContainerStyle
} from './styles/ParticipantItem.styles';
import { memberItemContainerStyle, memberItemIsYouStyle, iconsContainerStyle } from './styles/ParticipantItem.styles';
import {
ContextualMenu,
DirectionalHint,
Expand All @@ -23,7 +18,7 @@ import { useTheme } from '@fluentui/react-theme-provider';
/**
* Props for ParticipantItem component
*/
export type ParticipantItemProps = {
export interface ParticipantItemProps {
/** Name of participant */
name: string;
/** Optional indicator to show participant is the user */
Expand All @@ -36,7 +31,7 @@ export type ParticipantItemProps = {
onRenderIcon?: (props?: ParticipantItemProps) => JSX.Element | null;
/** Optional PersonaPresence to show participant presence. This will not have an effect if property avatar is assigned */
presence?: PersonaPresence;
};
}

const ParticipantItemBase = (props: ParticipantItemProps & ErrorHandlingProps): JSX.Element => {
const { name, isYou, onRenderAvatar, menuItems, onRenderIcon, presence } = props;
Expand All @@ -55,20 +50,19 @@ const ParticipantItemBase = (props: ParticipantItemProps & ErrorHandlingProps):
setMenuHidden(true);
};

const avatarToUse = onRenderAvatar ? (
<div style={{ display: 'flex' }}>
{onRenderAvatar()}
<span className={memberItemNameStyle}>{name}</span>
</div>
) : (
<Persona text={name} size={PersonaSize.size32} presence={presence} />
const avatarToUse = (
<Persona
text={name}
size={PersonaSize.size32}
presence={presence}
onRenderPersonaCoin={onRenderAvatar ? () => onRenderAvatar(props) : undefined}
/>
);

return (
<div ref={containerRef} className={memberItemContainerStyle(theme)} onClick={showMenu}>
{avatarToUse}
{isYou && <span className={memberItemIsYouStyle}>(you)</span>}
{onRenderIcon && <Stack className={iconsContainerStyle}>{onRenderIcon()}</Stack>}
{onRenderIcon && <Stack className={iconsContainerStyle}>{onRenderIcon(props)}</Stack>}
{menuItems && (
<ContextualMenu
items={menuItems}
Expand Down
19 changes: 16 additions & 3 deletions packages/communication-ui/src/components/SendBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,26 @@ import { WithErrorHandling } from '../utils/WithErrorHandling';
import { ErrorHandlingProps } from '../providers/ErrorProvider';
import { propagateError } from '../utils/SDKUtils';

type SendBoxProps = {
/**
* Properties for component SendBox
*/
export type SendBoxProps = {
/** Optional callback to render system message below the SendBox */
onRenderSystemMessage?: (systemMessage: string | undefined) => React.ReactElement;
/** Optional boolean to support new line in SendBox */
supportNewline?: boolean;
/** Optional callback to render send button icon to the right of the SendBox*/
onRenderIcon?: (props: SendBoxProps & SendBoxPropsFromContext) => JSX.Element | null;
} & SendBoxPropsFromContext;

const defaultOnRenderSystemMessage = (systemMessage: string | undefined): JSX.Element | undefined =>
systemMessage ? <Alert attached="bottom" content={systemMessage} /> : undefined;

/**
* @description `SendBox` is a component for users to type and send messages. An optional message can also be
* added below the `SendBox`
* @param props - SendBoxProps
*/
const SendBoxComponentBase = (props: SendBoxProps & ErrorHandlingProps): JSX.Element => {
const {
disabled,
Expand All @@ -36,7 +48,8 @@ const SendBoxComponentBase = (props: SendBoxProps & ErrorHandlingProps): JSX.Ele
supportNewline: supportMultiline,
sendMessage,
onErrorCallback,
onSendTypingNotification
onSendTypingNotification,
onRenderIcon
} = props;

const [textValue, setTextValue] = useState('');
Expand Down Expand Up @@ -109,7 +122,7 @@ const SendBoxComponentBase = (props: SendBoxProps & ErrorHandlingProps): JSX.Ele
e.stopPropagation();
}}
>
<div className={sendIconDiv} />
{onRenderIcon ? onRenderIcon(props) : <div className={sendIconDiv} />}
</div>
</Stack>
{onRenderSystemMessage(systemMessage ? systemMessage : textTooLongMessage)}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,7 @@ export const memberItemIsYouStyle = mergeStyles({
fontSize: '0.875rem', // 14px
fontWeight: 400,
color: '#A19F9D',
marginTop: '0.3125rem',
marginLeft: '0.3125rem'
marginTop: '0.3125rem'
});

export const iconsContainerStyle = mergeStyles({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@

import React from 'react';
import { Title, Description, Props, Heading, Source, Canvas } from '@storybook/addon-docs/blocks';
import { ParticipantItem } from '../../components';
import { IContextualMenuItem, PersonaPresence } from '@fluentui/react';
import { ParticipantItem, ParticipantItemProps } from '../../components';
import { IContextualMenuItem, PersonaPresence, Icon } from '@fluentui/react';

const importStatement = `
import { ParticipantItem } from '@azure/communication-ui';
Expand Down Expand Up @@ -49,13 +49,90 @@ return (
);
`;

const CustomAvatarExample: () => JSX.Element = () => {
const onRenderAvatar = (): JSX.Element => {
return (
<img
src="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-react-assets/persona-female.png"
width="32px"
height="32px"
style={{
borderRadius: 20,
display: 'block'
}}
/>
);
};
return (
<div style={{ width: '200px' }}>
<ParticipantItem name="Annie Lindqvist" onRenderAvatar={onRenderAvatar} />
</div>
);
};

const customAvatarCode = `
const onRenderAvatar = (): JSX.Element => {
return (
<img
src="https://static2.sharepointonline.com/files/fabric/office-ui-fabric-react-assets/persona-female.png"
width="32px"
height="32px"
style={{
borderRadius: 20,
display: 'block'
}}
/>
);
};
<div style={{ width: '200px' }}>
<ParticipantItem name="Annie Lindqvist" onRenderAvatar={onRenderAvatar} />
</div>
`;

const CustomIconExample: () => JSX.Element = () => {
const onRenderIcon = (props?: ParticipantItemProps): JSX.Element | null => {
// eslint-disable-next-line react/prop-types
if (props?.name === 'Patrick') {
return <Icon iconName="FavoriteStar" />;
// eslint-disable-next-line react/prop-types
} else if (props?.isYou) {
return null;
}
return <Icon iconName="AddFriend" />;
};
return (
<div style={{ width: '200px' }}>
<ParticipantItem name="Spongebob" isYou={true} onRenderIcon={onRenderIcon} />
<ParticipantItem name="Patrick" onRenderIcon={onRenderIcon} />
<ParticipantItem name="Sandy" onRenderIcon={onRenderIcon} />
</div>
);
};

const customIconCode = `
const onRenderIcon = (props?: ParticipantItemProps): JSX.Element | null => {
if (props?.name === 'Patrick') {
return <Icon iconName="FavoriteStar" />;
} else if (props?.isYou) {
return null;
}
return <Icon iconName="AddFriend" />;
};
return (
<div style={{ width: '200px' }}>
<ParticipantItem name="Spongebob" isYou={true} onRenderIcon={onRenderIcon} />
<ParticipantItem name="Patrick" onRenderIcon={onRenderIcon} />
<ParticipantItem name="Sandy" onRenderIcon={onRenderIcon} />
</div>
);
`;

export const getDocs: () => JSX.Element = () => {
return (
<>
<Title>ParticipantStackItem</Title>
<Title>ParticipantItem</Title>
<Description>
The ParticipantStackItem component displays a user avatar, name, as well as presence, muted, and screenshare
state.
The ParticipantItem component represents a user and displays their avatar, name, status and additional icons.
</Description>
<Heading>Importing</Heading>
<Source code={importStatement} />
Expand All @@ -64,6 +141,19 @@ export const getDocs: () => JSX.Element = () => {
<ParticipantItemExample />
</Canvas>
<Source code={exampleCode} />
<Heading>Custom avatar</Heading>
To customize the avatar, use the onRenderAvatar property like in the example below. Note: the avatar element is
recommended to be within 32 by 32 pixels.
<Source code={customAvatarCode} />
<Canvas>
<CustomAvatarExample />
</Canvas>
<Heading>Add icon</Heading>
To add an icon, use the onRenderIcon property like in the example below.
<Source code={customIconCode} />
<Canvas>
<CustomIconExample />
</Canvas>
<Heading>Props</Heading>
<Props of={ParticipantItem} />
</>
Expand Down
Loading

0 comments on commit cbb60d5

Please sign in to comment.