Skip to content

Commit

Permalink
[CCUBE-1548][MAHI]Set up ColDiv for layout with its tests and storybo…
Browse files Browse the repository at this point in the history
…ok and add theme capability for Layout component
  • Loading branch information
mahidhar-reddy09 committed Sep 19, 2024
1 parent 5c25380 commit 5252585
Show file tree
Hide file tree
Showing 6 changed files with 500 additions and 0 deletions.
119 changes: 119 additions & 0 deletions src/layout/col-div.style.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
import styled, { css } from "styled-components";
import { MediaQuery } from "../theme/mediaquery/mediaquery-helper";

export interface StyledDivStyleProps {
$xxsStart?: number | undefined;
$xxsSpan?: number | undefined;
$xsStart?: number | undefined;
$xsSpan?: number | undefined;
$smStart?: number | undefined;
$smSpan?: number | undefined;
$mdStart?: number | undefined;
$mdSpan?: number | undefined;
$lgStart?: number | undefined;
$lgSpan?: number | undefined;
$xlStart?: number | undefined;
$xlSpan?: number | undefined;
$xxlStart?: number | undefined;
$xxlSpan?: number | undefined;

$xxsMargin?: string | number;
$xxsGutter?: string | number;
$xsMargin?: string | number;
$xsGutter?: string | number;
$smMargin?: string | number;
$smGutter?: string | number;
$mdMargin?: string | number;
$mdGutter?: string | number;
$lgMargin?: string | number;
$lgGutter?: string | number;
$xlMargin?: string | number;
$xlGutter?: string | number;
$xxlMargin?: string | number;
$xxlGutter?: string | number;
}

export const StyledDiv = styled.div<StyledDivStyleProps>`
position: relative;
${(props) => {
const {
$xxlStart,
$xxlSpan,
$xxlMargin,
$xxlGutter,
$xlStart,
$xlSpan,
$xlMargin,
$xlGutter,
$lgStart,
$lgSpan,
$lgMargin,
$lgGutter,
$mdStart,
$mdSpan,
$mdMargin,
$mdGutter,
$smStart,
$smSpan,
$smMargin,
$smGutter,
$xsStart,
$xsSpan,
$xsMargin,
$xsGutter,
$xxsStart,
$xxsSpan,
$xxsMargin,
$xxsGutter,
} = props;
return css`
grid-column: ${$xxlStart || "auto"} / span ${$xxlSpan || 1};
margin: ${$xxlMargin}px;
padding: ${$xxlGutter}px;
${MediaQuery.MaxWidth.xl} {
grid-column: ${$xlStart || "auto"} / span ${$xlSpan || 1};
margin: ${$xlMargin}px;
padding: ${$xlGutter}px;
}
${MediaQuery.MaxWidth.lg} {
grid-column: ${$lgStart || "auto"} / span ${$lgSpan || 1};
margin: ${$lgMargin}px;
padding: ${$lgGutter}px;
}
${MediaQuery.MaxWidth.md} {
grid-column: ${$mdStart || "auto"} / span ${$mdSpan || 1};
margin: ${$mdMargin}px;
padding: ${$mdGutter}px;
}
${MediaQuery.MaxWidth.sm} {
grid-column: ${$smStart || "auto"} / span ${$smSpan || 1};
margin: ${$smMargin}px;
padding: ${$smGutter}px;
}
${MediaQuery.MaxWidth.xs} {
grid-column: ${$xsStart || "auto"} / span ${$xsSpan || 1};
margin: ${$xsMargin}px;
padding: ${$xsGutter}px;
}
${MediaQuery.MaxWidth.xxs} {
grid-column: ${$xxsStart || "auto"} / span ${$xxsSpan || 1};
margin: ${$xxsMargin}px;
padding: ${$xxsGutter}px;
}
`;
}}
`;
107 changes: 107 additions & 0 deletions src/layout/col-div.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React from "react";
import { ColDivProps, DivRef } from "./types";
import { StyledDiv } from "./col-div.style";
import { BreakpointValues } from "../theme/breakpoint/theme-helper";
import { ThemeSpec } from "../theme/types";
import { useTheme } from "styled-components";

const Component = (props: ColDivProps, ref: DivRef): JSX.Element => {
const theme = useTheme() as ThemeSpec;

const {
xxlCols,
xlCols,
lgCols,
mdCols,
smCols,
xsCols,
xxsCols,
...otherProps
} = props;

const getColSpan = (
cols: number | [number, number] | undefined,
maxCols: number,
label: string
) => {
if (!cols) return { start: undefined, span: undefined };

// during development process to give wwarning
if (process.env.NODE_ENV === "development") {
if (typeof cols === "number" && cols > maxCols) {
console.warn(
`Warning: ${label}Cols exceeds maximum (${maxCols}): ${cols}`
);
} else if (
Array.isArray(cols) &&
(cols[0] > maxCols + 1 || cols[1] > maxCols + 1)
) {
console.warn(
`Warning: ${label}Cols array exceeds maximum (${maxCols}): [${cols[0]}, ${cols[1]}]`
);
}
}

if (Array.isArray(cols)) {
const [start, end] = cols;
const span = Math.min(end - start, maxCols);
return { start, span };
}

return { start: undefined, span: Math.min(cols, maxCols) };
};

const getStyleProps = () => {
const xxlColumnCount = BreakpointValues["xxl-column"]({ theme });
const xlColumnCount = BreakpointValues["xl-column"]({ theme });
const lgColumnCount = BreakpointValues["lg-column"]({ theme });
const mdColumnCount = BreakpointValues["md-column"]({ theme });
const smColumnCount = BreakpointValues["sm-column"]({ theme });
const xsColumnCount = BreakpointValues["xs-column"]({ theme });
const xxsColumnCount = BreakpointValues["xxs-column"]({ theme });

const xxlStartSpan = getColSpan(xxlCols, xxlColumnCount, "xxl");
const xlStartSpan = getColSpan(xlCols, xlColumnCount, "xl");
const lgStartSpan = getColSpan(lgCols, lgColumnCount, "lg");
const mdStartSpan = getColSpan(mdCols, mdColumnCount, "md");
const smStartSpan = getColSpan(smCols, smColumnCount, "sm");
const xsStartSpan = getColSpan(xsCols, xsColumnCount, "xs");
const xxsStartSpan = getColSpan(xxsCols, xxsColumnCount, "xxs");

return {
$xxlStart: xxlStartSpan.start,
$xxlSpan: xxlStartSpan.span,
$xlStart: xlStartSpan.start,
$xlSpan: xlStartSpan.span,
$lgStart: lgStartSpan.start,
$lgSpan: lgStartSpan.span,
$mdStart: mdStartSpan.start,
$mdSpan: mdStartSpan.span,
$smStart: smStartSpan.start,
$smSpan: smStartSpan.span,
$xsStart: xsStartSpan.start,
$xsSpan: xsStartSpan.span,
$xxsStart: xxsStartSpan.start,
$xxsSpan: xxsStartSpan.span,

$xxlMargin: BreakpointValues["xxl-margin"]({ theme }),
$xxlGutter: BreakpointValues["xxl-gutter"]({ theme }),
$xlMargin: BreakpointValues["xl-margin"]({ theme }),
$xlGutter: BreakpointValues["xl-gutter"]({ theme }),
$lgMargin: BreakpointValues["lg-margin"]({ theme }),
$lgGutter: BreakpointValues["lg-gutter"]({ theme }),
$mdMargin: BreakpointValues["md-margin"]({ theme }),
$mdGutter: BreakpointValues["md-gutter"]({ theme }),
$smMargin: BreakpointValues["sm-margin"]({ theme }),
$smGutter: BreakpointValues["sm-gutter"]({ theme }),
$xsMargin: BreakpointValues["xs-margin"]({ theme }),
$xsGutter: BreakpointValues["xs-gutter"]({ theme }),
$xxsMargin: BreakpointValues["xxs-margin"]({ theme }),
$xxsGutter: BreakpointValues["xxs-gutter"]({ theme }),
};
};

return <StyledDiv ref={ref} {...getStyleProps()} {...otherProps} />;
};

export const ColDiv = React.forwardRef(Component);
2 changes: 2 additions & 0 deletions src/layout/index.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { ColDiv } from "./col-div";
import { Container } from "./container";
import { Content } from "./content";
import { Section } from "./section";
Expand All @@ -6,6 +7,7 @@ export const Layout = {
Section: Section,
Container: Container,
Content: Content,
ColDiv: ColDiv,
};

export * from "./types";
68 changes: 68 additions & 0 deletions src/layout/types.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import { DefaultTheme } from "styled-components";

export interface CommonLayoutProps
extends React.HTMLAttributes<HTMLDivElement> {
children: React.ReactNode;
Expand All @@ -17,3 +19,69 @@ export interface SectionProps extends CommonLayoutProps {}
export type DivRef = React.Ref<HTMLDivElement>;

export interface ContentProps extends ContainerProps {}

// does recursion till it gets the max col number
type Range<
N extends number,
Result extends number[] = []
> = Result["length"] extends N
? Exclude<Result[number] | N, 0>
: Range<N, [...Result, Result["length"]]>;

//add one to the range for array
type AddOne<
N extends number,
Result extends number[] = []
> = Result["length"] extends N
? [...Result, Result["length"]]["length"]
: AddOne<N, [...Result, Result["length"]]>;

// uses the range and if there is no max defined it just becomes a number
export type ColSpan<Max extends number | undefined> = Max extends number
? Range<Max> | [Range<AddOne<Max>>, Range<AddOne<Max>>] | undefined
: number | [number, number] | undefined;

// using generic breakpointspan to extract column span for a specific breakpoint
export type BreakpointSpan<
Breakpoint extends keyof DefaultTheme["maxColumns"]
> = DefaultTheme["maxColumns"] extends Record<
Breakpoint,
infer Max extends number
>
? ColSpan<Max>
: number | [number, number] | undefined;

// refactor ColProps to use BreakpointSpan
export interface ColProps {
/**
* Specifies the number of columns to be spanned across for any breakpoint.
* If an array is specified, the format is [startCol, endCol].
*/
xxlCols?: BreakpointSpan<"xxl">;
xlCols?: BreakpointSpan<"xl">;
lgCols?: BreakpointSpan<"lg">;
mdCols?: BreakpointSpan<"md">;
smCols?: BreakpointSpan<"sm">;
xsCols?: BreakpointSpan<"xs">;
xxsCols?: BreakpointSpan<"xxs">;
}
export interface ColDivProps
extends React.HTMLAttributes<HTMLDivElement>,
ColProps {
"data-testid"?: string;

xxlMargin?: string | number;
xxlGutter?: string | number;
xlMargin?: string | number;
xlGutter?: string | number;
lgMargin?: string | number;
lgGutter?: string | number;
mdMargin?: string | number;
mdGutter?: string | number;
smMargin?: string | number;
smGutter?: string | number;
xsMargin?: string | number;
xsGutter?: string | number;
xxsMargin?: string | number;
xxsGutter?: string | number;
}
Loading

0 comments on commit 5252585

Please sign in to comment.