HyperTheme

Editor v0.1.5

PricingDocsChangelog

Try it

Getting Started

InstallationPro InstallationPROUpgrade to v0.1

Guides

Create a Custom Editor Panel

Components

ThemeEditorProviderHyperThemeEditorThemeEditorThemeEditorDrawerThemeEditorDrawerHeaderThemeEditorDrawerFooterThemeEditorRootPanelThemeEditorButtonColorModeToggleThemeIcon

Hooks

useThemeEditor

Editors

ColorsFont SizesTypography PROFonts PROLine Heights PROLetter Spacing PROShadows PRORadii PROSpace PRO

Create a Custom ThemeEditor Panel

In this tutorial you'll learn how to create a custom theme editor and a simple Color Panel Editor like in the image below.

Custom Colors Editor

In this tutorial you'll use:

Prerequisites

You need HyperTheme Editor installed and working on your Chakra UI Project.

If you still not have installed HyperTheme, follow the installation instructions here.

HyperThemeEditor component

In the Installation page we have added the HyperThemeEditor component that gives us a plug&play editor on the page through a Button.

The source code of HyperThemeEditor itself it's very simple as you can see here:

import React, { FC } from 'react'
import {
ThemeEditor,
ThemeEditorButton,
ThemeEditorButtonProps,
ThemeEditorDrawer,
} from '@hypertheme-editor/chakra-ui-core'
import { ThemeEditorColors } from '@hypertheme-editor/chakra-ui-colors'
import { ThemeEditorFontSizes } from '@hypertheme-editor/chakra-ui-font-sizes'
import { CgColorPicker } from 'react-icons/cg'
import { ImFontSize } from 'react-icons/im'
export type DefaultThemeEditorProps = ThemeEditorButtonProps
export const HyperThemeEditor: FC<DefaultThemeEditorProps> = (props) => {
return (
<ThemeEditor>
<ThemeEditorButton {...props} />
<ThemeEditorDrawer>
<ThemeEditorColors icon={CgColorPicker} title="Colors" />
<ThemeEditorFontSizes icon={ImFontSize} title="Font Sizes" />
</ThemeEditorDrawer>
</ThemeEditor>
)
}

Read more about HyperThemeEditor component here.

Creating a Custom ThemeEditor

Based on the source code of HyperThemeEditor we can create a custom ThemeEditor.

To do so, create a new MyThemeEditor component with this content:

import React, { FC } from 'react'
import {
ThemeEditor,
ThemeEditorButton,
ThemeEditorButtonProps,
ThemeEditorColors,
ThemeEditorFontSizes,
} from '@hypertheme-editor/chakra-ui'
import { CgColorPicker } from 'react-icons/cg'
import { BiText } from 'react-icons/bi'
export const MyThemeEditor = (props) => {
return (
<ThemeEditor>
<ThemeEditorButton {...props} />
<ThemeEditorDrawer>
<ThemeEditorColors icon={CgColorPicker} title="Colors" />
<ThemeEditorFontSizes icon={BiText} title="Typography" />
</ThemeEditorDrawer>
</ThemeEditor>
)
}

As you can see, you can change the order of the panels, the icons and the labels.

HyperTheme uses react-icons for rendering the icons on the editor, here you can search for the icon you need.

Read more about: ThemeEditor, ThemeEditorDrawer and ThemeEditorButton.

Creating a custom Panel

Now that we have a custom ThemeEditor component we can start creating our custom editor panel.

Create a new MyCustomPanel component:

import React from 'react'
import { Box } from '@chakra-ui/react'
export default function MyCustomPanel(props) {
return <Box>Testing Custom Panel</Box>
}

Add it as a new Panel to our MyThemeEditor component:

import React, { FC } from 'react'
import {
ThemeEditor,
ThemeEditorButton,
ThemeEditorButtonProps,
ThemeEditorColors,
ThemeEditorFontSizes,
} from '@hypertheme-editor/chakra-ui'
import { CgColorPicker } from 'react-icons/cg'
import { BiText } from 'react-icons/bi'
import MyCustomPanel from './MyCustomPanel'
export default function MyThemeEditor(props) {
return (
<ThemeEditor>
<ThemeEditorButton {...props} />
<ThemeEditorDrawer>
{/* Add the MyCustomPanel to our theme editor */}
<MyCustomPanel icon={CgColorPicker} title="My Panel" />
<ThemeEditorColors icon={CgColorPicker} title="Colors" />
<ThemeEditorFontSizes icon={BiText} title="Typography" />
</ThemeEditorDrawer>
</ThemeEditor>
)
}

Now you have a custom panel inside the ThemeEditorDrawer component, your theme editor should look like the example below:

useThemeEditor hook

Now that we have a theme editor with a custom editor panel, it's time to start retrieving and live edit the theme.

HyperTheme Editor provides the useThemeEditor hook to:

  • maintaint the current theme state
  • live edit the current theme
  • manage changes history

Check out more on the documentation.

Retrieving and show the current theme

In this section we're creating a ThemeColorBox that shows a color for the theme.

Create a new ThemeColorBox component with this content:

import React from 'react'
import { Box } from '@chakra-ui/react'
import { useThemeEditor } from '@hypertheme-editor/chakra-ui'
export default function ThemeColorBox({ token, paletteIndex = 500, ...props }) {
const { theme } = useThemeEditor()
const color = useMemo(() => {
// in Chakra UI, colors could be objects with an index (like: 100, 200, 300, etc) or a single color
if (theme && theme.colors[token]) {
// if the color is a string, return it
if (typeof theme.colors[token] === 'string') {
return theme.colors[token]
// if it's an object return the current paletteIndex for that color
} else if (theme.colors[token][paletteIndex]) {
return theme.colors[token][paletteIndex]
}
}
return 'gray'
}, [theme, token, paletteIndex])
return <Box w="40px" h="40px" borderRadius="md" bgColor={color} {...props} />
}

Let's check our new component with some different theme colors, try to change the colors from the editor to check that is working correctly:

Live edit the current theme

It's time to live edit the current theme.

Let's create a SimpleColorEditor component that shows the current color and set a new one through an Input:

import React from 'react'
import { useThemeEditor } from '@hypertheme-editor/chakra-ui'
import { Input } from '@chakra-ui/react'
import { useDebouncyEffect } from 'use-debouncy'
import { colord } from 'colord'
export default function SimpleColorEditor({ token, paletteIndex, ...props }) {
const { theme, setTheme } = useThemeEditor()
const [inputValue, setInputValue] = useState<string>(theme.colors[token][paletteIndex] || '')
const handleOnChange = useCallback((event) => {
setInputValue(event.target.value)
}, [])
// use a debounced effect so the UI is not blocked
// while the value are changed through the Input
useDebouncyEffect(
() => {
// check that the input color is valid
if (colord(inputValue).isValid()) {
// the color token could be a simple color or a palette object,
// so we have to check it.
// We also check that the input value differ from
// the one from the theme, this is necessary
// for undo/redo functionality to work correctly
if (typeof theme.colors[token] === 'string' && theme.colors[token] !== inputValue) {
// live edit the current theme
setTheme({
...theme,
colors: {
...theme.colors,
[token]: inputValue,
},
})
} else if (
theme.colors[token][paletteIndex] &&
theme.colors[token][paletteIndex] !== inputValue
) {
// live edit the current theme
setTheme({
...theme,
colors: {
...theme.colors,
[token]: {
...theme.colors.token,
[paletteIndex]: inputValue,
},
},
})
}
}
},
500,
[inputValue]
)
// update internal state if another panel change this value
useEffect(() => {
if (
theme.colors[token] &&
theme.colors[token][paletteIndex] &&
theme.colors[token][paletteIndex] !== inputValue
) {
setInputValue(theme.colors[token][paletteIndex])
}
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [theme.colors, token, paletteIndex])
return (
<HStack>
{/* add the ThemeColorBox we've created before */}
<ThemeColorBox token={token} paletteIndex={paletteIndex} />
<Input onChange={handleOnChange} value={inputValue} />
</HStack>
)
}

Let's try our new SimpleColorEditor component.

If you change a value (using HEX notation) you should see the new color in current theme.

Compare the edited colors with the value provided by HyperThemeEditor.

Final mounting

Finally, we can mount our SimpleColorEditor into our custom theme editor.

Edit the MyPanel component like this:

import React from 'react'
import { Box } from '@chakra-ui/react'
export default function MyCustomPanel(props) {
return (
<VStack>
<SimpleColorEditor token="blue" paletteIndex={500} />
<SimpleColorEditor token="red" paletteIndex={500} />
<SimpleColorEditor token="green" paletteIndex={500} />
<SimpleColorEditor token="orange" paletteIndex={500} />
<SimpleColorEditor token="yellow" paletteIndex={500} />
<SimpleColorEditor token="purple" paletteIndex={500} />
</VStack>
)
}

The final result should be like this:

Congratulations! You have created your first working custom panel.


Hyper kit

Made with ❤️ in 🇮🇹 | byHyperting