diff --git a/packages/core/package.json b/packages/core/package.json index 5918fd6008..a08cf12a29 100644 --- a/packages/core/package.json +++ b/packages/core/package.json @@ -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", diff --git a/packages/core/src/components/CodeSnippet/CodeSnippet.stories.tsx b/packages/core/src/components/CodeSnippet/CodeSnippet.stories.tsx new file mode 100644 index 0000000000..52db02177e --- /dev/null +++ b/packages/core/src/components/CodeSnippet/CodeSnippet.stories.tsx @@ -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 = () => ( + +); + +export const MultipleLines = () => ( + +); + +export const LineNumbers = () => ( + +); + +export const Overflow = () => ( + <> +
+ +
+
+ +
+ +); + +export const Laguages = () => ( + <> + + + + +); diff --git a/packages/core/src/components/CodeSnippet/CodeSnippet.test.tsx b/packages/core/src/components/CodeSnippet/CodeSnippet.test.tsx new file mode 100644 index 0000000000..0d0c34a3e6 --- /dev/null +++ b/packages/core/src/components/CodeSnippet/CodeSnippet.test.tsx @@ -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('', () => { + it('renders text without exploding', () => { + const { getByText } = render( + wrapInThemedTestApp(), + ); + expect(getByText(/"Hello"/)).toBeInTheDocument(); + expect(getByText(/"World"/)).toBeInTheDocument(); + }); + + it('renders without line numbers', () => { + const { queryByText } = render( + wrapInThemedTestApp(), + ); + expect(queryByText('1')).not.toBeInTheDocument(); + expect(queryByText('2')).not.toBeInTheDocument(); + expect(queryByText('3')).not.toBeInTheDocument(); + }); + + it('renders with line numbers', () => { + const { queryByText } = render( + wrapInThemedTestApp(), + ); + expect(queryByText(/1/)).toBeInTheDocument(); + expect(queryByText(/2/)).toBeInTheDocument(); + expect(queryByText(/3/)).toBeInTheDocument(); + }); +}); diff --git a/packages/core/src/components/CodeSnippet/CodeSnippet.tsx b/packages/core/src/components/CodeSnippet/CodeSnippet.tsx new file mode 100644 index 0000000000..c77dc5bd43 --- /dev/null +++ b/packages/core/src/components/CodeSnippet/CodeSnippet.tsx @@ -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 => { + const { text, language, showLineNumbers } = { + ...defaultProps, + ...props, + }; + + const theme = useTheme(); + const mode = theme.palette.type === 'dark' ? dark : docco; + + return ( + + {text} + + ); +}; + +// 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; diff --git a/packages/core/src/components/CodeSnippet/index.tsx b/packages/core/src/components/CodeSnippet/index.tsx new file mode 100644 index 0000000000..71587789e5 --- /dev/null +++ b/packages/core/src/components/CodeSnippet/index.tsx @@ -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'; diff --git a/yarn.lock b/yarn.lock index 1bdf373666..e18e7ec38f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -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"