Skip to content

Commit

Permalink
Refactored for generic alt+action to edit
Browse files Browse the repository at this point in the history
  • Loading branch information
benjackwhite committed Mar 20, 2024
1 parent 0a9bc75 commit f529b5e
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 47 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,9 @@ export function PropertyValue({
onChange={(nextVal) => (isMultiSelect ? setValue(nextVal) : setValue(nextVal[0]))}
onInputChange={onSearchTextChange}
placeholder={placeholder}
dropdownProps={{
sameWidth: false,
}}
options={displayOptions.map(({ name: _name }, index) => {
const name = toString(_name)
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,9 +54,24 @@ MultipleSelect.args = {

export const MultipleSelectWithCustom: Story = Template.bind({})
MultipleSelectWithCustom.args = {
placeholder: 'Enter any email...',
placeholder: 'Pick a url...',
mode: 'multiple',
allowCustomValues: true,
options: [
{
key: 'http://posthog.com/docs',
label: 'http://posthog.com/docs',
},
{
key: 'http://posthog.com/pricing',
label: 'http://posthog.com/pricing',
},

{
key: 'http://posthog.com/products',
label: 'http://posthog.com/products',
},
],
}

export const Disabled: Story = Template.bind({})
Expand Down
111 changes: 65 additions & 46 deletions frontend/src/lib/lemon-ui/LemonInputSelect/LemonInputSelect.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { IconPencil } from '@posthog/icons'

Check failure on line 1 in frontend/src/lib/lemon-ui/LemonInputSelect/LemonInputSelect.tsx

View workflow job for this annotation

GitHub Actions / Code quality checks

'IconPencil' is declared but its value is never read.
import { Tooltip } from '@posthog/lemon-ui'
import { useKeyHeld } from 'lib/hooks/useKeyHeld'
import { LemonSkeleton } from 'lib/lemon-ui/LemonSkeleton'
Expand All @@ -8,7 +9,7 @@ import { useEffect, useMemo, useRef, useState } from 'react'
import { KeyboardShortcut } from '~/layout/navigation-3000/components/KeyboardShortcut'

import { LemonButton } from '../LemonButton'
import { LemonDropdown } from '../LemonDropdown'
import { LemonDropdown, LemonDropdownProps } from '../LemonDropdown'
import { LemonInput } from '../LemonInput'
import { PopoverReferenceContext } from '../Popover'

Expand All @@ -25,12 +26,12 @@ export type LemonInputSelectProps = {
loading?: boolean
placeholder?: string
disableFiltering?: boolean
disableAltToEdit?: boolean
mode: 'multiple' | 'single'
allowCustomValues?: boolean
onChange?: (newValue: string[]) => void
onInputChange?: (newValue: string) => void
'data-attr'?: string
dropdownProps?: Partial<LemonDropdownProps>
}

export function LemonInputSelect({
Expand All @@ -43,8 +44,8 @@ export function LemonInputSelect({
mode,
disabled,
disableFiltering = false,
disableAltToEdit = false,
allowCustomValues = false,
dropdownProps = {},
...props
}: LemonInputSelectProps): JSX.Element {
const [showPopover, setShowPopover] = useState(false)
Expand Down Expand Up @@ -116,29 +117,50 @@ export function LemonInputSelect({
onInputChange?.(inputValue)
}

const _onActionItem = (item: string): void => {
const _removeItem = (item: string): void => {
let newValues = [...values]
if (values.includes(item)) {
// Remove the item
if (mode === 'single') {
newValues = []
} else {
newValues.splice(values.indexOf(item), 1)
}
// Remove the item
if (mode === 'single') {
newValues = []
} else {
// Add the item
if (mode === 'single') {
newValues = [item]
} else {
newValues.splice(values.indexOf(item), 1)
}

onChange?.(newValues)
}

const _addItem = (item: string): void => {
let newValues = [...values]
// Add the item
if (mode === 'single') {
newValues = [item]
} else {
if (!newValues.includes(item)) {
newValues.push(item)
}

setInputValue('')
}

setInputValue('')
onChange?.(newValues)
}

const _onActionItem = (item: string): void => {
if (altKeyHeld && allowCustomValues) {
// In this case we want to remove it if added and set input to it
if (values.includes(item)) {
_removeItem(item)
}
setInputValue(item)
return
}

if (values.includes(item)) {
_removeItem(item)
} else {
_addItem(item)
}
}

const _onBlur = (): void => {
// We need to add a delay as a click could be in the popover or the input wrapper which refocuses
setTimeout(() => {
Expand All @@ -165,8 +187,8 @@ export function LemonInputSelect({
const _onKeyDown = (e: React.KeyboardEvent<HTMLInputElement>): void => {
if (e.key === 'Enter') {
e.preventDefault()

const itemToAdd = visibleOptions[selectedIndex]?.key

if (itemToAdd) {
_onActionItem(visibleOptions[selectedIndex]?.key)
}
Expand Down Expand Up @@ -196,45 +218,42 @@ export function LemonInputSelect({
label: value,
labelComponent: null,
}
return (
<>
<Tooltip
title={
<>
<KeyboardShortcut option /> + click to edit
</>
}
>
<LemonSnack
title={option?.label}
onClose={() => {
_onActionItem(value)
}}
onClick={() => {
if (altKeyHeld && !disableAltToEdit) {
_onActionItem(value)
setInputValue(value)
}
}}
>
{option?.labelComponent ?? option?.label}
</LemonSnack>
</Tooltip>
</>
const snack = (
<LemonSnack
title={option?.label}
onClose={() => _onActionItem(value)}
onClick={allowCustomValues ? () => _onActionItem(value) : undefined}
>
{option?.labelComponent ?? option?.label}
</LemonSnack>
)
return allowCustomValues ? (
<Tooltip
title={
<>
<KeyboardShortcut option /> + click to edit
</>
}
>
{snack}
</Tooltip>
) : (
snack
)
})}
</>
</PopoverReferenceContext.Provider>
),
[values, options, altKeyHeld, disableAltToEdit]
[values, options, altKeyHeld, allowCustomValues]
)

return (
<LemonDropdown
closeOnClickInside={false}
visible={showPopover}
sameWidth
closeOnClickInside={false}
actionable
{...dropdownProps}
visible={showPopover}
onClickOutside={() => {
popoverFocusRef.current = false
setShowPopover(false)
Expand Down

0 comments on commit f529b5e

Please sign in to comment.