Skip to content

Commit

Permalink
fix(SearchInput): add new custom shortcut and children now optional (#…
Browse files Browse the repository at this point in the history
…3968)

* fix(SearchInput): add new custom shortcut and children now optional

* fix: feedback pantelis

* fix: feedback
  • Loading branch information
matthprost authored Jul 8, 2024
1 parent e0eced0 commit fe71811
Show file tree
Hide file tree
Showing 14 changed files with 1,084 additions and 1,185 deletions.
8 changes: 8 additions & 0 deletions .changeset/eleven-moose-sell.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@ultraviolet/ui": minor
---

Improve `<SearchInput />`:
- prop `shortcut` now takes an array of string in addition to boolean. This way you can define multiple shortcuts for the same input: `shortcut={['/', 's']` for example.
- prop `children` is now optional. If not provided the popup will not be displayed and the input will behave like a regular input.
- new prop `className`
3 changes: 2 additions & 1 deletion packages/ui/src/components/Popup/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import {
useState,
} from 'react'
import { createPortal } from 'react-dom'
import { isClientSide } from '../../helpers/isClientSide'
import type { PositionsType } from './animations'
import { animation, exitAnimation } from './animations'
import type { PopupPlacement } from './helpers'
Expand Down Expand Up @@ -223,7 +224,7 @@ export const Popup = forwardRef(

if (role === 'dialog') {
if (childrenRef.current) return childrenRef.current
if (typeof window !== 'undefined') return document.body
if (isClientSide) return document.body

return null
}
Expand Down
48 changes: 37 additions & 11 deletions packages/ui/src/components/SearchInput/Key.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import styled from '@emotion/styled'
import { useMemo } from 'react'
import { Text } from '../Text'

const Container = styled.div`
Expand All @@ -22,18 +23,43 @@ const Container = styled.div`
}
`

export const KEYS_MATCH = {
Enter: '↵',
' ': '␣',
Meta: '⌘',
Control: 'Ctrl',
Alt: 'Alt',
ArrowUp: '↑',
ArrowDown: '↓',
ArrowLeft: '←',
ArrowRight: '→',
Backspace: '⌫',
Delete: '⌦',
Escape: 'Esc',
CapsLock: 'Caps',
} as const

type KeyProps = {
children: string
children: KeyboardEvent['key']
disabled?: boolean
}

export const Key = ({ children, disabled }: KeyProps) => (
<Container
data-disabled={disabled}
data-children-length={children.length > 1}
>
<Text as="span" variant="caption" sentiment="neutral" disabled={disabled}>
{children}
</Text>
</Container>
)
export const Key = ({ children, disabled }: KeyProps) => {
const isSpecialKey = useMemo(
() => Object.keys(KEYS_MATCH).find(key => key === children),
[children],
)

return (
<Container
data-disabled={disabled}
data-children-length={children.length > 1}
>
<Text as="span" variant="caption" sentiment="neutral" disabled={disabled}>
{isSpecialKey
? KEYS_MATCH[children as keyof typeof KEYS_MATCH]
: children}
</Text>
</Container>
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { Template } from './Template.stories'

export const CustomShortcut = Template.bind({})

CustomShortcut.args = {
shortcut: ['Control', 'Shift', 'A'],
}

CustomShortcut.parameters = {
docs: {
description: {
story:
'If the default shortcut is not suitable, you can customize it by passing a `shortcut` prop with an array of string representing the keys. For example, `["Ctrl", "Shift", "A"]` will display `Ctrl + Shift + A` as the shortcut.\n\nImportant: You need to set the correct key for it to work. To know the name of a key visit [https://www.toptal.com/developers/keycode](https://www.toptal.com/developers/keycode) type your key and check `event.key`.',
},
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import type { StoryFn } from '@storybook/react'
import { useState } from 'react'
import { SearchInput } from '..'
import { Button } from '../../Button'
import { Stack } from '../../Stack'

export const Standalone: StoryFn<typeof SearchInput> = ({ ...args }) => {
const [value, setValue] = useState('')
const [submit, setSubmit] = useState<string | undefined>()

return (
<div style={{ height: '120px' }}>
<Stack direction="row" gap={1}>
<SearchInput
{...args}
placeholder="Type something"
onSearch={setValue}
onClose={() => {}}
/>
<Button onClick={() => setSubmit(value)}>Search</Button>
</Stack>
<div style={{ marginTop: '20px' }}>
<p>Value: {value}</p>
</div>
{submit ? (
<div style={{ marginTop: '20px' }}>
<p>Submitted with value: {submit}</p>
</div>
) : null}
</div>
)
}

Standalone.parameters = {
docs: {
description: {
story:
"The component can take a children or not. If not set the popup won't be displayed and the component will act as a simple input.",
},
},
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import { SearchInput } from '..'
import { Text } from '../../Text'

export const Template: StoryFn<typeof SearchInput> = ({ ...args }) => (
<div style={{ height: '500px' }}>
<div style={{ height: '120px' }}>
<SearchInput
{...args}
placeholder="Type something"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,7 @@ export default {

export { Playground } from './Playground.stories'
export { Shortcut } from './Shortcut.stories'
export { CustomShortcut } from './CustomShortcut.stories'
export { Standalone } from './Standalone.stories'
export { Disabled } from './Disabled.stories'
export { Error } from './Error.stories'
Loading

0 comments on commit fe71811

Please sign in to comment.