typography.ts

/**
 * Typography.ts
 * This file defines all text styles for use throughout the application
 */

import {
  textSizes as bodySizes,
  headingSizes,
  lineHeights,
  letterSpacing,
} from '@/styles/Sizes';
import Colors from '@/styles/Colors';

/**
 * Reset the font styles to avoid unexpected styles on some browsers
 * And adds base font styles, that are applied globally to all app text
 */
export const TextReset = `
  font-family: "aktiv-grotesk", Helvetica, Arial, sans-serif;
  font-weight: 400;
  font-style: normal;
  font-stretch: normal;
  line-height: normal;
  letter-spacing: 0.38px;
  margin: 0;
  padding: 0;
  -webkit-font-smoothing: antialiased;
  -moz-osx-font-smoothing: grayscale;
`;

/**
 * Types relating to typography
 */
export type Alignment = 'left' | 'center' | 'right';
export type BodyTag = 'p' | 'span' | 'div' | 'li' | 'a';
export type HeadingTag = 'h1' | 'h2' | 'h3' | 'h4' | 'p';
export type BodyStyle = 'small' | 'medium' | 'tab' | 'subHeader';
export type HeadingSize = 'small' | 'medium' | 'large';

/**
 * Builds text sizes and spacings, based on specified theme/ style
 * @param style
 */
export const getTextSize = (style: BodyStyle = 'medium') =>
  ({
    small: `font-size: ${bodySizes.small}`,
    medium: `font-size: ${bodySizes.medium};
      line-height: ${lineHeights.medium};`,
    tab: `font-size: ${bodySizes.small};
      letter-spacing: ${letterSpacing.small}`,
    subHeader: `font-size: ${bodySizes.small};
      line-height: ${lineHeights.large};
      letter-spacing: ${letterSpacing.small};`,
  }[style]);

/**
 * Styles used for body Text (p, a, li, label etc)
 * @param style
 * @param color
 * @param align
 */
export const getBodyStyles = (
  style: BodyStyle = 'medium',
  color: Colors = Colors.darkGrey,
  align: Alignment = 'left',
  inline: boolean = false,
) => `
  ${TextReset}
  ${getTextSize(style)};
  color: ${color || 'inherit'};
  text-align: ${align || 'inherit'};
  display: ${inline ? 'inline' : 'block'};
  `;

/**
 * Styled for Heading (h1, h2, h3, h4)
 * @param color
 * @param align
 * @param size
 * @param inline
 */
export const getHeadingStyles = (
  size: HeadingSize,
  color: Colors,
  align: Alignment,
  inline: boolean,
) => `
  ${TextReset}
  text-align: ${align || 'inherit'};
  color: ${color || 'inherit'};
  font-size: ${headingSizes[size || 'medium']};
  display: ${inline ? 'inline' : 'block'};
`;


// Text.ts

import styled from 'styled-components';
import { getBodyStyles, BodyStyle, Alignment } from '@/styles/Typography';
import Colors from '@/styles/Colors';

/**
 * Text: Component used for all application body text
 */
export const Text = styled.span.attrs((props: TextProps) => ({
  ...(props.attrs || {}),
  as: props.as,
}))<TextProps>`
  ${props => {
    const { size, color, align, inline } = props;
    return getBodyStyles(size, color, align, inline);
  }}
`;

export interface TextProps {
  as?: 'p' | 'span' | 'div' | 'li' | 'a'; // Element tag
  size?: BodyStyle; // small, medium, tab, subHeader
  align?: Alignment; // text-align property
  color?: Colors; // font-color, must come from Color pallet
  inline?: boolean; // Should display inline?
  attrs?: object; // Optional HTML attributes
}

export default Text;


// Heading.tsx

import styled from 'styled-components';
import Colors from '@/styles/Colors';
import { getHeadingStyles, HeadingSize, Alignment } from '@/styles/Typography';

/**
 * Component used for all instances of heading text (e.g. title, sub-title)
 * All props are optional. The tag type should be correct (specify with the `as` prop)
 * Additional styles can be applied by extending Heading with Styled-Components
 */
export interface HeadingProps {
  as?: 'h1' | 'h2' | 'h3' | 'h4' | 'p';
  align?: Alignment;
  color?: Colors;
  size?: HeadingSize;
  inline?: boolean;
}

export const Heading = styled.h1.attrs((props: HeadingProps) => props.as)<HeadingProps>`
  ${props => {
    const { align, color, size, inline } = props;
    return getHeadingStyles(
      size || 'medium',
      color || Colors.darkGrey,
      align || 'left',
      inline || true,
    );
  }}
`;

Heading.defaultProps = {
  as: 'h1',
};

export default Heading;