Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 25 additions & 4 deletions packages/chakra-ui-colors/src/ThemeEditorPalette.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import React, { FC } from 'react'
import React, { FC, useCallback } from 'react'
import {
BoxProps,
useColorModeValue,
Center,
Text,
Expand All @@ -9,7 +8,7 @@ import {
Tooltip,
SimpleGridProps,
} from '@chakra-ui/react'
import { extend } from 'colord'
import { extend, colord } from 'colord'
import namesPlugin from 'colord/plugins/names'
import ThemeEditorPaletteDrawer from './ThemeEditorPaletteDrawer'

Expand Down Expand Up @@ -39,6 +38,28 @@ const ThemeEditorPalette: FC<ThemeEditorPaletteProps> = ({
const shadow = useColorModeValue('surface', 'surfaceDark')
const borderColor = useColorModeValue('blackAlpha.100', 'whiteAlpha.100')

const complemetaryFontColor = useCallback(
(scale: number, key: number) => {
const shade = palette?.[scale]

if (!shade) {
return token.indexOf('white') >= 0 ? 'gray.500' : palette[scale[9 - key]]
}

const colordShade = colord(shade)
const brightness = colordShade.brightness()

if (brightness > 0.71) {
const darkShade = colordShade.invert().darken(2)
return darkShade.toHex()
} else {
const lightShade = colordShade.invert().lighten(1)
return lightShade.toHex()
}
},
[token, palette, scale]
)

return (
<>
<Tooltip
Expand Down Expand Up @@ -74,7 +95,7 @@ const ThemeEditorPalette: FC<ThemeEditorPaletteProps> = ({
>
{showIndex && (
<Text
color={token.indexOf('white') >= 0 ? 'gray.500' : palette[scale[9 - key]]}
color={complemetaryFontColor(Number(paletteIndex), key)}
size="xs"
d={{ base: 'none', md: 'inline' }}
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ export const ThemeEditorDrawerFooter: FC<ThemeEditorDrawerFooterProps> = ({
<Flex
display={isMobile ? 'none' : 'flex'}
position="fixed"
zIndex={10}
justifyContent="center"
bottom={6}
w="100%"
Expand Down
118 changes: 27 additions & 91 deletions packages/chakra-ui-font-sizes/src/ThemeEditorFontSizesItem.tsx
Original file line number Diff line number Diff line change
@@ -1,18 +1,9 @@
import React, { FC, useCallback, useMemo, useState, useEffect } from 'react'
import {
Box,
Flex,
Tag,
Text,
Slider,
SliderTrack,
SliderThumb,
SliderFilledTrack,
Select,
Input,
} from '@chakra-ui/react'
import React, { createContext, FC, useMemo, useState } from 'react'
import { Flex, Tag, Text } from '@chakra-ui/react'
import { useDebouncyEffect } from 'use-debouncy'
import { ElementsHighlighter } from '@hypertheme-editor/chakra-ui-core'
import { FontSizeSlider } from './base-components/FontSizeSlider'
import { InputFields } from './base-components/InputFields'

export type ThemeEditorFontSizesItemProps = {
size: string
Expand All @@ -21,98 +12,43 @@ export type ThemeEditorFontSizesItemProps = {
onChange: (value: { size: string; value: string }) => void
}

export const InputGroupContext = createContext<{
currentFontValue: any
setCurrentFontValue: React.Dispatch<React.SetStateAction<any>>
}>({ currentFontValue: '', setCurrentFontValue: () => undefined })

const ThemeEditorFontSizesItem: FC<ThemeEditorFontSizesItemProps> = (props) => {
const { sampleTitle = 'Lorem ipsum dolor sit', size, value, onChange } = props

const [currentValue, setCurrentValue] = useState<string>(value)

const cssValue = useMemo(() => {
return window && currentValue
? (window as any).CSSStyleValue.parse('font-size', currentValue)
: undefined
}, [currentValue])

const handleSliderChange = useCallback(
(newValue: number) => {
setCurrentValue(`${newValue}${cssValue.unit}`)
},
[cssValue.unit]
)

const handleInputChange = useCallback<React.ChangeEventHandler<HTMLInputElement>>(
(event) => {
setCurrentValue(`${event.target.value}${cssValue.unit}`)
},
[cssValue.unit]
)
const staticCssValue = useMemo(() => {
if (!window) {
return '0rem'
} else if (!value?.length) {
return '0rem'
} else {
return value
}
}, [value])

const handleUnitChange = useCallback<React.ChangeEventHandler<HTMLSelectElement>>(
(event) => {
if (cssValue.unit === 'px' && (event.target.value === 'em' || event.target.value === 'rem')) {
setCurrentValue(`${cssValue.value / 16}${event.target.value}`)
} else if (
(cssValue.unit === 'em' || cssValue.unit === 'rem') &&
event.target.value === 'px'
) {
setCurrentValue(`${(cssValue.value * 16).toFixed(0)}${event.target.value}`)
} else {
setCurrentValue(`${cssValue.value}${event.target.value}`)
}
},
[cssValue.unit, cssValue.value]
)
const [currentValue, setCurrentValue] = useState<string>(staticCssValue)

useDebouncyEffect(() => onChange({ size, value: currentValue }), 500, [currentValue])

useEffect(() => {
setCurrentValue(value)
}, [value])

return (
<ElementsHighlighter themeKeys={`fontSizes.${size}`} fontSize="1rem">
<Flex justifyContent="space-between" mt="0.5rem" alignItems="center">
<Tag alignItems="center" minW="min-content" fontSize="0.75rem" px="0.5rem">
{size}
</Tag>
<Slider
aria-label="slider-ex-1"
min={0}
max={cssValue.unit === 'px' ? 100 : 10}
step={cssValue.unit === 'px' ? 1 : 0.001}
mx="1rem"
value={cssValue.value}
onChange={handleSliderChange}
<InputGroupContext.Provider
value={{
currentFontValue: currentValue,
setCurrentFontValue: setCurrentValue,
}}
>
<SliderTrack>
<SliderFilledTrack bg="primary.500" />
</SliderTrack>
<SliderThumb />
</Slider>
<Flex alignItems="center">
<Input
borderRadius="6px"
size="sm"
textAlign="right"
fontSize="0.875rem"
w="70px"
type="number"
value={cssValue.value}
onChange={handleInputChange}
/>
<Select
size="sm"
w="70px"
ml="0.5rem"
borderRadius="6px"
value={cssValue.unit}
onChange={handleUnitChange}
fontSize="0.875rem"
>
<option value="rem">rem</option>
<option value="em">em</option>
<option value="px">px</option>
</Select>
</Flex>
<FontSizeSlider />
<InputFields />
</InputGroupContext.Provider>
</Flex>
<Text
alignItems="center"
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import { Slider, SliderTrack, SliderFilledTrack, SliderThumb } from '@chakra-ui/react'
import React, { useContext, useMemo, useState } from 'react'
import { InputGroupContext } from '../ThemeEditorFontSizesItem'

export const FontSizeSlider = () => {
const context = useContext(InputGroupContext)
const { currentFontValue, setCurrentFontValue } = context

const fontSizeUnit = useMemo(() => {
const charactersList = Array.from(currentFontValue.matchAll(/[a-z]/g))
const charactersSubstring = charactersList.toString().replaceAll(',', '')

return charactersSubstring
}, [currentFontValue])

const fontSizeValue = useMemo(() => {
const numbersList = Array.from(currentFontValue.matchAll(/[^a-z]/g))
let numbersSubstring = ''
numbersList.forEach((item) => {
numbersSubstring += item
})

const int = Number.isNaN(Number(numbersSubstring)) ? 0 : Number(numbersSubstring)

return int
}, [currentFontValue])

const [isMouseOver, setIsMouseOver] = useState<boolean>(false)

return (
<Slider
aria-label="slider-ex-1"
min={0}
max={fontSizeUnit === 'px' ? 100 : 10}
step={fontSizeUnit === 'px' ? 1 : 0.01}
mx="1rem"
focusThumbOnChange={isMouseOver}
value={fontSizeValue}
onChange={(value) => setCurrentFontValue(`${value}${fontSizeUnit}`)}
onMouseOver={() => setIsMouseOver(true)}
onMouseLeave={() => setIsMouseOver(false)}
>
<SliderTrack>
<SliderFilledTrack bg="primary.500" />
</SliderTrack>
<SliderThumb zIndex={2} />
</Slider>
)
}
70 changes: 70 additions & 0 deletions packages/chakra-ui-font-sizes/src/base-components/InputFields.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import { Flex, Input, Select } from '@chakra-ui/react'
import React, { useCallback, useContext, useMemo } from 'react'
import { InputGroupContext } from '../ThemeEditorFontSizesItem'

export const InputFields = () => {
const context = useContext(InputGroupContext)
const { currentFontValue, setCurrentFontValue } = context

const fontSizeUnit = useMemo(() => {
const charactersList = Array.from(currentFontValue.matchAll(/[a-z]/g))
const charactersSubstring = charactersList.toString().replaceAll(',', '')

return charactersSubstring
}, [currentFontValue])

const fontSizeValue = useMemo(() => {
const numbersList = Array.from(currentFontValue.matchAll(/[^a-z]/g))
let numbersSubstring = ''
numbersList.forEach((item) => {
numbersSubstring += item
})

return numbersSubstring
}, [currentFontValue])

const handleUnitChange = useCallback<React.ChangeEventHandler<HTMLSelectElement>>(
(event) => {
let newValue = '0rem'
if (fontSizeUnit === 'px' && (event.target.value === 'em' || event.target.value === 'rem')) {
newValue = `${Number(fontSizeValue) / 16}${event.target.value}`
} else {
newValue = `${fontSizeValue}${event.target.value}`
}

setCurrentFontValue(newValue)
},
[currentFontValue]
)

return (
<Flex alignItems="center">
<Input
type="number"
step="0.01"
fontSize="0.875rem"
w="70px"
borderRadius="6px"
size="sm"
value={fontSizeValue}
onChange={(e) =>
setCurrentFontValue(`${!e.target.value ? '' : e.target.value}${fontSizeUnit}`)
}
onWheel={(e) => e.currentTarget.blur()}
/>
<Select
size="sm"
w="70px"
ml="0.5rem"
borderRadius="6px"
value={!fontSizeValue?.length ? '' : !!fontSizeUnit?.length ? fontSizeUnit : 'rem'}
onChange={handleUnitChange}
fontSize="0.875rem"
>
<option value="rem">rem</option>
<option value="em">em</option>
<option value="px">px</option>
</Select>
</Flex>
)
}