Skip to content

Commit

Permalink
[CCUBE-1547][MAHI]Set up breakpoint tokens and mediaquery helper func…
Browse files Browse the repository at this point in the history
…tion
  • Loading branch information
mahidhar-reddy09 committed Sep 11, 2024
1 parent 409a2cb commit 3e4177e
Show file tree
Hide file tree
Showing 14 changed files with 346 additions and 0 deletions.
41 changes: 41 additions & 0 deletions src/theme/breakpoint/specs/lifesg-breakpoint-set.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { MediaWidth } from "../types";

export const LifeSgMediaWidths: MediaWidth = {
"xxs-min": 0,
"xxs-max": 320,
"xs-min": 321,
"xs-max": 375,
"sm-min": 376,
"sm-max": 420,
"md-min": 421,
"md-max": 767,
"lg-min": 768,
"lg-max": 1023,
"xl-min": 1024,
"xl-max": 1440,
"xxl-min": 1441,

"xxs-column": 8,
"xs-column": 8,
"sm-column": 8,
"md-column": 8,
"lg-column": 12,
"xl-column": 12,
"xxl-column": 12,

"xxs-gutter": 16,
"xs-gutter": 16,
"sm-gutter": 16,
"md-gutter": 16,
"lg-gutter": 32,
"xl-gutter": 32,
"xxl-gutter": 32,

"xxs-margin": 24,
"xs-margin": 24,
"sm-margin": 24,
"md-margin": 24,
"lg-margin": 48,
"xl-margin": 48,
"xxl-margin": 48,
};
74 changes: 74 additions & 0 deletions src/theme/breakpoint/theme-helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
import { StyledComponentProps, getCollection, getValue } from "../helpers";
import { BreakpointScheme, ThemeCollectionSpec } from "../types";
import { LifeSgMediaWidths } from "./specs/lifesg-breakpoint-set";
import { BreakPointCollectionsMap, MediaWidth } from "./types";

const BreakpointSpec: ThemeCollectionSpec<
BreakPointCollectionsMap,
BreakpointScheme
> = {
collections: {
lifesg: LifeSgMediaWidths,
},
defaultValue: "lifesg",
};

export const getBreakpoint = (key: keyof MediaWidth) => {
return (props: StyledComponentProps): number => {
const theme = props.theme;
const breakpointSet: MediaWidth = getCollection(
BreakpointSpec,
theme?.breakpointScheme
);

let value: number | undefined;

if (theme?.overrides?.breakpoint) {
value = getValue(breakpointSet, key, theme.overrides.breakpoint);
} else {
value = breakpointSet[key];
}

return value;
};
};

export const BreakpointValues = {
"xxs-min": getBreakpoint("xxs-min"),
"xxs-max": getBreakpoint("xxs-max"),
"xs-min": getBreakpoint("xs-min"),
"xs-max": getBreakpoint("xs-max"),
"sm-min": getBreakpoint("sm-min"),
"sm-max": getBreakpoint("sm-max"),
"md-min": getBreakpoint("md-min"),
"md-max": getBreakpoint("md-max"),
"lg-min": getBreakpoint("lg-min"),
"lg-max": getBreakpoint("lg-max"),
"xl-min": getBreakpoint("xl-min"),
"xl-max": getBreakpoint("xl-max"),
"xxl-min": getBreakpoint("xxl-min"),

"xxs-column": getBreakpoint("xxs-column"),
"xs-column": getBreakpoint("xs-column"),
"sm-column": getBreakpoint("sm-column"),
"md-column": getBreakpoint("md-column"),
"lg-column": getBreakpoint("lg-column"),
"xl-column": getBreakpoint("xl-column"),
"xxl-column": getBreakpoint("xxl-column"),

"xxs-gutter": getBreakpoint("xxs-gutter"),
"xs-gutter": getBreakpoint("xs-gutter"),
"sm-gutter": getBreakpoint("sm-gutter"),
"md-gutter": getBreakpoint("md-gutter"),
"lg-gutter": getBreakpoint("lg-gutter"),
"xl-gutter": getBreakpoint("xl-gutter"),
"xxl-gutter": getBreakpoint("xxl-gutter"),

"xxs-margin": getBreakpoint("xxs-margin"),
"xs-margin": getBreakpoint("xs-margin"),
"sm-margin": getBreakpoint("sm-margin"),
"md-margin": getBreakpoint("md-margin"),
"lg-margin": getBreakpoint("lg-margin"),
"xl-margin": getBreakpoint("xl-margin"),
"xxl-margin": getBreakpoint("xxl-margin"),
};
45 changes: 45 additions & 0 deletions src/theme/breakpoint/types.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { StyledComponentProps } from "../helpers";
import { BreakpointScheme } from "../types";

export interface MediaWidth {
"xxs-min": number;
"xxs-max": number;
"xs-min": number;
"xs-max": number;
"sm-min": number;
"sm-max": number;
"md-min": number;
"md-max": number;
"lg-min": number;
"lg-max": number;
"xl-min": number;
"xl-max": number;
"xxl-min": number;
"xxs-column": number;
"xs-column": number;
"sm-column": number;
"md-column": number;
"lg-column": number;
"xl-column": number;
"xxl-column": number;
"xxs-gutter": number;
"xs-gutter": number;
"sm-gutter": number;
"md-gutter": number;
"lg-gutter": number;
"xl-gutter": number;
"xxl-gutter": number;
"xxs-margin": number;
"xs-margin": number;
"sm-margin": number;
"md-margin": number;
"lg-margin": number;
"xl-margin": number;
"xxl-margin": number;
}

export type BreakPointCollectionsMap = {
[key in BreakpointScheme]: MediaWidth;
};

export type BreakPointSetOptions = Partial<MediaWidth>;
8 changes: 8 additions & 0 deletions src/theme/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { BreakpointValues } from "./breakpoint/theme-helper";
import { AnimationValues } from "./animation/theme-helper";
import { BorderValues } from "./border/theme-helper";
import { PrimitiveColour } from "./colour-primitive/theme-helper";
Expand Down Expand Up @@ -25,13 +26,16 @@ export const Spacing = SpacingValues;

export const Radius = RadiusValues;

export const Breakpoint = BreakpointValues;

export const LifeSGTheme: ThemeSpec = {
colourScheme: "lifesg",
fontScheme: "lifesg",
animationScheme: "lifesg",
borderScheme: "lifesg",
spacingScheme: "lifesg",
radiusScheme: "lifesg",
breakpointScheme: "lifesg",
};

export const BookingSGTheme: ThemeSpec = {
Expand All @@ -41,6 +45,7 @@ export const BookingSGTheme: ThemeSpec = {
borderScheme: "lifesg",
spacingScheme: "lifesg",
radiusScheme: "lifesg",
breakpointScheme: "lifesg",
};

export const CcubeTheme: ThemeSpec = {
Expand All @@ -50,6 +55,7 @@ export const CcubeTheme: ThemeSpec = {
borderScheme: "lifesg",
spacingScheme: "lifesg",
radiusScheme: "lifesg",
breakpointScheme: "lifesg",
};

export const MyLegacyTheme: ThemeSpec = {
Expand All @@ -59,6 +65,7 @@ export const MyLegacyTheme: ThemeSpec = {
borderScheme: "lifesg",
spacingScheme: "lifesg",
radiusScheme: "lifesg",
breakpointScheme: "lifesg",
};

export const RBSTheme: ThemeSpec = {
Expand All @@ -68,4 +75,5 @@ export const RBSTheme: ThemeSpec = {
borderScheme: "lifesg",
spacingScheme: "lifesg",
radiusScheme: "lifesg",
breakpointScheme: "lifesg",
};
42 changes: 42 additions & 0 deletions src/theme/mediaquery/mediaquery-helper.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { BreakpointValues } from "../breakpoint/theme-helper";
import { StyledComponentProps } from "../helpers";

// Two separate types for max and min breakpoints
type MaxWidthBreakpoints = "xxs" | "xs" | "sm" | "md" | "lg" | "xl";
type MinWidthBreakpoints = MaxWidthBreakpoints | "xxl";

const createMediaQueryFunction = <T extends string>(
type: "max-width" | "min-width",
key: T
) => {
const mappedKey = type === "max-width" ? `${key}-max` : `${key}-min`;
const breakpointFunction =
BreakpointValues[mappedKey as keyof typeof BreakpointValues];

return (props: StyledComponentProps) => {
const value = breakpointFunction(props);
return `@media screen and (${type}: ${value}px)`;
};
};

const getMediaQuerySpec = <T extends string>(
type: "max-width" | "min-width"
): Record<T, (props: StyledComponentProps) => string> => {
// Conditional breakpoints for max and min widths
const breakpoints = (
type === "max-width"
? ["xxs", "xs", "sm", "md", "lg", "xl"]
: ["xxs", "xs", "sm", "md", "lg", "xl", "xxl"]
) as T[];

return breakpoints.reduce((accumulator, key) => {
accumulator[key] = createMediaQueryFunction(type, key);
return accumulator;
}, {} as Record<T, (props: StyledComponentProps) => string>);
};

// Export with typing
export const MediaQuery = {
MaxWidth: getMediaQuerySpec<MaxWidthBreakpoints>("max-width"),
MinWidth: getMediaQuerySpec<MinWidthBreakpoints>("min-width"),
};
6 changes: 6 additions & 0 deletions src/theme/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import { AnimationSetOptions } from "./animation/types";
import { BorderSetOptions } from "./border/types";
import { SpacingSetOptions } from "./spacing/types";
import { RadiusSetOptions } from "./radius/types";
import { BreakPointSetOptions } from "./breakpoint/types";

export type {
PrimitiveColourSet,
Expand Down Expand Up @@ -46,6 +47,7 @@ export type AnimationScheme = "lifesg";
export type BorderScheme = "lifesg";
export type SpacingScheme = "lifesg";
export type RadiusScheme = "lifesg";
export type BreakpointScheme = "lifesg";

export interface ThemeSpecOptions {
primitiveColour?: PrimitiveColourSetOptions | undefined;
Expand All @@ -55,6 +57,7 @@ export interface ThemeSpecOptions {
spacing?: SpacingSetOptions | undefined;
border?: BorderSetOptions | undefined;
radius?: RadiusSetOptions | undefined;
breakpoint?: BreakPointSetOptions | undefined;
typography?: TypographySetOptions | undefined;
}

Expand All @@ -65,7 +68,10 @@ export interface ThemeSpec {
borderScheme: BorderScheme;
spacingScheme: SpacingScheme;
radiusScheme: RadiusScheme;
breakpointScheme: BreakpointScheme;
overrides?: ThemeSpecOptions | undefined;

maxColumns?: any;
}

export interface ThemeCollectionSpec<T, V> {
Expand Down
2 changes: 2 additions & 0 deletions tests/theme/theme-animation.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ describe("StyledAnimationTest", () => {
borderScheme: "lifesg",
spacingScheme: "lifesg",
radiusScheme: "lifesg",
breakpointScheme: "lifesg",
};

const duration = "500ms";
Expand All @@ -43,6 +44,7 @@ describe("StyledAnimationTest", () => {
borderScheme: "lifesg",
spacingScheme: "lifesg",
radiusScheme: "lifesg",
breakpointScheme: "lifesg",
overrides: {
animation: {
"duration-500": "700ms",
Expand Down
3 changes: 3 additions & 0 deletions tests/theme/theme-border.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ describe("Border Theming Test", () => {
borderScheme: "lifesg",
spacingScheme: "lifesg",
radiusScheme: "lifesg",
breakpointScheme: "lifesg",
};

// Constants for border-top (dashed-default)
Expand Down Expand Up @@ -68,6 +69,7 @@ describe("Border Theming Test", () => {
borderScheme: "lifesg",
spacingScheme: "lifesg",
radiusScheme: "lifesg",
breakpointScheme: "lifesg",
};

const dashThickness = "2px";
Expand Down Expand Up @@ -110,6 +112,7 @@ describe("Border Theming Test", () => {
animationScheme: "lifesg",
spacingScheme: "lifesg",
radiusScheme: "lifesg",
breakpointScheme: "lifesg",
overrides: {
border: {
"width-010": 3,
Expand Down
54 changes: 54 additions & 0 deletions tests/theme/theme-breakpoint.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { render } from "@testing-library/react";
import "jest-styled-components";
import styled, { ThemeProvider } from "styled-components";
import { Breakpoint } from "../../src";
import { ThemeSpec } from "../../src/theme/types";

const StyledComponentTest = styled.div`
background-color: red;
@media (min-width: ${Breakpoint["xs-min"]}px) {
background-color: blue;
}
@media (min-width: ${Breakpoint["xs-max"]}px) {
background-color: green;
}
`;

describe("Media Width Breakpoints Test", () => {
const mockTheme: ThemeSpec = {
colourScheme: "lifesg",
fontScheme: "lifesg",
animationScheme: "lifesg",
borderScheme: "lifesg",
spacingScheme: "lifesg",
radiusScheme: "lifesg",
breakpointScheme: "lifesg",
};
it("should apply correct styles based on media width", () => {
const { container } = render(
<ThemeProvider theme={mockTheme}>
<StyledComponentTest />
</ThemeProvider>
);

expect(container.firstChild).toHaveStyleRule("background-color", "red");

expect(container.firstChild).toHaveStyleRule(
"background-color",
"blue",
{
media: `(min-width: 321px)`,
}
);

expect(container.firstChild).toHaveStyleRule(
"background-color",
"green",
{
media: `(min-width: 375px)`,
}
);
});
});
Loading

0 comments on commit 3e4177e

Please sign in to comment.