Skip to content

Commit bf30b93

Browse files
authored
chore(Markdown): convert markdown styles to vanilla-ish emotion CSS
Convert markdown component styles from SCSS to emotion
1 parent 1a68571 commit bf30b93

File tree

9 files changed

+276
-255
lines changed

9 files changed

+276
-255
lines changed

packages/gamut/src/Markdown/__tests__/Markdown.test.tsx

Lines changed: 19 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ jest.mock('react-player', () => ({
1313
__esModule: true,
1414
default: () => <iframe title={mockTitle} />,
1515
}));
16+
1617
jest.mock('@vidstack/react', () => ({
1718
__esModule: true,
1819
MediaPlayer: () => <iframe title={mockTitle} />,
@@ -101,9 +102,9 @@ describe('<Markdown />', () => {
101102
it('Renders custom tables in markdown', () => {
102103
jest.spyOn(console, 'error').mockImplementation(jest.fn());
103104
renderView({ text: table });
104-
expect(document.querySelectorAll('div.tableWrapper table').length).toEqual(
105-
1
106-
);
105+
expect(
106+
document.querySelectorAll('div[class*="TableWrapper"]').length
107+
).toEqual(1);
107108
});
108109

109110
it('Skips rendering custom tables in markdown when skipProcessing.table is true', () => {
@@ -113,9 +114,9 @@ describe('<Markdown />', () => {
113114
text: table,
114115
});
115116
expect(document.querySelectorAll('table').length).toEqual(1);
116-
expect(document.querySelectorAll('div.tableWrapper table').length).toEqual(
117-
0
118-
);
117+
expect(
118+
document.querySelectorAll('div[class*="TableWrapper"]').length
119+
).toEqual(0);
119120
});
120121

121122
it('Renders YouTube iframes using the Video component', () => {
@@ -144,12 +145,19 @@ describe('<Markdown />', () => {
144145

145146
it('Wraps the markdown in a div by default (block)', () => {
146147
renderView({ text: basicMarkdown });
147-
expect(document.querySelectorAll('div.spacing-tight').length).toEqual(1);
148+
expect(
149+
document.querySelectorAll('div[class*="spacingTight"]').length
150+
).toEqual(1);
148151
});
149152

150153
it('Wraps the markdown in a span when inline', () => {
151154
renderView({ text: basicMarkdown, inline: true });
152-
expect(document.querySelectorAll('span.spacing-tight').length).toEqual(1);
155+
expect(
156+
document.querySelectorAll('div[class*="spacingTight"]').length
157+
).toEqual(0);
158+
expect(
159+
document.querySelectorAll('span[class*="spacingTight"]').length
160+
).toEqual(1);
153161
});
154162

155163
it('does not crash on a value-less attribute', () => {
@@ -406,9 +414,9 @@ var test = true;
406414
`,
407415
});
408416

409-
expect(document.querySelector('li')?.getAttribute('class')).toBe(
410-
'checkbox-parent li'
411-
);
417+
expect(
418+
document.querySelectorAll('li[class*="CheckboxParentLi"]').length
419+
).toEqual(1);
412420
});
413421

414422
it('sets the default checked state correctly', () => {

packages/gamut/src/Markdown/index.tsx

Lines changed: 15 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
import styled from '@emotion/styled';
12
import cx from 'classnames';
23
import HtmlToReact from 'html-to-react';
34
import { marked } from 'marked';
@@ -25,17 +26,23 @@ import { Table } from './libs/overrides/Table';
2526
import { MarkdownVideo } from './libs/overrides/Video';
2627
import { createPreprocessingInstructions } from './libs/preprocessing';
2728
import { defaultSanitizationConfig } from './libs/sanitizationConfig';
28-
// eslint-disable-next-line gamut/no-css-standalone
29-
import styles from './styles/index.module.scss';
29+
import { markdownStyles } from './styles';
3030

3131
const htmlToReactParser = HtmlToReact.Parser({
3232
xmlMode: true,
3333
});
3434

35-
const preprocessingInstructions = createPreprocessingInstructions(styles);
35+
const preprocessingInstructions = createPreprocessingInstructions();
3636

3737
const isValidNode = () => true;
3838

39+
const MarkdownWrapper = styled.div<{ spacing: 'loose' | 'tight' | 'none' }>`
40+
${({ theme, spacing }) => {
41+
const spacingStyleFunction = markdownStyles[spacing];
42+
return spacingStyleFunction ? spacingStyleFunction(theme) : '';
43+
}}
44+
`;
45+
3946
export type SkipDefaultOverridesSettings = {
4047
a?: boolean;
4148
checkbox?: boolean;
@@ -78,11 +85,6 @@ export class Markdown extends PureComponent<MarkdownProps> {
7885

7986
if (!text) return null;
8087

81-
const spacingStyles = styles[`spacing-${spacing}`];
82-
const classes = cx(spacingStyles, className);
83-
84-
const Wrapper = inline ? 'span' : 'div';
85-
8688
const overrides = Object.keys(userOverrides).map((tagName) => {
8789
if (tagName === 'CodeBlock') {
8890
return createCodeBlockOverride(tagName, userOverrides[tagName]);
@@ -175,12 +177,14 @@ export class Markdown extends PureComponent<MarkdownProps> {
175177
);
176178

177179
return (
178-
<Wrapper
180+
<MarkdownWrapper
181+
as={inline ? 'span' : 'div'}
179182
{...omitProps(Object.keys(this.props), this.props)}
180-
className={classes}
183+
className={cx(className)}
184+
spacing={spacing}
181185
>
182186
{react}
183-
</Wrapper>
187+
</MarkdownWrapper>
184188
);
185189
}
186190
}
Lines changed: 44 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,53 @@
1+
import { pxRem } from '@codecademy/gamut-styles';
2+
import styled from '@emotion/styled';
13
import { HTMLAttributes } from 'react';
24
import * as React from 'react';
35

4-
// eslint-disable-next-line gamut/no-css-standalone
5-
import styles from './styles.module.scss';
6+
const TableWrapper = styled.div`
7+
border: 1px solid ${({ theme }) => theme.colors['gray-300']};
8+
max-height: 500px;
9+
overflow: auto;
10+
margin-bottom: 1rem;
11+
12+
table {
13+
font-family: ${({ theme }) => theme.fontFamily.monospace};
14+
padding: ${pxRem(10)};
15+
width: 100%;
16+
color: ${({ theme }) => theme.colors.black};
17+
position: relative;
18+
19+
thead {
20+
position: relative;
21+
}
22+
23+
tr {
24+
height: ${pxRem(30)};
25+
font-size: ${pxRem(13)};
26+
}
27+
28+
tr:nth-of-type(odd) {
29+
background-color: ${({ theme }) => theme.colors['gray-100']};
30+
}
31+
32+
td,
33+
th {
34+
padding-left: 0.5rem;
35+
text-align: inherit;
36+
vertical-align: middle;
37+
color: ${({ theme }) => theme.colors.black};
38+
}
39+
40+
tr:nth-of-type(even),
41+
th {
42+
background-color: ${({ theme }) => theme.colors.white};
43+
}
44+
}
45+
`;
646

747
export const Table: React.FC<HTMLAttributes<HTMLTableElement>> = (props) => {
848
return (
9-
<div className={styles.tableWrapper}>
49+
<TableWrapper>
1050
<table {...props} />
11-
</div>
51+
</TableWrapper>
1252
);
1353
};

packages/gamut/src/Markdown/libs/overrides/Table/styles.module.scss

Lines changed: 0 additions & 42 deletions
This file was deleted.

packages/gamut/src/Markdown/libs/overrides/index.tsx

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,19 @@
1-
import cx from 'classnames';
1+
import styled from '@emotion/styled';
22
import HtmlToReact from 'html-to-react';
33
import camelCaseMap from 'html-to-react/lib/camel-case-attribute-names';
44
import get from 'lodash/get';
55
import * as React from 'react';
66

7-
// eslint-disable-next-line gamut/no-css-standalone
8-
import styles from '../../styles/index.module.scss';
97
import { getLabel, isCheckboxParent, isInput, isLabelText } from './utils';
108

119
const processNodeDefinitions = HtmlToReact.ProcessNodeDefinitions();
1210

11+
const CheckboxParentLi = styled.li`
12+
&::before {
13+
display: none !important;
14+
}
15+
`;
16+
1317
export interface AttributesMap {
1418
[key: string]: string | boolean;
1519
}
@@ -229,10 +233,7 @@ export const createInputOverride = (
229233
if (!Override.component) return null;
230234

231235
if (isCheckboxParent(node, type)) {
232-
const { className, ...rest } = props;
233-
const plainLiClass = cx(styles[`checkbox-parent`], className);
234-
235-
return <li className={plainLiClass} {...rest} />;
236+
return <CheckboxParentLi {...props} />;
236237
}
237238

238239
if (isLabelText(node, type)) return null;

packages/gamut/src/Markdown/libs/preprocessing.ts

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,6 @@ import cx from 'classnames';
22

33
import { HTMLToReactNode } from './overrides';
44

5-
type StylesObject = {
6-
[className: string]: string;
7-
};
8-
95
/**
106
* Preprocessing Instructions:
117
*
@@ -18,14 +14,14 @@ type StylesObject = {
1814
* This is done instead of styling the elements directly to prevent styles from interfering
1915
* with component overrides
2016
*/
21-
export const createPreprocessingInstructions = (styles: StylesObject) => {
17+
export const createPreprocessingInstructions = () => {
2218
return [
2319
{
2420
shouldPreprocessNode(node: HTMLToReactNode) {
2521
return Boolean(node.name);
2622
},
2723
preprocessNode(node: HTMLToReactNode) {
28-
const classname = cx(styles[node.name!], node.attribs?.class);
24+
const classname = cx(`g-md-${node.name}`, node.attribs?.class);
2925

3026
const attrs = { ...node.attribs };
3127
if (classname) attrs.class = classname;

0 commit comments

Comments
 (0)