@mui/material#PaletteColor TypeScript Examples

The following examples show how to use @mui/material#PaletteColor. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: Message.tsx    From airmessage-web with Apache License 2.0 4 votes vote down vote up
export default function Message(props: Props) {
	//State
	const [attachmentDataArray, setAttachmentDataArray] = useState<FileDownloadResult[]>([]);
	const [dialogOpen, setDialogOpen] = useState<"error" | "rawError" | undefined>(undefined);
	
	function closeDialog() {
		setDialogOpen(undefined);
	}
	function openDialogError() {
		setDialogOpen("error");
	}
	function openDialogRawError() {
		setDialogOpen("rawError");
	}
	function copyRawErrorAndClose() {
		navigator.clipboard.writeText(props.message.error!.detail!);
		closeDialog();
	}
	
	//Getting the message information
	const isOutgoing = props.message.sender === undefined;
	const displayAvatar = !isOutgoing && !props.flow.anchorTop;
	const displaySender = props.isGroupChat && displayAvatar;
	const messageConfirmed = props.message.status !== MessageStatusCode.Unconfirmed;
	
	//Building the message style
	const theme = useTheme();
	let colorPalette: PaletteColor;
	if(isOutgoing) {
		if(props.service === appleServiceAppleMessage) colorPalette = theme.palette.messageOutgoing;
		else colorPalette = theme.palette.messageOutgoingTextMessage;
	} else {
		colorPalette = theme.palette.messageIncoming;
	}
	const messagePartPropsBase: Partial<MessagePartProps> = {
		alignSelf: isOutgoing ? "flex-end" : "flex-start",
		color: colorPalette.contrastText,
		backgroundColor: colorPalette.main,
		opacity: messageConfirmed ? opacityConfirmed : opacityUnconfirmed
	};
	
	//Splitting the modifiers for each message part
	const stickerGroups = props.message.stickers.reduce((accumulator: {[index: number]: StickerItem[]}, item: StickerItem) => {
		if(accumulator[item.messageIndex]) accumulator[item.messageIndex].push(item);
		else accumulator[item.messageIndex] = [item];
		return accumulator;
	}, {});
	const tapbackGroups = props.message.tapbacks.reduce((accumulator: {[index: number]: TapbackItem[]}, item: TapbackItem) => {
		if(accumulator[item.messageIndex]) accumulator[item.messageIndex].push(item);
		else accumulator[item.messageIndex] = [item];
		return accumulator;
	}, {});
	
	//Adding the message text
	const components: React.ReactNode[] = [];
	if(props.message.text) {
		const partProps: MessagePartProps = {
			...messagePartPropsBase,
			borderRadius: getBorderRadius(props.flow.anchorTop, props.flow.anchorBottom || props.message.attachments.length > 0, isOutgoing),
			marginTop: 0
		} as MessagePartProps;
		
		const component = <MessageBubble key="messagetext" text={props.message.text!} index={0} partProps={partProps} stickers={stickerGroups[0]} tapbacks={tapbackGroups[0]} />;
		
		components.push(component);
	}
	
	function onAttachmentData(attachmentIndex: number, shouldDownload: boolean, result: FileDownloadResult) {
		if(shouldDownload) {
			//Downloading the file
			const attachment = props.message.attachments[attachmentIndex];
			downloadArrayBuffer(result.data, result.downloadType ?? attachment.type, result.downloadName ?? attachment.name);
		} else {
			//Updating the data
			const newArray = [...attachmentDataArray];
			newArray[attachmentIndex] = result;
			setAttachmentDataArray(newArray);
		}
	}
	
	function downloadData(attachmentIndex: number, data: ArrayBuffer | Blob) {
		const attachment = props.message.attachments[attachmentIndex];
		if(data instanceof ArrayBuffer) {
			downloadArrayBuffer(data, attachment.type, attachment.name);
		} else {
			downloadBlob(data, attachment.type, attachment.name);
		}
	}
	
	/**
	 * Computes the file data to display to the user
	 */
	const getComputedFileData = useCallback((attachmentIndex: number): FileDisplayResult => {
		const attachment = props.message.attachments[attachmentIndex];
		const downloadData = attachmentDataArray[attachmentIndex];
		
		if(downloadData === undefined) {
			return {
				data: attachment.data,
				name: attachment.name,
				type: attachment.type
			};
		} else return {
			data: downloadData.data,
			name: downloadData.downloadName ?? attachment.name,
			type: downloadData.downloadType ?? attachment.type
		};
	}, [props.message.attachments, attachmentDataArray]);
	
	//Adding the attachments
	for(let i = 0; i < props.message.attachments.length; i++) {
		const index = props.message.text ? i + 1 : i;
		const attachment = props.message.attachments[i];
		
		const partProps: MessagePartProps = {
			...messagePartPropsBase,
			borderRadius: getBorderRadius(props.flow.anchorTop || index > 0, props.flow.anchorBottom || i + 1 < props.message.attachments.length, isOutgoing),
			marginTop: index > 0 ? marginLinked : undefined
		} as MessagePartProps;
		
		//Checking if the attachment has data
		const attachmentData = getComputedFileData(i);
		if(attachmentData.data !== undefined && isAttachmentPreviewable(attachmentData.type)) {
			//Custom background color
			const imagePartProps = {
				...partProps,
				backgroundColor: theme.palette.background.sidebar,
			};
			
			if(attachmentData.type.startsWith("image/")) {
				components.push(<MessageAttachmentImage key={attachment.guid ?? attachment.localID} data={attachmentData.data} name={attachmentData.name} type={attachmentData.type} partProps={imagePartProps} stickers={stickerGroups[index]} tapbacks={tapbackGroups[index]} />);
			}
		} else {
			//Adding a generic download attachment
			components.push(<MessageAttachmentDownloadable
				key={attachment.guid ?? attachment.localID}
				data={attachmentData.data}
				name={attachmentData.name}
				type={attachmentData.type}
				size={attachment.size}
				guid={attachment.guid!}
				onDataAvailable={(data) => onAttachmentData(i, !isAttachmentPreviewable(data.downloadType ?? attachment.type), data)}
				onDataClicked={(data) => downloadData(i, data)}
				partProps={partProps}
				stickers={stickerGroups[index]}
				tapbacks={tapbackGroups[index]} />);
		}
	}
	
	const messageStyle: CSSProperties = {
		marginTop: props.flow.anchorTop ? marginLinked : marginUnlinked,
	};
	
	//Initializing state
	const [personData, setPersonData] = useState<PersonData | undefined>();
	useEffect(() => {
		if(!props.message.sender) return;
		
		//Requesting contact data
		findPerson(props.message.sender).then(setPersonData, console.warn);
	}, [props.message.sender]);
	
	//Building and returning the component
	return (
		<div className={styles.message} style={messageStyle}>
			{props.flow.showDivider && <Typography className={styles.separator} variant="body2" color="textSecondary">{getTimeDivider(props.message.date)}</Typography>}
			{displaySender && <Typography className={styles.labelSender} variant="caption" color="textSecondary">{personData?.name ?? props.message.sender}</Typography>}
			<div className={styles.messageSplit}>
				{<Avatar className={styles.avatar} src={personData?.avatar} style={displayAvatar ? {visibility: "visible", backgroundColor: colorFromContact(props.message.sender ?? "")} : {visibility: "hidden"}} />}
				<div className={styles.messageParts}>
					{components}
				</div>
				{props.message.progress && !props.message.error && <CircularProgress className={styles.messageProgress} size={24} variant={props.message.progress === -1 ? "indeterminate" : "determinate"} value={props.message.progress} />}
				{props.message.error && <IconButton className={styles.messageError} style={{color: theme.palette.error.light}} size="small" onClick={openDialogError}>
					<ErrorRounded />
				</IconButton>}
				<Dialog open={dialogOpen === "error"} onClose={closeDialog}>
					<DialogTitle>Your message could not be sent</DialogTitle>
					{props.message.error !== undefined && <React.Fragment>
						<DialogContent>
							<DialogContentText>{messageErrorToUserString(props.message.error!.code)}</DialogContentText>
						</DialogContent>
						<DialogActions>
							{props.message.error!.detail && <Button onClick={openDialogRawError} color="primary">
								Error details
							</Button>}
							<Button onClick={closeDialog} color="primary" autoFocus>
								Dismiss
							</Button>
						</DialogActions>
					</React.Fragment>}
				</Dialog>
				<Dialog open={dialogOpen === "rawError"} onClose={closeDialog}>
					<DialogTitle>Error details</DialogTitle>
					{props.message.error !== undefined && <React.Fragment>
						<DialogContent>
							<DialogContentText className={styles.rawErrorText}>{props.message.error.detail!}</DialogContentText>
						</DialogContent>
						<DialogActions>
							<Button onClick={copyRawErrorAndClose} color="primary">
								Copy to clipboard
							</Button>
							<Button onClick={closeDialog} color="primary" autoFocus>
								Dismiss
							</Button>
						</DialogActions>
					</React.Fragment>}
				</Dialog>
			</div>
			{props.showStatus && <Typography className={styles.labelStatus} variant="caption" color="textSecondary">{getStatusString(props.message)}</Typography>}
		</div>
	);
}