Issue 660: CodeSnippet Reuseable component (#803)

* Initial CodeSnippet setup in Storybook

* Add support for line numbers

* Pseudo-code some basic tests and leverage useTheme hook

The test suite cannot currently be run, as the react-syntax-highlighter
appears to be using ESM, which are not supported by Jest out-of-the-box.

This should only require a simple Babel loader to remedy, but I want to
make sure first that I have not misconfigured something, as configuring
Babel is likely a notable scope increase for this relatively small
issue.

* Fix ESM Jest issue and update tests

It would be ideal to have snapshot tests to cover the lightmode vs
darkmode rendering. I started experimenting with directly testing the
styling, and it quickly became very sloppy.

* Provide more examples in stories

* Add showLineNumbers to PropType validation
This commit is contained in:
Nathan Calvank
2020-05-11 07:28:20 -07:00
committed by GitHub
parent 901562a0b2
commit 8b2dd21fd0
6 changed files with 245 additions and 1 deletions
+2 -1
View File
@@ -40,7 +40,8 @@
"react-helmet": "5.2.1",
"react-router": "^5.1.2",
"react-router-dom": "^5.1.2",
"react-sparklines": "^1.7.0"
"react-sparklines": "^1.7.0",
"react-syntax-highlighter": "^12.2.1"
},
"devDependencies": {
"@backstage/cli": "^0.1.1-alpha.4",
@@ -0,0 +1,81 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import CodeSnippet from './CodeSnippet';
export default {
title: 'CodeSnippet',
component: CodeSnippet,
};
const containerStyle = { width: 300 };
const JAVASCRIPT = `const greeting = "Hello";
const world = "World";
const greet = person => greeting + " " + person + "!";
greet(world);
`;
const TYPESCRIPT = `const greeting: string = "Hello";
const world: string = "World";
const greet = (person: string): string => greeting + " " + person + "!";
greet(world);
`;
const PYTHON = `greeting = "Hello"
world = "World"
def greet(person):
return f"{greeting} {person}!"
greet(world)
`;
export const Default = () => (
<CodeSnippet text={"const hello = 'World';"} language="javascript" />
);
export const MultipleLines = () => (
<CodeSnippet text={JAVASCRIPT} language="javascript" />
);
export const LineNumbers = () => (
<CodeSnippet text={JAVASCRIPT} language="javascript" showLineNumbers />
);
export const Overflow = () => (
<>
<div style={containerStyle}>
<CodeSnippet text={JAVASCRIPT} language="javascript" />
</div>
<div style={containerStyle}>
<CodeSnippet text={JAVASCRIPT} language="javascript" showLineNumbers />
</div>
</>
);
export const Laguages = () => (
<>
<CodeSnippet text={JAVASCRIPT} language="javascript" showLineNumbers />
<CodeSnippet text={TYPESCRIPT} language="typescript" showLineNumbers />
<CodeSnippet text={PYTHON} language="python" showLineNumbers />
</>
);
@@ -0,0 +1,60 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React from 'react';
import { render } from '@testing-library/react';
import { wrapInThemedTestApp } from '@backstage/test-utils';
import CodeSnippet from './CodeSnippet';
const JAVASCRIPT = `const greeting = "Hello";
const world = "World";
const greet = person => gretting + " " + person + "!";
`;
const minProps = {
text: JAVASCRIPT,
language: 'javascript',
};
describe('<CodeSnippet />', () => {
it('renders text without exploding', () => {
const { getByText } = render(
wrapInThemedTestApp(<CodeSnippet {...minProps} />),
);
expect(getByText(/"Hello"/)).toBeInTheDocument();
expect(getByText(/"World"/)).toBeInTheDocument();
});
it('renders without line numbers', () => {
const { queryByText } = render(
wrapInThemedTestApp(<CodeSnippet {...minProps} />),
);
expect(queryByText('1')).not.toBeInTheDocument();
expect(queryByText('2')).not.toBeInTheDocument();
expect(queryByText('3')).not.toBeInTheDocument();
});
it('renders with line numbers', () => {
const { queryByText } = render(
wrapInThemedTestApp(<CodeSnippet {...minProps} showLineNumbers />),
);
expect(queryByText(/1/)).toBeInTheDocument();
expect(queryByText(/2/)).toBeInTheDocument();
expect(queryByText(/3/)).toBeInTheDocument();
});
});
@@ -0,0 +1,61 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import React, { FC } from 'react';
import PropTypes from 'prop-types';
import SyntaxHighlighter from 'react-syntax-highlighter';
import { docco, dark } from 'react-syntax-highlighter/dist/cjs/styles/hljs';
import { useTheme } from '@material-ui/core';
import { BackstageTheme } from '@backstage/theme';
type Props = {
text: string;
language: string;
showLineNumbers?: boolean;
};
const defaultProps = {
showLineNumbers: false,
};
const CodeSnippet: FC<Props> = props => {
const { text, language, showLineNumbers } = {
...defaultProps,
...props,
};
const theme = useTheme<BackstageTheme>();
const mode = theme.palette.type === 'dark' ? dark : docco;
return (
<SyntaxHighlighter
language={language}
style={mode}
showLineNumbers={showLineNumbers}
>
{text}
</SyntaxHighlighter>
);
};
// Type check for the JS files using this core component
CodeSnippet.propTypes = {
text: PropTypes.string.isRequired,
language: PropTypes.string.isRequired,
showLineNumbers: PropTypes.bool,
};
export default CodeSnippet;
@@ -0,0 +1,17 @@
/*
* Copyright 2020 Spotify AB
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
export { default } from './CodeSnippet';
+24
View File
@@ -10907,6 +10907,11 @@ highlight.js@~9.13.0:
resolved "https://registry.npmjs.org/highlight.js/-/highlight.js-9.13.1.tgz#054586d53a6863311168488a0f58d6c505ce641e"
integrity sha512-Sc28JNQNDzaH6PORtRLMvif9RSn1mYuOoX3omVjnb0+HbpPygU2ALBI0R/wsiqCb4/fcp07Gdo8g+fhtFrQl6A==
highlight.js@~9.15.0, highlight.js@~9.15.1:
version "9.15.10"
resolved "https://registry.npmjs.org/highlight.js/-/highlight.js-9.15.10.tgz#7b18ed75c90348c045eef9ed08ca1319a2219ad2"
integrity sha512-RoV7OkQm0T3os3Dd2VHLNMoaoDVx77Wygln3n9l5YV172XonWG6rgQD3XnF/BuFFZw9A0TJgmMSO8FEWQgvcXw==
history@^4.9.0:
version "4.10.1"
resolved "https://registry.npmjs.org/history/-/history-4.10.1.tgz#33371a65e3a83b267434e2b3f3b1b4c58aad4cf3"
@@ -14141,6 +14146,14 @@ lowercase-keys@^1.0.0:
resolved "https://registry.npmjs.org/lowercase-keys/-/lowercase-keys-1.0.1.tgz#6f9e30b47084d971a7c820ff15a6c5167b74c26f"
integrity sha512-G2Lj61tXDnVFFOi8VZds+SoQjtQC3dgokKdDG2mTm1tx4m50NUHBOZSBwQQHyy0V12A0JTG4icfZQH+xPyh8VA==
lowlight@1.12.1:
version "1.12.1"
resolved "https://registry.npmjs.org/lowlight/-/lowlight-1.12.1.tgz#014acf8dd73a370e02ff1cc61debcde3bb1681eb"
integrity sha512-OqaVxMGIESnawn+TU/QMV5BJLbUghUfjDWPAtFqDYDmDtr4FnB+op8xM+pR7nKlauHNUHXGt0VgWatFB8voS5w==
dependencies:
fault "^1.0.2"
highlight.js "~9.15.0"
lowlight@~1.11.0:
version "1.11.0"
resolved "https://registry.npmjs.org/lowlight/-/lowlight-1.11.0.tgz#1304d83005126d4e8b1dc0f07981e9b689ec2efc"
@@ -17923,6 +17936,17 @@ react-syntax-highlighter@^11.0.2:
prismjs "^1.8.4"
refractor "^2.4.1"
react-syntax-highlighter@^12.2.1:
version "12.2.1"
resolved "https://registry.npmjs.org/react-syntax-highlighter/-/react-syntax-highlighter-12.2.1.tgz#14d78352da1c1c3f93c6698b70ec7c706b83493e"
integrity sha512-CTsp0ZWijwKRYFg9xhkWD4DSpQqE4vb2NKVMdPAkomnILSmsNBHE0n5GuI5zB+PU3ySVvXvdt9jo+ViD9XibCA==
dependencies:
"@babel/runtime" "^7.3.1"
highlight.js "~9.15.1"
lowlight "1.12.1"
prismjs "^1.8.4"
refractor "^2.4.1"
react-textarea-autosize@^7.1.0:
version "7.1.2"
resolved "https://registry.npmjs.org/react-textarea-autosize/-/react-textarea-autosize-7.1.2.tgz#70fdb333ef86bcca72717e25e623e90c336e2cda"