Skip to content
This repository was archived by the owner on Mar 26, 2022. It is now read-only.

Commit 9e5c02d

Browse files
committed
support controlled and uncontrolled behavior
1 parent 243b6ab commit 9e5c02d

File tree

5 files changed

+128
-15
lines changed

5 files changed

+128
-15
lines changed

src/markdown/src/components/MarkdownEditor.js

Lines changed: 17 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,31 +15,42 @@ const StyledTabPanel = styled(TabPanel)`
1515
`;
1616

1717
type Props = {
18+
defaultValue :?string;
1819
forwardedRef :any;
1920
value :string;
2021
view :'edit' | 'preview';
2122
...TextFieldProps;
2223
};
2324

2425
const MarkdownEditor = ({
26+
defaultValue,
2527
forwardedRef,
28+
onChange,
29+
value,
2630
view = 'edit',
27-
value = '',
2831
...rest
2932
} :Props) => {
3033
const [tab, setTab] = useState(view);
34+
const [content, setContent] = useState(value || defaultValue);
3135

32-
const handleChange = (event, newValue) => {
36+
const handleChangeTab = (event, newValue) => {
3337
setTab(newValue);
3438
};
3539

40+
const handleChangeContent = (e) => {
41+
if (onChange) {
42+
onChange(e);
43+
}
44+
setContent(e.target.value);
45+
};
46+
3647
return (
3748
<div>
3849
<TabContext value={tab}>
3950
<TabList
4051
aria-label="markdown editor tabs"
4152
indicatorColor="primary"
42-
onChange={handleChange}
53+
onChange={handleChangeTab}
4354
textColor="primary"
4455
value={tab}>
4556
<Tab label="Edit" value="edit" />
@@ -49,12 +60,13 @@ const MarkdownEditor = ({
4960
<TextArea
5061
rows={4}
5162
ref={forwardedRef}
52-
value={value}
63+
onChange={handleChangeContent}
64+
value={content}
5365
/* eslint-disable-next-line react/jsx-props-no-spreading */
5466
{...rest} />
5567
</StyledTabPanel>
5668
<StyledTabPanel value="preview">
57-
<MarkdownPreview>{value}</MarkdownPreview>
69+
<MarkdownPreview>{content}</MarkdownPreview>
5870
</StyledTabPanel>
5971
</TabContext>
6072
</div>
Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,54 @@
1-
import toJson from 'enzyme-to-json';
2-
import { shallow } from 'enzyme';
1+
import { mount } from 'enzyme';
32

43
import MarkdownEditor from './MarkdownEditor';
4+
import MarkdownPreview from './MarkdownPreview';
5+
6+
import { TextArea } from '../../../text';
57

68
describe('MarkdownEditor', () => {
79

8-
test('render matches snapshot', () => {
9-
const wrapper = shallow(<MarkdownEditor />);
10-
expect(toJson(wrapper)).toMatchSnapshot();
10+
test('default view is edit', () => {
11+
const wrapper = mount(<MarkdownEditor />);
12+
13+
expect(wrapper.find(TextArea)).toHaveLength(1);
14+
});
15+
16+
test('preview view renders MarkdownPreview', () => {
17+
const wrapper = mount(<MarkdownEditor view="preview" />);
18+
19+
expect(wrapper.find(MarkdownPreview)).toHaveLength(1);
20+
});
21+
22+
test('clicking preview tab shows MarkdownPreview', () => {
23+
const wrapper = mount(<MarkdownEditor />);
24+
25+
const previewTab = wrapper.find('button').last();
26+
previewTab.simulate('click');
27+
28+
wrapper.update();
29+
30+
expect(wrapper.find(TextArea)).toHaveLength(0);
31+
expect(wrapper.find(MarkdownPreview)).toHaveLength(1);
32+
});
33+
34+
test('clicking edit tab shows MarkdownPreview', () => {
35+
const wrapper = mount(<MarkdownEditor view="edit" />);
36+
37+
const previewTab = wrapper.find('button').first();
38+
previewTab.simulate('click');
39+
40+
wrapper.update();
41+
42+
expect(wrapper.find(TextArea)).toHaveLength(1);
43+
expect(wrapper.find(MarkdownPreview)).toHaveLength(0);
44+
});
45+
46+
test('should call onChange if provided', () => {
47+
const mockOnChange = jest.fn();
48+
const wrapper = mount(<MarkdownEditor onChange={mockOnChange} />);
49+
50+
wrapper.find('textarea').simulate('change', { target: { value: 'test' } });
51+
expect(mockOnChange).toHaveBeenCalledTimes(1);
1152
});
1253

1354
});
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
import ReactMarkdown from 'react-markdown';
2+
import toJson from 'enzyme-to-json';
3+
import { shallow } from 'enzyme';
4+
5+
import MarkdownPreview from './MarkdownPreview';
6+
import { MarkdownWrapper } from './styled/MarkdownWrapper';
7+
8+
describe('MarkdownPreview', () => {
9+
10+
test('render matches snapshot', () => {
11+
const wrapper = shallow(<MarkdownPreview />);
12+
expect(toJson(wrapper)).toMatchSnapshot();
13+
});
14+
15+
test('should render MarkdownWrapper', () => {
16+
const wrapper = shallow(<MarkdownPreview />);
17+
18+
expect(wrapper.find(MarkdownWrapper)).toHaveLength(1);
19+
});
20+
21+
test('should render ReactMarkdown', () => {
22+
const wrapper = shallow(<MarkdownPreview />);
23+
24+
expect(wrapper.find(ReactMarkdown)).toHaveLength(1);
25+
});
26+
27+
});
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// Jest Snapshot v1, https://goo.gl/fbAQLP
2+
3+
exports[`MarkdownPreview render matches snapshot 1`] = `
4+
<styled.div>
5+
<ReactMarkdown
6+
rehypePlugins={
7+
Array [
8+
[Function],
9+
]
10+
}
11+
remarkPlugins={
12+
Array [
13+
[Function],
14+
]
15+
}
16+
transformLinkUri={[Function]}
17+
/>
18+
</styled.div>
19+
`;

src/markdown/stories/markdownEditor.stories.js

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
import { useState } from 'react';
22

3+
import { action } from '@storybook/addon-actions';
4+
35
import { MARKDOWN_DEMO } from './constants';
46

57
import MarkdownEditor from '../src/components/MarkdownEditor';
@@ -9,11 +11,23 @@ export default {
911
title: 'MarkdownEditor',
1012
};
1113

12-
export const Default = () => {
13-
const [text, setText] = useState(MARKDOWN_DEMO);
14+
export const Uncontrolled = () => (
15+
<Card>
16+
<CardSegment>
17+
<MarkdownEditor defaultValue={MARKDOWN_DEMO} />
18+
</CardSegment>
19+
</Card>
20+
);
1421

22+
Uncontrolled.story = {
23+
name: 'Uncontrolled',
24+
};
25+
26+
export const Controlled = () => {
27+
const [text, setText] = useState(MARKDOWN_DEMO);
1528
const handleChange = (e) => {
16-
setText(e.currentTarget.value);
29+
setText(e.target.value);
30+
action('onChange')(e);
1731
};
1832

1933
return (
@@ -25,6 +39,6 @@ export const Default = () => {
2539
);
2640
};
2741

28-
Default.story = {
29-
name: 'default',
42+
Controlled.story = {
43+
name: 'Controlled',
3044
};

0 commit comments

Comments
 (0)