Skip to content

Commit

Permalink
feat(docs): add js/ts toggle in code previewer
Browse files Browse the repository at this point in the history
  • Loading branch information
deini committed Nov 11, 2019
1 parent 63ccd16 commit 3ac60e3
Show file tree
Hide file tree
Showing 11 changed files with 170 additions and 36 deletions.
3 changes: 3 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,8 @@
"@commitlint/config-conventional": "^8.1.0",
"husky": "^3.0.2",
"lerna": "^3.16.4"
},
"resolutions": {
"**/react-live/prism-react-renderer": "^1.0.2"
}
}
53 changes: 42 additions & 11 deletions packages/docs/components/CodePreview/CodePreview.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,15 @@
import { transform } from '@babel/standalone';
import * as BigDesign from '@bigcommerce/big-design';
import * as BigDesignIcons from '@bigcommerce/big-design-icons';
import clipboardCopy from 'clipboard-copy';
import { Language } from 'prism-react-renderer';
import React, { useContext, useState } from 'react';
import parser from 'prettier/parser-babylon';
import prettier from 'prettier/standalone';
import React, { useContext, useEffect, useState } from 'react';
import { LiveEditor, LivePreview, LiveProvider } from 'react-live';
import styled from 'styled-components';

import { SnippetControls } from '../SnippetControls';
import { CodeEditorThemeContext } from '../StoryWrapper/StoryWrapper';
import { CodeEditorContext, Language } from '../StoryWrapper/StoryWrapper';

import { StyledLiveError } from './styled';

Expand All @@ -18,29 +20,59 @@ const defaultScope = {
styled,
};

function getInitialCode(children: React.ReactNode): string {
function getInitialCode(children: React.ReactNode, language: Language): string {
if (typeof children !== 'string') {
throw new Error('<CodePreview> children must be of type string');
}

return children;
if (language === 'tsx') {
return children;
}

const code = transform(children, {
compact: false,
retainLines: true,
presets: [['typescript', { allExtensions: true, isTSX: true, jsxPragma: 'preserve' }]],
}).code;

return prettier.format(code, {
parser: 'babel',
plugins: [parser],
printWidth: 100,
singleQuote: true,
trailingComma: 'all',
});
}

function transformCode(input: string): string {
try {
return transform(input, {
presets: [['typescript', { allExtensions: true, isTSX: true }], 'react'],
}).code;
} catch (e) {
return input;
}
}

export interface CodePreviewProps {
scope?: { [key: string]: any };
language?: Language;
}

export const CodePreview: React.FC<CodePreviewProps> = props => {
const { children, language } = props;
const initialCode = getInitialCode(children);
const { children } = props;
const { theme: editorTheme, language } = useContext(CodeEditorContext);

const initialCode = getInitialCode(children, language);
const [code, setCode] = useState(initialCode);
const { editorTheme } = useContext(CodeEditorThemeContext);
const scope = { ...defaultScope, ...props.scope };

useEffect(() => {
setCode(getInitialCode(children, language));
}, [children, language, setCode, getInitialCode]);

return (
<BigDesign.Box border="box" marginBottom="xxLarge">
<LiveProvider code={code} scope={scope} theme={editorTheme} language={language}>
<LiveProvider code={code} scope={scope} theme={editorTheme} language={language} transformCode={transformCode}>
<BigDesign.Box padding="medium" backgroundColor="white" borderBottom="box">
<LivePreview />
</BigDesign.Box>
Expand All @@ -53,6 +85,5 @@ export const CodePreview: React.FC<CodePreviewProps> = props => {
};

CodePreview.defaultProps = {
language: 'jsx',
scope: defaultScope,
};
4 changes: 2 additions & 2 deletions packages/docs/components/CodeSnippet/CodeSnippet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import React, { useContext } from 'react';
import { Editor } from 'react-live';

import { SnippetControls } from '../SnippetControls';
import { CodeEditorThemeContext } from '../StoryWrapper/StoryWrapper';
import { CodeEditorContext } from '../StoryWrapper/StoryWrapper';

interface EditorProps {
language?: Language;
Expand Down Expand Up @@ -41,7 +41,7 @@ function getCode(children: React.ReactNode) {

export const CodeSnippet: React.FC<EditorProps> = props => {
const { children, language, showControls } = props;
const { editorTheme } = useContext(CodeEditorThemeContext);
const { theme: editorTheme } = useContext(CodeEditorContext);
const code = getCode(children);

return (
Expand Down
31 changes: 31 additions & 0 deletions packages/docs/components/Icons/JavascriptIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// **********************************
// Auto-generated file, do NOT modify
// **********************************
import { createStyledIcon, IconProps } from '@bigcommerce/big-design-icons';
import React from 'react';

const Icon =
/*#__PURE__*/
React.memo<Partial<IconProps>>(({ title, theme, ...props }) => (
<svg
height={80}
width={80}
preserveAspectRatio="xMinYMin meet"
viewBox="0 0 256 256"
stroke="currentColor"
fill="currentColor"
strokeWidth="0"
{...props}
>
<title>{title}</title>
<path d="M0 0h256v256H0z" fill="#f7df1e" />
<path
fill="#000"
d="M67.312 213.932l19.59-11.856c3.78 6.701 7.218 12.371 15.465 12.371 7.905 0 12.89-3.092 12.89-15.12v-81.798h24.057v82.138c0 24.917-14.606 36.259-35.916 36.259-19.245 0-30.416-9.967-36.087-21.996m85.07-2.576l19.588-11.341c5.157 8.421 11.859 14.607 23.715 14.607 9.969 0 16.325-4.984 16.325-11.858 0-8.248-6.53-11.17-17.528-15.98l-6.013-2.58c-17.357-7.387-28.87-16.667-28.87-36.257 0-18.044 13.747-31.792 35.228-31.792 15.294 0 26.292 5.328 34.196 19.247l-18.732 12.03c-4.125-7.389-8.591-10.31-15.465-10.31-7.046 0-11.514 4.468-11.514 10.31 0 7.217 4.468 10.14 14.778 14.608l6.014 2.577c20.45 8.765 31.963 17.7 31.963 37.804 0 21.654-17.012 33.51-39.867 33.51-22.339 0-36.774-10.654-43.819-24.574"
/>
</svg>
));

export const JavascriptIcon =
/*#__PURE__*/
createStyledIcon(Icon);
31 changes: 31 additions & 0 deletions packages/docs/components/Icons/TypescriptIcon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
// **********************************
// Auto-generated file, do NOT modify
// **********************************
import { createStyledIcon, IconProps } from '@bigcommerce/big-design-icons';
import React from 'react';

const Icon =
/*#__PURE__*/
React.memo<Partial<IconProps>>(({ title, theme, ...props }) => (
<svg
height={80}
width={80}
viewBox="0 0 128 128"
stroke="currentColor"
fill="currentColor"
strokeWidth="0"
{...props}
>
<title>{title}</title>
<path fill="#fff" d="M22.67 47h99.67v73.67H22.67z" />
<path
fill="#007acc"
d="M1.5 63.91v62.5h125v-125H1.5zm100.73-5a15.56 15.56 0 017.82 4.5 20.58 20.58 0 013 4c0 .16-5.4 3.81-8.69 5.85-.12.08-.6-.44-1.13-1.23a7.09 7.09 0 00-5.87-3.53c-3.79-.26-6.23 1.73-6.21 5a4.58 4.58 0 00.54 2.34c.83 1.73 2.38 2.76 7.24 4.86 8.95 3.85 12.78 6.39 15.16 10 2.66 4 3.25 10.46 1.45 15.24-2 5.2-6.9 8.73-13.83 9.9a38.32 38.32 0 01-9.52-.1 23 23 0 01-12.72-6.63c-1.15-1.27-3.39-4.58-3.25-4.82a9.34 9.34 0 011.15-.73L82 101l3.59-2.08.75 1.11a16.78 16.78 0 004.74 4.54c4 2.1 9.46 1.81 12.16-.62a5.43 5.43 0 00.69-6.92c-1-1.39-3-2.56-8.59-5-6.45-2.78-9.23-4.5-11.77-7.24a16.48 16.48 0 01-3.43-6.25 25 25 0 01-.22-8c1.33-6.23 6-10.58 12.82-11.87a31.66 31.66 0 019.49.26zm-29.34 5.24v5.12H56.66v46.23H45.15V69.26H28.88v-5a49.19 49.19 0 01.12-5.17C29.08 59 39 59 51 59h21.83z"
data-name="original"
/>
</svg>
));

export const TypescriptIcon =
/*#__PURE__*/
createStyledIcon(Icon);
15 changes: 13 additions & 2 deletions packages/docs/components/SnippetControls/SnippetControls.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ import { Button, Flex, Small } from '@bigcommerce/big-design';
import { AssignmentIcon, CheckIcon, InvertColorsIcon, RestoreIcon } from '@bigcommerce/big-design-icons';
import React, { useContext, useState } from 'react';

import { CodeEditorThemeContext } from '../StoryWrapper/StoryWrapper';
import { JavascriptIcon } from '../Icons/JavascriptIcon';
import { TypescriptIcon } from '../Icons/TypescriptIcon';
import { CodeEditorContext } from '../StoryWrapper/StoryWrapper';

import { StyledFlex } from './styled';

Expand Down Expand Up @@ -32,7 +34,7 @@ function onCopy(setIsCopying: (copying: boolean) => void, copyToClipboard: () =>
export const SnippetControls: React.FC<SnippetControls> = props => {
const { copyToClipboard, helperText, resetCode } = props;
const [isCopying, setIsCopying] = useState(false);
const { toggleEditorTheme } = useContext(CodeEditorThemeContext);
const { toggleTheme: toggleEditorTheme, setLanguage } = useContext(CodeEditorContext);

return (
<StyledFlex
Expand All @@ -45,6 +47,15 @@ export const SnippetControls: React.FC<SnippetControls> = props => {
<Flex.Item flexGrow={1}>
<Small marginHorizontal="small">{helperText}</Small>
</Flex.Item>

<Flex.Item borderLeft="box">
<Button iconOnly={<TypescriptIcon />} variant="subtle" onClick={() => setLanguage('tsx')} />
</Flex.Item>

<Flex.Item borderLeft="box">
<Button iconOnly={<JavascriptIcon />} variant="subtle" onClick={() => setLanguage('jsx')} />
</Flex.Item>

<Flex.Item borderLeft="box">
<Button
iconOnly={getCopyToClipboardIcon(isCopying)}
Expand Down
22 changes: 15 additions & 7 deletions packages/docs/components/StoryWrapper/StoryWrapper.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,26 +4,34 @@ import { default as lightTheme } from 'prism-react-renderer/themes/github';
import { default as darkTheme } from 'prism-react-renderer/themes/oceanicNext';
import React, { createContext, useState } from 'react';

export type Language = 'jsx' | 'tsx';

interface Context {
editorTheme: PrismTheme;
toggleEditorTheme(): void;
theme: PrismTheme;
language: Language;
setLanguage(language: Language): void;
toggleTheme(): void;
}

export const CodeEditorThemeContext = createContext<Context>({
editorTheme: darkTheme,
export const CodeEditorContext = createContext<Context>({
language: 'tsx',
theme: darkTheme,
// tslint:disable-next-line: no-empty
setLanguage: () => {},
// tslint:disable-next-line: no-empty
toggleEditorTheme: () => {},
toggleTheme: () => {},
});

export const StoryWrapper: React.FC = props => {
const [editorTheme, setEditorTheme] = useState(darkTheme);
const [language, setLanguage] = useState<Language>('tsx');
const toggleEditorTheme = () => setEditorTheme(editorTheme === darkTheme ? lightTheme : darkTheme);

return (
<Panel>
<CodeEditorThemeContext.Provider value={{ editorTheme, toggleEditorTheme }}>
<CodeEditorContext.Provider value={{ theme: editorTheme, toggleTheme: toggleEditorTheme, language, setLanguage }}>
{props.children}
</CodeEditorThemeContext.Provider>
</CodeEditorContext.Provider>
</Panel>
);
};
8 changes: 6 additions & 2 deletions packages/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,16 @@
]
},
"dependencies": {
"@babel/preset-react": "^7.7.0",
"@babel/preset-typescript": "^7.7.0",
"@babel/standalone": "^7.7.3",
"@bigcommerce/big-design": "^0.13.0",
"@bigcommerce/big-design-icons": "^0.5.0",
"@bigcommerce/big-design-theme": "^0.3.0",
"clipboard-copy": "^3.1.0",
"next": "^9.0.3",
"prism-react-renderer": "^0.1.7",
"prettier": "^1.16.4",
"prism-react-renderer": "^1.0.2",
"react": "^16.8.4",
"react-dom": "^16.8.4",
"react-live": "^2.2.0",
Expand All @@ -43,10 +47,10 @@
"devDependencies": {
"@bigcommerce/configs": "^0.8.0",
"@types/gtag.js": "^0.0.2",
"@types/prettier": "^1.18.3",
"@types/styled-components": "^4.1.12",
"babel-plugin-styled-components": "^1.10.6",
"jsx-to-string-loader": "^1.2.0",
"prettier": "^1.16.4",
"push-dir": "^0.4.1",
"tslint": "^5.14.0",
"typescript": "^3.7.2",
Expand Down
5 changes: 4 additions & 1 deletion packages/docs/pages/Dropdown/DropdownPage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,10 @@ export default () => (
<CodePreview>
{/* jsx-to-string:start */}
<Dropdown
options={[{ content: 'Save', actionType: 'normal' }, { content: 'Delete', actionType: 'destructive' }]}
options={[
{ content: 'Save', actionType: 'normal' },
{ content: 'Delete', actionType: 'destructive' },
]}
trigger={<Button>Button</Button>}
/>
{/* jsx-to-string:end */}
Expand Down
9 changes: 3 additions & 6 deletions packages/docs/pages/Table/TablePage.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,14 @@ export default () => {
<CodePreview scope={{ data, columns }}>
{/* jsx-to-string:start */}
{function Example() {
const [selectedItems, setSelectedItems] = React.useState([]);
const [selectedItems, setSelectedItems] = React.useState<Item[]>([]);

return (
<Table
keyField="sku"
columns={columns}
items={data}
itemName="Products"
// @ts-ignore
selectable={{
selectedItems,
onSelectionChange: setSelectedItems,
Expand All @@ -102,7 +101,7 @@ export default () => {
const [currentPage, setCurrentPage] = React.useState(1);
const [itemsPerPageOptions] = React.useState([5, 10, 20, 30]);
const [itemsPerPage, setItemsPerPage] = React.useState(5);
const [currentItems, setCurrentItems] = React.useState([]);
const [currentItems, setCurrentItems] = React.useState<Item[]>([]);

const onItemsPerPageChange = newRange => {
setCurrentPage(1);
Expand All @@ -114,7 +113,6 @@ export default () => {
const lastItem = Math.min(maxItems, data.length);
const firstItem = Math.max(0, maxItems - itemsPerPage);

// @ts-ignore
setCurrentItems(data.slice(firstItem, lastItem));
}, [currentPage, data, itemsPerPage]);

Expand Down Expand Up @@ -145,7 +143,7 @@ export default () => {
{function Example() {
const [items, setItems] = React.useState(data);
const [columnHash, setColumnHash] = React.useState('');
const [direction, setDirection] = React.useState('ASC');
const [direction, setDirection] = React.useState<'ASC' | 'DESC'>('ASC');

const onSort = (newColumnHash, newDirection) => {
setColumnHash(newColumnHash);
Expand All @@ -163,7 +161,6 @@ export default () => {
]}
items={items}
itemName="Products"
// @ts-ignore
sortable={{
columnHash,
direction,
Expand Down
Loading

0 comments on commit 3ac60e3

Please sign in to comment.