Goal
Add AEM SPA React Alert component showing a banner created using Material UI (MUI) at the top of page. Using MUI there are no global style-sheets, each component is independent and there are no css conflicts at page level. Responsive page layout is created using AEM Grid...
Thank you Joe Ritchie and team...
Demo | Package Install | Github
Banner (View as Published)
Component Dialog in Template
mvn -B archetype:generate -D archetypeGroupId=com.adobe.granite.archetypes -D archetypeArtifactId=aem-project-archetype
-D archetypeVersion=23 -D aemVersion=6.5.0 -D appTitle="Experience AEM SPA React" -D appId="eaem-sites-spa-how-to-react" -D groupId="com.eaem"
-D frontendModule=react -D includeExamples=n -D includeErrorHandler=n -D includeDispatcherConfig=n
3) Open a command prompt (terminal) at eaem-sites-react-spa-material-ui-banner\ui.frontend and install the typscript and material ui specific dependencies
5) Add the component render script in eaemeaem-sites-react-spa-material-ui-banner\ui.frontend\src\components\Alert\EAEMAlert.tsx with the following code...
import { MapTo } from "@adobe/cq-react-editable-components";
import React, { FC, useState, useEffect } from "react";
import { Link } from "react-router-dom";
import {
IconButton,
Typography,
createStyles,
makeStyles,
Theme,
Portal,
SvgIcon,
SvgIconProps,
Collapse
} from "@material-ui/core";
import CSS from "csstype";
import classNames from "classnames";
const iconStyles = makeStyles(() =>
createStyles({
root: {
fontSize: 20
}
})
);
const EAEMCloseIcon: FC<SvgIconProps> = props => {
const classes = iconStyles();
return (
<SvgIcon
viewBox="0 0 20 20"
{...props}
className={classNames(classes.root, props.className)}
>
<title>Combined Shape</title>
<desc>Created with Sketch.</desc>
<g
id="Symbols"
stroke="none"
strokeWidth="1"
fill="none"
fillRule="evenodd"
>
<g id="Grommet/X-Close" transform="translate(-15.000000, -15.000000)">
<rect id="Rectangle" x="0" y="0" width="50" height="50"></rect>
<path
d="M34.3548387,15 L35,15.6451613 L25.645,24.999 L35,34.3548387 L34.3548387,35 L25,25.645 L15.6451613,35 L15,34.3548387 L24.354,25 L15,15.6451613 L15.6451613,15 L25,24.354 L34.3548387,15 Z"
id="Combined-Shape"
fill="currentColor"
></path>
</g>
</g>
</SvgIcon>
);
};
type AlertProps = {
showAlert: string;
text: string;
linkURL: string;
};
const AlertEditConfig = {
emptyLabel: "Alert - Shows banner at the top of page",
isEmpty: function (props: any) {
return !props || !props.text || props.text.trim().length < 1;
}
};
const useStyles = makeStyles((theme: Theme) =>
createStyles({
closeIcon: {
fontSize: 12,
color: "white",
[theme.breakpoints.up("sm")]: {
fontSize: 16
}
},
container: {
alignItems: "center",
background: "black",
display: "flex"
},
content: {
color: "white",
paddingTop: "15px",
paddingBottom: "15px",
flex: "1 1",
fontFamily: 'Times, serif',
fontSize: 16,
textAlign: "center"
}
})
);
const EAEMAlert: FC<AlertProps> = props => {
const classes = useStyles();
const [open, setOpen] = useState(true);
const [root, setRoot] = useState<HTMLElement | null>(null);
useEffect(() => {
setRoot(document.getElementById("eaem-alert-banner"));
}, [root]);
const handleClose = () => {
setOpen(false);
};
if (!props.text || props.showAlert != "true") {
return null;
}
let text = props.text.trim();
if (text.startsWith("<p>") && text.endsWith("</p>")) {
text = text.substring(3, text.lastIndexOf("</p>"));
}
return (
<Portal container={root}>
<Collapse in={open}>
<Typography className={classes.container} component={"div"}>
<div
className={classes.content}
dangerouslySetInnerHTML={{ __html: text }}
/>
<IconButton onClick={handleClose}>
<EAEMCloseIcon className={classes.closeIcon} />
</IconButton>
</Typography>
</Collapse>
</Portal>
);
};
export default MapTo("eaem-sites-spa-how-to-react/components/alert")(EAEMAlert, AlertEditConfig);
6) Add the EAEMAlert.tsx path in eaem-sites-react-spa-material-ui-banner\ui.frontend\src\components\import-components.js