-
{rest}
- {side &&
{side}
}
+
+ {sections.map(([left, right], idx) => (
+
+
+ {left}
+
+ {rendersRightColumn && {right}
}
+
+ ))}
);
};
@@ -21,11 +33,6 @@ SideBySide.propTypes = {
children: PropTypes.node.isRequired,
type: PropTypes.string.isRequired,
className: PropTypes.string,
- dir: PropTypes.oneOf(['right', 'left']),
-};
-
-SideBySide.defaultProps = {
- dir: 'right',
};
export default SideBySide;
diff --git a/src/components/SideBySide.module.scss b/src/components/SideBySide.module.scss
index f79337163..84ce66400 100644
--- a/src/components/SideBySide.module.scss
+++ b/src/components/SideBySide.module.scss
@@ -1,32 +1,14 @@
.container {
- display: flex;
-
- > div {
- flex: 1;
- }
-
- &.right {
- flex-direction: row;
-
- > div:nth-child(2) {
- margin-left: 1rem;
- }
- }
-
- &.left {
- flex-direction: row-reverse;
-
- > div:nth-child(2) {
- margin-right: 1rem;
- }
- }
+ display: grid;
+ grid-template-columns: 50% 50%;
+ grid-gap: 1rem;
@media (max-width: 760px) {
- display: block;
-
- &.left > div:nth-child(2),
- &.right > div:nth-child(2) {
- margin: 0;
- }
+ grid-template-columns: 100%;
+ grid-gap: 0;
}
}
+
+.spanColumns {
+ grid-column: span 2;
+}
diff --git a/src/components/Steps.js b/src/components/Steps.js
index 9e68e3151..5c5dd55a8 100644
--- a/src/components/Steps.js
+++ b/src/components/Steps.js
@@ -1,24 +1,14 @@
-import React from 'react';
+import { Children, cloneElement } from 'react';
import PropTypes from 'prop-types';
+import { isMdxType } from '../utils/mdx';
const Steps = ({ children }) => {
- // get the number of steps
- const totalSteps = children.filter(
- (child) => child?.props?.mdxType === 'Step'
+ const totalSteps = Children.toArray(children).filter((child) =>
+ isMdxType(child, 'Step')
).length;
- // return the children with additional props
- return (
- <>
- {children.map((child, index) => ({
- ...child,
- props: {
- ...child.props,
- number: index + 1,
- total: totalSteps,
- },
- }))}
- >
+ return Children.map(children, (child, index) =>
+ cloneElement(child, { number: index + 1, total: totalSteps })
);
};
diff --git a/src/hooks/useClipboard.js b/src/hooks/useClipboard.js
new file mode 100644
index 000000000..307c276bc
--- /dev/null
+++ b/src/hooks/useClipboard.js
@@ -0,0 +1,26 @@
+import { useEffect, useState, useCallback } from 'react';
+import copyToClipboard from '../utils/copyToClipboard';
+
+const useClipboard = ({ duration = 1000 } = {}) => {
+ const [copied, setCopied] = useState(false);
+ const copy = useCallback((text) => {
+ copyToClipboard(text);
+ setCopied(true);
+ }, []);
+
+ useEffect(() => {
+ if (copied && duration) {
+ const id = setTimeout(() => {
+ setCopied(false);
+ }, duration);
+
+ return () => {
+ clearTimeout(id);
+ };
+ }
+ }, [copied, duration]);
+
+ return [copied, copy];
+};
+
+export default useClipboard;
diff --git a/src/hooks/useFormattedCode.js b/src/hooks/useFormattedCode.js
new file mode 100644
index 000000000..a559e765e
--- /dev/null
+++ b/src/hooks/useFormattedCode.js
@@ -0,0 +1,14 @@
+import { useMemo } from 'react';
+import formatCode from '../utils/formatCode';
+
+const useFormattedCode = (code, options) => {
+ return useMemo(() => {
+ try {
+ return formatCode(code, options);
+ } catch (e) {
+ return code;
+ }
+ }, [code, options]);
+};
+
+export default useFormattedCode;
diff --git a/src/markdown-pages/example.mdx b/src/markdown-pages/example.mdx
index 0b37e2620..6daffdd2d 100644
--- a/src/markdown-pages/example.mdx
+++ b/src/markdown-pages/example.mdx
@@ -44,6 +44,12 @@ Use the New Relic One CLI to update the application UUID and run the application
```shell lineNumbers=false
cd /nr1-howto/add-time-picker
```
+
+Once that is done, run the following:
+
+```shell lineNumbers=false
+npm start
+```
@@ -76,7 +82,7 @@ You'll get a URL to access New Relic One and see your application running locall
One the New Relic home page, there's a new launcher to the Add time picker application.
-Click the launcher, and the dashboard opens with your New Relic account transactions.
+Click the launcher, and the dashboard opens with your New Relic account transactions.
### Related info
diff --git a/src/utils/__tests__/splitUsing.js b/src/utils/__tests__/splitUsing.js
new file mode 100644
index 000000000..a5b864f61
--- /dev/null
+++ b/src/utils/__tests__/splitUsing.js
@@ -0,0 +1,37 @@
+import splitUsing from '../splitUsing';
+
+test('splits the list into chunks at the indexes where the predicate is true', () => {
+ const list = [1, 2, 3, 2, 5, 5];
+
+ const result = splitUsing(list, (num) => num === 2);
+
+ expect(result).toEqual([
+ [1, 2],
+ [3, 2],
+ [5, 5],
+ ]);
+});
+
+test('returns empty list if there are no items', () => {
+ const list = [];
+
+ const result = splitUsing(list, () => true);
+
+ expect(result).toEqual([]);
+});
+
+test('handles list where no items satisfy the predicate', () => {
+ const list = [0, 1, 2, 3];
+
+ const result = splitUsing(list, (num) => num === 10);
+
+ expect(result).toEqual([[0, 1, 2, 3]]);
+});
+
+test('handles list where all items satisfy the predicate', () => {
+ const list = [0, 0, 0, 0];
+
+ const result = splitUsing(list, (num) => num === 0);
+
+ expect(result).toEqual([[0], [0], [0], [0]]);
+});
diff --git a/src/utils/__tests__/splitWhen.js b/src/utils/__tests__/splitWhen.js
new file mode 100644
index 000000000..ac3c27088
--- /dev/null
+++ b/src/utils/__tests__/splitWhen.js
@@ -0,0 +1,28 @@
+import splitWhen from '../splitWhen';
+
+test('splits the list into 2 chunks where the predicate is true', () => {
+ const list = [1, 2, 3, 4, 5];
+
+ const result = splitWhen(list, (num) => num === 3);
+
+ expect(result).toEqual([
+ [1, 2],
+ [3, 4, 5],
+ ]);
+});
+
+test('returns empty list if there are no items', () => {
+ const list = [];
+
+ const result = splitWhen(list, () => true);
+
+ expect(result).toEqual([]);
+});
+
+test('handles list where no items satisfy the predicate', () => {
+ const list = [1, 2, 3];
+
+ const result = splitWhen(list, (num) => num === 10);
+
+ expect(result).toEqual([[1, 2, 3], []]);
+});
diff --git a/src/utils/copyToClipboard.js b/src/utils/copyToClipboard.js
new file mode 100644
index 000000000..7404dbee4
--- /dev/null
+++ b/src/utils/copyToClipboard.js
@@ -0,0 +1,11 @@
+const copyToClipboard = (text) => {
+ const textArea = document.createElement('textarea');
+
+ textArea.value = text;
+ document.body.appendChild(textArea);
+ textArea.select();
+ document.execCommand('copy');
+ document.body.removeChild(textArea);
+};
+
+export default copyToClipboard;
diff --git a/src/utils/mdx.js b/src/utils/mdx.js
new file mode 100644
index 000000000..40cb182ab
--- /dev/null
+++ b/src/utils/mdx.js
@@ -0,0 +1 @@
+export const isMdxType = (child, type) => child?.props?.mdxType === type;
diff --git a/src/utils/splitUsing.js b/src/utils/splitUsing.js
new file mode 100644
index 000000000..e29621772
--- /dev/null
+++ b/src/utils/splitUsing.js
@@ -0,0 +1,20 @@
+const splitUsing = (list, predicate) => {
+ const { groups, items } = list.reduce(
+ ({ groups, items }, item) => {
+ if (predicate(item)) {
+ return { groups: groups.concat([items.concat(item)]), items: [] };
+ }
+
+ return { groups: groups, items: items.concat(item) };
+ },
+ { groups: [], items: [] }
+ );
+
+ if (items.length > 0) {
+ return [...groups, items];
+ }
+
+ return groups;
+};
+
+export default splitUsing;
diff --git a/src/utils/splitWhen.js b/src/utils/splitWhen.js
new file mode 100644
index 000000000..5f9febb60
--- /dev/null
+++ b/src/utils/splitWhen.js
@@ -0,0 +1,15 @@
+const splitWhen = (list, predicate) => {
+ if (list.length === 0) {
+ return [];
+ }
+
+ const idx = list.findIndex((item) => predicate(item));
+
+ if (idx === -1) {
+ return [list, []];
+ }
+
+ return [list.slice(0, idx), list.slice(idx)];
+};
+
+export default splitWhen;