Skip to content

Commit

Permalink
[IOPLT-64] Migrating typography components from io-app (#4)
Browse files Browse the repository at this point in the history
## Short description
Migrating all the typography components from the io-app.

## List of changes proposed in this pull request
- BaseTypograhy
- Body
- Factory
- H1
- H2
- H3
- H4
- H5
- H6
- Label
- LabelSmall
- Link
- Monospace
  • Loading branch information
drmarro authored Jul 4, 2023
1 parent bf8882d commit 0967720
Show file tree
Hide file tree
Showing 22 changed files with 3,548 additions and 1,350 deletions.
2 changes: 1 addition & 1 deletion .github/actions/setup/action.yml
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,4 @@ runs:
run: |
yarn install --cwd example --frozen-lockfile
yarn install --frozen-lockfile
shell: bash
shell: bash
4 changes: 3 additions & 1 deletion .github/workflows/checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,6 @@ jobs:
- id: tsc
run: yarn typecheck
- id: lint
run: yarn lint
run: yarn lint
- name: tests
run: yarn test
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@
"react": "18.2.0",
"react-native": "0.71.8",
"react-native-builder-bob": "^0.20.0",
"react-test-renderer": "^18.2.0",
"release-it": "^15.0.0",
"typescript": "^4.9.5"
},
Expand Down Expand Up @@ -144,6 +145,7 @@
},
"dependencies": {
"@pagopa/ts-commons": "^12.0.0",
"@types/react-test-renderer": "^18.0.0",
"react-native-linear-gradient": "^2.7.3"
}
}
57 changes: 57 additions & 0 deletions src/components/typography/BaseTypography.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import React, { useMemo } from "react";
import { StyleProp, Text, TextStyle } from "react-native";
import { IOColors } from "../../core/IOColors";
import { FontFamily, IOFontWeight, makeFontStyleObject } from "../../utils/fonts";

/**
* The specific properties needed to calculate the font style using {@link makeFontStyleObject} (these information
* cannot be included in the default StyleProp<TextStyle>
*/
type BaseTypographyProps = {
weight: IOFontWeight;
color: IOColors;
font?: FontFamily;
isItalic?: boolean;
};

/**
* Decorate the function {@link makeFontStyleObject} with the additional color calculation.
* @param color A value key from {@link IOColors}, transformed here in {@link ColorValue}
* @param args the args of the function {@link makeFontStyleObject}
*/
const calculateTextStyle = (
color: IOColors,
...args: Parameters<typeof makeFontStyleObject>
) => ({
...makeFontStyleObject(...args),
color: IOColors[color]
});

type OwnProps = BaseTypographyProps & {
fontStyle?: StyleProp<TextStyle>;
} & React.ComponentPropsWithRef<typeof Text>;

/**
* `BaseTypography` is the core Typography component used to render a text.
* It accepts all the default text style `StyleProp<TextStyle>` in addition with {@link BaseTypographyProps}
* used to calculate at runtime the platform-dependent styles.
* This component shouldn't be used in the application but only to compose others `Typography elements`.
* @param props
* @constructor
*/
export const BaseTypography: React.FC<OwnProps> = props => {
const fontStyle = useMemo(
() =>
calculateTextStyle(props.color, props.weight, props.isItalic, props.font),
[props.color, props.weight, props.isItalic, props.font]
);
const style = props.style
? [props.style, props.fontStyle, fontStyle]
: [props.fontStyle, fontStyle];

return (
<Text {...props} style={style}>
{props.children}
</Text>
);
};
37 changes: 37 additions & 0 deletions src/components/typography/Body.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import React from "react";
import { IOColors, IOTheme } from "../../core";
import { FontFamily, IOFontWeight } from "../../utils/fonts";
import { useTypographyFactory } from "./Factory";
import { ExternalTypographyProps, TypographyProps } from "./common";

type PartialAllowedColors = Extract<
IOColors,
"bluegreyDark" | "white" | "blue" | "bluegrey" | "bluegreyLight"
>;
type AllowedColors = PartialAllowedColors | IOTheme["textBody-default"];
type AllowedWeight = IOFontWeight | "Regular" | "SemiBold";

type OwnProps = ExternalTypographyProps<
TypographyProps<AllowedWeight, AllowedColors>
>;

const fontName: FontFamily = "TitilliumWeb";
export const bodyFontSize = 16;
export const bodyLineHeight = 24;
export const bodyDefaultColor: AllowedColors = "bluegrey";
export const bodyDefaultWeight: AllowedWeight = "Regular";

/**
* Typography component to render `Body` text with font size {@link fontSize} and fontFamily {@link fontName}.
* default values (if not defined) are weight: `Regular`, color: `bluegrey`
* @param props`
* @constructor
*/
export const Body: React.FunctionComponent<OwnProps> = props =>
useTypographyFactory<AllowedWeight, AllowedColors>({
...props,
defaultWeight: bodyDefaultWeight,
defaultColor: bodyDefaultColor,
font: fontName,
fontStyle: { fontSize: bodyFontSize, lineHeight: bodyLineHeight }
});
93 changes: 93 additions & 0 deletions src/components/typography/Factory.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
import React, { useMemo } from "react";
import { IOColors } from "../../core";
import { IOFontWeight } from "../../utils/fonts";
import { XOR } from "../../utils/types";
import { BaseTypography } from "./BaseTypography";
import {
calculateWeightColor,
RequiredTypographyProps,
TypographyProps
} from "./common";

/**
* Using the DefaultArgumentProps is possible to define a default fallback value for weight and color
* that will be used when the fields weight and color will be undefined.
*/
type DefaultArgumentProps<WeightPropsType, ColorsPropsType> = {
defaultWeight: WeightPropsType;
defaultColor: ColorsPropsType;
};

/**
* Using the DefaultFactoryProps is possible to define a custom factory to calculate the default value for
* weight and color, thus allowing to implement more sophisticated strategies.
*/
type DefaultFactoryProps<WeightPropsType, ColorsPropsType> = {
weightColorFactory: (
weight?: WeightPropsType,
color?: ColorsPropsType
) => RequiredTypographyProps<WeightPropsType, ColorsPropsType>;
};

/**
* Only one type of default props strategy is allowed
*/
type DefaultProps<WeightPropsType, ColorsPropsType> = XOR<
DefaultArgumentProps<WeightPropsType, ColorsPropsType>,
DefaultFactoryProps<WeightPropsType, ColorsPropsType>
>;

/**
* The factory props will include:
* - One of the two DefaultProps
* - The props of {@link BaseTypographyProps} without weight and color
* - The default {@link TypographyProps}
*/
type FactoryProps<WeightPropsType, ColorsPropsType> = TypographyProps<
WeightPropsType,
ColorsPropsType
> &
DefaultProps<WeightPropsType, ColorsPropsType> &
Omit<React.ComponentProps<typeof BaseTypography>, "weight" | "color">;

/**
* Calculate if the props is of type {@link DefaultFactoryProps}
* @param props
*/
function isDefaultFactoryProps<WeightPropsType, ColorsPropsType>(
props:
| DefaultFactoryProps<WeightPropsType, ColorsPropsType>
| DefaultArgumentProps<WeightPropsType, ColorsPropsType>
): props is DefaultFactoryProps<WeightPropsType, ColorsPropsType> {
return (
(props as DefaultFactoryProps<WeightPropsType, ColorsPropsType>)
.weightColorFactory !== undefined
);
}

/**
* Build a {@link BaseTypography} component, calculating the default values for weight and color if undefined.
* The default values can be calculated specifying some fallback values using {@link DefaultArgumentProps}
* or with a factory function to define some custom behaviour using {@link DefaultFactoryProps}
* @param props
*/
export function useTypographyFactory<
WeightPropsType extends IOFontWeight,
ColorsPropsType extends IOColors
>(props: FactoryProps<WeightPropsType, ColorsPropsType>) {
// Use different strategy to calculate the default values, based on DefaultProps
const { weight, color } = useMemo(
() =>
isDefaultFactoryProps(props)
? props.weightColorFactory(props.weight, props.color)
: calculateWeightColor(
props.defaultWeight,
props.defaultColor,
props.weight,
props.color
),
[props]
);

return <BaseTypography weight={weight} color={color} {...props} />;
}
45 changes: 45 additions & 0 deletions src/components/typography/H1.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from "react";
import {
IOColors,
IOColorsStatusForeground,
IOTheme
} from "../../core/IOColors";
import { FontFamily, IOFontWeight } from "../../utils/fonts";
import { useTypographyFactory } from "./Factory";
import { ExternalTypographyProps, TypographyProps } from "./common";

type PartialAllowedColors = Extract<
IOColors,
"bluegreyDark" | "white" | "blue"
>;
type AllowedColors =
| PartialAllowedColors
| IOColorsStatusForeground
| IOTheme["textHeading-default"];
type AllowedWeight = Extract<IOFontWeight, "Bold">;

type OwnProps = ExternalTypographyProps<
TypographyProps<AllowedWeight, AllowedColors>
>;

export const h1FontSize = 26;
export const h1LineHeight = 32;
export const h1DefaultColor: AllowedColors = "bluegreyDark";
export const h1DefaultWeight: AllowedWeight = "Bold";

/**
* Typography component to render H1 text with font size {@link fontSize} and fontFamily {@link fontName}.
* default values(if not defined) are weight: `Bold`, color: `bluegreyDark`
* @param props
* @constructor
*/
export const H1: React.FC<OwnProps> = (props) => {
const fontName: FontFamily = "TitilliumWeb";
return useTypographyFactory<AllowedWeight, AllowedColors>({
...props,
defaultWeight: h1DefaultWeight,
defaultColor: h1DefaultColor,
font: fontName,
fontStyle: { fontSize: h1FontSize, lineHeight: h1LineHeight }
});
};
45 changes: 45 additions & 0 deletions src/components/typography/H2.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from "react";
import {
IOColors,
IOColorsStatusForeground,
IOTheme
} from "../../core/IOColors";
import { FontFamily, IOFontWeight } from "../../utils/fonts";
import { useTypographyFactory } from "./Factory";
import { ExternalTypographyProps, TypographyProps } from "./common";

type PartialAllowedColors = Extract<
IOColors,
"bluegreyDark" | "white" | "blue" | "bluegrey"
>;
type AllowedColors =
| PartialAllowedColors
| IOColorsStatusForeground
| IOTheme["textHeading-default"];
type AllowedWeight = Extract<IOFontWeight, "Bold" | "SemiBold">;

type OwnProps = ExternalTypographyProps<
TypographyProps<AllowedWeight, AllowedColors>
>;

export const h2FontSize = 20;
export const h2LineHeight = 24;
export const h2DefaultColor: AllowedColors = "bluegreyDark";
export const h2DefaultWeight: AllowedWeight = "Bold";

/**
* Typography component to render `H2` text with font size {@link fontSize} and fontFamily {@link fontName}.
* default values(if not defined) are weight: `Bold`, color: `bluegreyDark`
* @param props
* @constructor
*/
export const H2: React.FC<OwnProps> = (props) => {
const fontName: FontFamily = "TitilliumWeb";
return useTypographyFactory<AllowedWeight, AllowedColors>({
...props,
defaultWeight: h2DefaultWeight,
defaultColor: h2DefaultColor,
font: fontName,
fontStyle: { fontSize: h2FontSize, lineHeight: h2LineHeight }
});
};
Loading

0 comments on commit 0967720

Please sign in to comment.