Skip to content

Commit

Permalink
Allows copy code component (#65)
Browse files Browse the repository at this point in the history
  • Loading branch information
baptadn authored Feb 17, 2020
1 parent 6f4e9a4 commit cb08e89
Show file tree
Hide file tree
Showing 4 changed files with 142 additions and 20 deletions.
3 changes: 3 additions & 0 deletions src/components/inspector/ActionButton.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ interface Props
icon: IconButtonProps['icon']
as?: IconButtonProps['as']
label: string
isLoading?: boolean
onClick?: IconButtonProps['onClick']
variantColor?: IconButtonProps['variantColor']
}
Expand All @@ -21,6 +22,7 @@ const ActionButton: React.FC<Props> = ({
label,
onClick,
variantColor,
isLoading,
...props
}) => {
return (
Expand All @@ -29,6 +31,7 @@ const ActionButton: React.FC<Props> = ({
size="xs"
variant="ghost"
as={as}
isLoading={isLoading}
onClick={onClick}
icon={icon}
aria-label={label}
Expand Down
45 changes: 40 additions & 5 deletions src/components/inspector/Inspector.tsx
Original file line number Diff line number Diff line change
@@ -1,16 +1,50 @@
import React from 'react'
import React, { useState, memo } from 'react'
import { Link, Box, Stack } from '@chakra-ui/core'

import Panels from './panels/Panels'
import { GoRepo } from 'react-icons/go'
import { GoRepo, GoCode } from 'react-icons/go'
import { FiTrash2 } from 'react-icons/fi'
import { IoMdRefresh } from 'react-icons/io'
import { useSelector } from 'react-redux'
import useDispatch from '../../hooks/useDispatch'
import QuickPropsPanel from './QuickPropsPanel'
import StylesPanel from './panels/StylesPanel'
import { getSelectedComponent } from '../../core/selectors/components'
import {
getSelectedComponent,
getComponents,
getSelectedComponentId,
} from '../../core/selectors/components'
import ActionButton from './ActionButton'
import { generateComponentCode } from '../../utils/code'
import useClipboard from '../../hooks/useClipboard'

const CodeActionButton = memo(() => {
const [isLoading, setIsLoading] = useState(false)
const { onCopy, hasCopied } = useClipboard()

const selectedId = useSelector(getSelectedComponentId)
const components = useSelector(getComponents)

const parentId = components[selectedId].parent
const parent = { ...components[parentId] }
// Do not copy sibling components from parent
parent.children = [selectedId]

return (
<ActionButton
isLoading={isLoading}
label="Copy code component"
variantColor={hasCopied ? 'green' : 'gray'}
onClick={async () => {
setIsLoading(true)
const code = await generateComponentCode(parent, components)
onCopy(code)
setIsLoading(false)
}}
icon={hasCopied ? 'check' : GoCode}
/>
)
})

const Inspector = () => {
const dispatch = useDispatch()
Expand Down Expand Up @@ -53,18 +87,19 @@ const Inspector = () => {
flexWrap="wrap"
justify="flex-end"
>
<CodeActionButton />
<ActionButton
label="Duplicate"
onClick={() => dispatch.components.duplicate()}
icon="copy"
/>
<ActionButton
label="Reset"
label="Reset props"
icon={IoMdRefresh}
onClick={() => dispatch.components.resetProps(component.id)}
/>
<ActionButton
label="Doc"
label="Chakra UI Doc"
as={Link}
onClick={() => {
window.open(
Expand Down
66 changes: 66 additions & 0 deletions src/utils/code.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import { generateComponentCode, generateCode } from './code'

const componentFixtures: IComponents = {
root: {
id: 'root',
parent: 'root',
type: 'Box',
children: ['comp-1'],
props: {},
},
'comp-1': {
id: 'comp-1',
props: {
bg: 'whatsapp.500',
},
children: ['comp-2'],
type: 'Box',
parent: 'root',
rootParentType: 'Box',
},
'comp-2': {
id: 'comp-2',
props: {
children: 'Lorem Ipsum',
},
children: [],
type: 'Text',
parent: 'comp-1',
rootParentType: 'Text',
},
}

describe('Code utils', () => {
it('should generate component code', async () => {
const code = await generateComponentCode(
componentFixtures['root'],
componentFixtures,
)

expect(code).toEqual(`const MyBox = () => (
<Box bg="whatsapp.500">
<Text>Lorem Ipsum</Text>
</Box>
)
`)
})

it('should generate whole tree code', async () => {
const code = await generateCode(componentFixtures)

expect(code).toEqual(`import React from 'react'
import { ThemeProvider, CSSReset, theme, Box, Text } from '@chakra-ui/core'
const App = () => (
<ThemeProvider theme={theme}>
<CSSReset />
<Box bg="whatsapp.500">
<Text>Lorem Ipsum</Text>
</Box>
</ThemeProvider>
)
export default App
`)
})
})
48 changes: 33 additions & 15 deletions src/utils/code.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,24 @@ const capitalize = (value: string) => {
return value.charAt(0).toUpperCase() + value.slice(1)
}

const formatCode = async (code: string) => {
let formattedCode = `// 🚨 Your props contains invalid code`

const prettier = await import('prettier/standalone')
const babylonParser = await import('prettier/parser-babylon')

try {
formattedCode = prettier.format(code, {
parser: 'babel',
plugins: [babylonParser],
semi: false,
singleQuote: true,
})
} catch (e) {}

return formattedCode
}

const buildBlock = (component: IComponent, components: IComponents) => {
let content = ''

Expand Down Expand Up @@ -55,6 +73,20 @@ const buildBlock = (component: IComponent, components: IComponents) => {
return content
}

export const generateComponentCode = async (
component: IComponent,
components: IComponents,
) => {
let code = buildBlock(component, components)

code = `
const My${component.type} = () => (
${code}
)`

return await formatCode(code)
}

export const generateCode = async (components: IComponents) => {
let code = buildBlock(components.root, components)

Expand Down Expand Up @@ -83,19 +115,5 @@ const App = () => (
export default App;`

let formattedCode = `// 🚨 Your props contains invalid code`

const prettier = await import('prettier/standalone')
const babylonParser = await import('prettier/parser-babylon')

try {
formattedCode = prettier.format(code, {
parser: 'babel',
plugins: [babylonParser],
semi: false,
singleQuote: true,
})
} catch (e) {}

return formattedCode
return await formatCode(code)
}

0 comments on commit cb08e89

Please sign in to comment.