Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[CCUBE-1628][MAHI]Migrate accordian and text list components #617

Merged
merged 4 commits into from
Dec 3, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions codemods/deprecate-v2-tokens/data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,10 @@ export const componentMap = [
oldName: "ColDivProps",
newName: "V2_ColDivProps",
},
{
oldName: "TextList",
newName: "V2_TextList",
},
// Added theme name mappings
{
oldName: "BaseTheme",
Expand Down Expand Up @@ -244,6 +248,10 @@ export const pathMap = [
oldPath: "layout",
newPath: "v2_layout",
},
{
oldPath: "text-list",
newPath: "v2_text-list",
},
{
oldPath: "theme",
newPath: "v2_theme",
Expand Down
16 changes: 16 additions & 0 deletions codemods/migrate-text-list/data.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
export const sizePropMapping = {
D1: "header-xxl",
D2: "header-xl",
D3: "header-md",
D4: "header-sm",
H1: "header-lg",
H2: "header-md",
H3: "header-sm",
H4: "header-xs",
H5: "body-md",
H6: "body-sm",
DBody: "header-sm",
Body: "body-baseline",
BodySmall: "body-md",
XSmall: "body-xs",
};
102 changes: 102 additions & 0 deletions codemods/migrate-text-list/index.ts
qroll marked this conversation as resolved.
Show resolved Hide resolved
qroll marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { API, FileInfo, JSCodeshift } from "jscodeshift";
import { sizePropMapping } from "./data";

// ======= Constants ======= //

const IMPORT_PATHS = {
TEXT_LIST: "@lifesg/react-design-system/text-list",
V2_TEXT_LIST: "@lifesg/react-design-system/v2_text-list",
DESIGN_SYSTEM: "@lifesg/react-design-system",
};

const IMPORT_SPECIFIERS = {
TEXT_LIST: "TextList",
V2_TEXT_LIST: "V2_TextList",
};

const JSX_IDENTIFIERS = {
TEXT_LIST: "TextList",
V2_TEXT_LIST: "V2_TextList",
};

// ======= Transformer Function ======= //

export default function transformer(file: FileInfo, api: API) {
const j: JSCodeshift = api.jscodeshift;
const source = j(file.source);

let isV2TextListImport = false;

source.find(j.ImportDeclaration).forEach((path) => {
const importPath = path.node.source.value;

if (
importPath === IMPORT_PATHS.V2_TEXT_LIST ||
importPath === IMPORT_PATHS.DESIGN_SYSTEM
) {
path.node.specifiers?.forEach((specifier) => {
if (
j.ImportSpecifier.check(specifier) &&
specifier.imported.name === IMPORT_SPECIFIERS.V2_TEXT_LIST
) {
specifier.imported.name = IMPORT_SPECIFIERS.TEXT_LIST;

if (
specifier.local &&
specifier.local.name === IMPORT_SPECIFIERS.V2_TEXT_LIST
) {
specifier.local.name = IMPORT_SPECIFIERS.TEXT_LIST;
}

if (importPath === IMPORT_PATHS.V2_TEXT_LIST) {
path.node.source.value = IMPORT_PATHS.TEXT_LIST;
}

isV2TextListImport = true;
}
});
}
});

if (isV2TextListImport) {
source
.find(j.Identifier, { name: JSX_IDENTIFIERS.V2_TEXT_LIST })
.forEach((path) => {
path.node.name = JSX_IDENTIFIERS.TEXT_LIST;
});

source.find(j.MemberExpression).forEach((path) => {
if (
j.Identifier.check(path.node.object) &&
path.node.object.name === JSX_IDENTIFIERS.V2_TEXT_LIST
) {
path.node.object.name = JSX_IDENTIFIERS.TEXT_LIST;
}
});

source
.find(j.JSXOpeningElement, {
name: { name: JSX_IDENTIFIERS.TEXT_LIST },
qroll marked this conversation as resolved.
Show resolved Hide resolved
})
.forEach((path) => {
const attributes = path.node.attributes;

attributes?.forEach((attribute) => {
if (
j.JSXAttribute.check(attribute) &&
attribute.name.name === "size" &&
j.StringLiteral.check(attribute.value)
) {
const sizeValue = attribute.value.value;
if (sizePropMapping[sizeValue]) {
attribute.value = j.literal(
sizePropMapping[sizeValue]
);
}
}
});
});
}

return source.toSource();
}
3 changes: 3 additions & 0 deletions codemods/run-codemod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ enum Codemod {
MigrateLayout = "migrate-layout",
MigrateMediaQuery = "migrate-media-query",
MigrateText = "migrate-text",
MigrateTextList = "migrate-text-list",
}

enum Theme {
Expand All @@ -32,6 +33,8 @@ const CodemodDescriptions: { [key in Codemod]: string } = {
[Codemod.MigrateMediaQuery]:
"Replace V2 media queries with new Breakpoint tokens",
[Codemod.MigrateText]: "Replace V2_Text with new Typography components",
[Codemod.MigrateTextList]:
"Replace V2_TextList with new Textlist components",
};

const TargetDirectoryPaths = {
Expand Down
25 changes: 12 additions & 13 deletions src/accordion/accordion-item.style.tsx
qroll marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import { ChevronUpIcon } from "@lifesg/react-icons/chevron-up";
import { animated } from "react-spring";
import styled, { css } from "styled-components";
import { V2_Color } from "../v2_color";
import { V2_MediaQuery } from "../v2_media";
import { ClickableIcon } from "../shared/clickable-icon";
import { V2_Text } from "../v2_text/text";
import { Transition } from "../transition";
import { Border, Colour, Motion } from "../theme";
import { MediaQuery } from "../theme";
import { Typography } from "../typography";

// =============================================================================
// STYLE INTERFACE, transient props are denoted with $
Expand All @@ -19,11 +18,11 @@ interface StyleProps {
// STYLING
// =============================================================================
export const Container = styled.div<StyleProps>`
background-color: ${V2_Color.Neutral[8]} !important;
border-top: 1px solid ${V2_Color.Neutral[6]};
background-color: ${Colour.bg} !important;
border-top: ${Border["width-010"]} ${Border.solid} ${Colour.border};
padding: ${(props) => (props.$isCollapsed ? "0 0 1rem" : "0")};

${V2_MediaQuery.MaxWidth.mobileL} {
${MediaQuery.MaxWidth.sm} {
padding: ${(props) =>
props.$isCollapsed ? ".25rem 0 1.05rem" : "0.5rem 0"};
}
Expand All @@ -40,16 +39,16 @@ export const TitleContainer = styled.div<StyleProps>`
const TITLE_STYLE = (isCollapsed?: boolean) => css`
flex: 1;
margin: 1rem 2rem ${isCollapsed ? 0.5 : 1}rem 0;
transition: ${Transition.Base};
transition: all ${Motion["duration-250"]} ${Motion["ease-standard"]};
`;

export const Title = styled(V2_Text.H3)<StyleProps>`
export const Title = styled(Typography.HeaderSM)<StyleProps>`
${(props) => {
return TITLE_STYLE(props.$isCollapsed);
}}
`;

export const TitleH4 = styled(V2_Text.H4)<StyleProps>`
export const TitleH4 = styled(Typography.HeaderXS)<StyleProps>`
${(props) => {
return TITLE_STYLE(props.$isCollapsed);
}}
Expand All @@ -60,14 +59,14 @@ export const ExpandCollapseButton = styled(ClickableIcon)<StyleProps>`
width: 3.25rem;
padding: 1rem;
transform: rotate(${(props) => (props.$isCollapsed ? 0 : 180)}deg);
transition: transform 300ms ease-in-out;
transition: transform ${Motion["duration-250"]} ${Motion["ease-default"]};
margin: auto -1rem auto 0;
`;

export const ChevronIcon = styled(ChevronUpIcon)`
height: 1.25rem;
width: 1.25rem;
color: ${V2_Color.Primary};
color: ${Colour["icon-primary"]};
`;

export const Expandable = styled(animated.div)<StyleProps>`
Expand All @@ -78,7 +77,7 @@ export const DescriptionContainer = styled.div`
display: inline-block;
padding-right: 4rem;

${V2_MediaQuery.MaxWidth.tablet} {
${MediaQuery.MaxWidth.lg} {
padding-right: 0;
}
`;
18 changes: 9 additions & 9 deletions src/accordion/accordion.style.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import styled, { css } from "styled-components";
import { Button } from "../button";
import { V2_Color } from "../v2_color";
import { V2_MediaQuery } from "../v2_media";
import { V2_Text } from "../v2_text/text";
import { TitleStyleProps, TitleWrapperStyleProps } from "./types";
import { Border, MediaQuery } from "../theme";
import { Colour } from "../theme";
import { Typography } from "../typography";

// ============================================================================
// STYLING
// =============================================================================
export const Content = styled.div`
width: 100%;
border-bottom: 1px solid ${V2_Color.Neutral[6]};
border-bottom: ${Border["width-010"]} ${Border.solid} ${Colour.border};
`;

export const TitleWrapper = styled.div<TitleWrapperStyleProps>`
Expand All @@ -20,33 +20,33 @@ export const TitleWrapper = styled.div<TitleWrapperStyleProps>`
justify-content: flex-end;
padding-bottom: 1rem;

${V2_MediaQuery.MaxWidth.mobileL} {
${MediaQuery.MaxWidth.sm} {
justify-content: flex-end;
}

${(props) => {
if (!props.$showTitleInMobile && !props.$hasExpandAll) {
return css`
${V2_MediaQuery.MaxWidth.mobileL} {
${MediaQuery.MaxWidth.sm} {
display: none;
}
`;
}
}}
`;

export const Title = styled(V2_Text.H2)<TitleStyleProps>`
export const Title = styled(Typography.HeaderMD)<TitleStyleProps>`
display: flex;
align-self: flex-start;
flex: 1;
${V2_MediaQuery.MaxWidth.mobileL} {
${MediaQuery.MaxWidth.sm} {
text-align: left;
}

${(props) => {
if (!props.$showInMobile) {
return css`
${V2_MediaQuery.MaxWidth.mobileL} {
${MediaQuery.MaxWidth.sm} {
display: none;
visibility: hidden;
}
Expand Down
9 changes: 9 additions & 0 deletions src/text-list/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { UnorderedList } from "./unordered-list";
import { OrderedList } from "./ordered-list";

export const TextList = {
Ul: UnorderedList,
Ol: OrderedList,
};

export * from "./types";
15 changes: 15 additions & 0 deletions src/text-list/ordered-list.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import React from "react";
import { StyledOrderedList } from "./text-list.styles";
import { OrderedListProps } from "./types";

export const OrderedList = ({
size = "body-baseline",
children,
...otherProps
}: OrderedListProps) => {
return (
<StyledOrderedList size={size} {...otherProps}>
{children}
</StyledOrderedList>
);
};
Loading