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"