refactor: extract keyboard shortcut setting

This commit is contained in:
EnixCoda 2022-08-20 21:52:07 +08:00
parent c6fe580d33
commit 3476ed1072
3 changed files with 76 additions and 63 deletions

View file

@ -0,0 +1,58 @@
import { Box, Button, FormControl, TextInput } from '@primer/react'
import * as React from 'react'
import { useUpdateEffect } from 'react-use'
import { friendlyFormatShortcut, noop } from 'utils/general'
import { useStateIO } from 'utils/hooks/useStateIO'
import * as keyHelper from 'utils/keyHelper'
type Props = IO<string | undefined> & {
label: React.ReactNode
}
export function KeyboardShortcutSetting({ label, value, onChange }: Props) {
const $focused = useStateIO(false)
const $shortcut = useStateIO(value)
useUpdateEffect(() => $shortcut.onChange(value), [value])
const id = React.useMemo(() => Math.random() + '', [])
return (
<FormControl>
<FormControl.Label htmlFor={id}>{label}</FormControl.Label>
<Box display="inline-flex" width="100%">
<TextInput
id={id}
sx={{ marginRight: 1, flex: 1 }}
onFocus={() => $focused.onChange(true)}
onBlur={() => $focused.onChange(false)}
placeholder={$focused.value ? 'Press key combination' : 'Click here to set'}
value={friendlyFormatShortcut($shortcut.value)}
onChange={noop}
onKeyDown={e => {
switch (e.key) {
case 'Esc':
case 'Tab':
return
case 'Delete':
case 'Backspace':
// Clear shortcut with backspace
$shortcut.onChange(undefined)
return
default:
e.preventDefault()
e.stopPropagation()
}
$shortcut.onChange(keyHelper.parseEvent(e))
}}
/>
<Button
disabled={!value && !$shortcut.value}
onClick={() => onChange(value === $shortcut.value ? undefined : $shortcut.value)}
>
{/* Show clear when shortcut equal to input value */}
{value === $shortcut.value ? 'Clear' : 'Save'}
</Button>
</Box>
</FormControl>
)
}

View file

@ -1,10 +1,8 @@
import { Box, Button, FormControl, TextInput } from '@primer/react'
import { SimpleConfigFieldCheckbox } from 'components/settings/SimpleConfigField/Checkbox'
import { useConfigs } from 'containers/ConfigsContext'
import * as React from 'react'
import { friendlyFormatShortcut, noop } from 'utils/general'
import { useStateIO } from 'utils/hooks/useStateIO'
import * as keyHelper from 'utils/keyHelper'
import { subIO } from 'utils/general'
import { KeyboardShortcutSetting } from './KeyboardShortcutSetting'
import { SettingsSection } from './SettingsSection'
export function SidebarSettings() {
@ -12,7 +10,10 @@ export function SidebarSettings() {
return (
<SettingsSection title={'Sidebar'}>
<ToggleSidebarShortcutSettings />
<KeyboardShortcutSetting
label={'Keyboard shortcut to toggle visibility'}
{...subIO(useConfigs(), 'shortcut')}
/>
<SimpleConfigFieldCheckbox
field={{
key: 'intelligentToggle',
@ -30,61 +31,3 @@ export function SidebarSettings() {
</SettingsSection>
)
}
function ToggleSidebarShortcutSettings() {
const configContext = useConfigs()
const { shortcut } = configContext.value
const id = 'toggle-show-sidebar-shortcut'
React.useEffect(() => {
useToggleShowSideBarShortcut.onChange(shortcut)
}, [shortcut]) // eslint-disable-line react-hooks/exhaustive-deps
const useToggleShowSideBarShortcut = useStateIO(shortcut)
const { value: toggleShowSideBarShortcut } = useToggleShowSideBarShortcut
const focused = useStateIO(false)
return (
<FormControl>
<FormControl.Label htmlFor={id}>Keyboard shortcut to toggle visibility</FormControl.Label>
<Box display="inline-flex" width="100%">
<TextInput
id={id}
sx={{ marginRight: 1, flex: 1 }}
onFocus={() => focused.onChange(true)}
onBlur={() => focused.onChange(false)}
placeholder={focused.value ? 'Press key combination' : 'Click here to set'}
value={friendlyFormatShortcut(toggleShowSideBarShortcut)}
onChange={noop}
onKeyDown={e => {
e.preventDefault()
e.stopPropagation()
// Clear shortcut with backspace
const shortcut = e.key === 'Backspace' ? '' : keyHelper.parseEvent(e)
useToggleShowSideBarShortcut.onChange(shortcut)
}}
/>
{shortcut === toggleShowSideBarShortcut ? (
<Button
disabled={!shortcut}
onClick={() => {
configContext.onChange({ shortcut: '' })
}}
>
Clear
</Button>
) : (
<Button
onClick={() => {
const { value: toggleShowSideBarShortcut } = useToggleShowSideBarShortcut
if (typeof toggleShowSideBarShortcut !== 'string') return
configContext.onChange({ shortcut: toggleShowSideBarShortcut })
}}
>
Save
</Button>
)}
</Box>
</FormControl>
)
}

View file

@ -2,6 +2,18 @@ import { ReactElement } from 'react'
import * as ReactDOM from 'react-dom'
import { is } from './is'
export function subIO<T, K extends keyof T>(io: IO<T>, field: K): IO<T[K]> {
return {
value: io.value[field],
onChange(value) {
io.onChange({
...io.value,
[field]: value,
})
},
}
}
export function pick<T>(source: T, keys: string[]): Partial<T> {
if (keys && typeof keys === 'object') {
return (Array.isArray(keys) ? keys : Object.keys(keys)).reduce((copy, key) => {