AEM 6560 - React SPA Text component with Material UI Theme and Styles

Goal

Add AEM SPA React Text component showing paragraph texts created using Typescript and Material UI (MUI). Using MUI there are no global style-sheets, each component is independent, so there are no css conflicts at page level polluting global scope. In the following steps a MUI theme created with device specific breakpoints shows AdobeCaslonPro font and device specific font sizes...

Package Install | Github


Typography in Sketch File (opened using Windows Lunacy App)



Typography in AEM


Solution


1) Create the project structure (for both React SPA and MPA authoring) with the following command using maven archetype - https://github.com/adobe/aem-project-archetype

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-react-spa-material-ui-text"  -D groupId="com.eaem"  
-D frontendModule=react  -D includeExamples=n  -D includeErrorHandler=n -D includeDispatcherConfig=n

2) Remove all additional components created, except the following required for testing... (or download Package Install)

                                                          /apps/eaem-sites-react-spa-material-ui-text/components/spa
                                                          /apps/eaem-sites-react-spa-material-ui-text/components/page
                                                          /apps/eaem-sites-react-spa-material-ui-text/components/text

3) Open a command prompt (terminal) at eaem-sites-react-spa-material-ui-text\ui.frontend and install the typscript and material ui specific dependencies

                                                          npm install typescript
                                                          npm install @material-ui/core
                                                          npm install classnames

4) Create the component /apps/eaem-sites-react-spa-material-ui-text/components/text. In the next step we'd be creating the react render type script...

5) Add the component render script in eaem-sites-react-spa-material-ui-text\ui.frontend\src\components\AEMText\AEMText.tsx with the following code...

import { MapTo } from "@adobe/cq-react-editable-components";
import React, { FC, useState, useEffect } from "react";
import {
  makeStyles, Theme, createStyles
} from "@material-ui/core";
import { createMuiTheme } from "@material-ui/core/styles";
import createBreakpoints from "@material-ui/core/styles/createBreakpoints";

type TextProps = {
  cqPath: string;
  text: string;
};

const AEMTextEditConfig = {
  emptyLabel: "Text - Experience AEM",

  isEmpty: function (props: any) {
    return !props || !props.text || props.text.trim().length < 1;
  }
};

function extractModelId(path: string) {
  return path && path.replace(/\/|:/g, "_");
}

enum BREAKPOINTS {
  XS = 0,
  SM = 768,
  MD = 992,
  LG = 1200,
  XL = 1600
}

const eaemTheme = createMuiTheme({
  breakpoints: createBreakpoints({
    values: {
      xs: BREAKPOINTS.XS,
      sm: BREAKPOINTS.SM,
      md: BREAKPOINTS.MD,
      lg: BREAKPOINTS.LG,
      xl: BREAKPOINTS.XL
    },
    get down() {
      return (key : number | string) => {
        let values = this.values as any;
        return `@media (max-width: ${values[key]- 0.05}px)`;
      }
    },
    get between() {
      return (a : number | string, b : number | string) => {
        let values = this.values as any;
        return `@media (min-width:${values[a]}px) and (max-width:${values[b] - 0.05}px)`;
      }
    }
  })
});

const useStyles = makeStyles(() => {
  console.log(eaemTheme.breakpoints.up("md"));

  return createStyles({
    root: {
      fontFamily: 'AdobeCaslonPro, Times, serif !important',
      '& h1': {
        [eaemTheme.breakpoints.down("xl")]: {
          fontSize: '34px',
        },
        [eaemTheme.breakpoints.down("lg")]: {
          fontSize: '30px',
        },
        [eaemTheme.breakpoints.down("md")]: {
          fontSize: '26px',
        }
      },
      '& h2': {
        [eaemTheme.breakpoints.down("xl")]: {
          fontSize: '28px',
        },
        [eaemTheme.breakpoints.down("lg")]: {
          fontSize: '25px',
        },
        [eaemTheme.breakpoints.down("md")]: {
          fontSize: '22px',
        }
      },
      '& h3': {
        [eaemTheme.breakpoints.down("xl")]: {
          fontSize: '22px',
        },
        [eaemTheme.breakpoints.down("lg")]: {
          fontSize: '20px',
        },
        [eaemTheme.breakpoints.down("md")]: {
          fontSize: '18px',
        }
      },
      '& p': {
        fontSize: '13px',
      },
      "& a:hover": {
        textDecoration: "none"
      }
    }
  })
});

const AEMText: FC<TextProps> = props => {
  const classes = useStyles();

  return (
    <div
      className={classes.root}
      id={extractModelId(props.cqPath)}
      data-rte-editelement
      dangerouslySetInnerHTML={{
        __html: props.text
      }}
    />
  );
};

export default MapTo("eaem-sites-spa-how-to-react/components/text")(AEMText, AEMTextEditConfig);

6) Add AEMText.tsx path in eaem-sites-react-spa-material-ui-text\ui.frontend\src\components\import-components.js

                                                          import './Page/Page';
                                                          import './AEMText/AEMText';
                                                          import './Title/Title';
                                                          import './Nav/Nav';
                                                          import './Image/Image';

1 comment: