Skip to content

Commit

Permalink
feat: Enable titleContent for ComboBoxes (#548)
Browse files Browse the repository at this point in the history
  • Loading branch information
dogmar authored Dec 13, 2023
1 parent b00948e commit 460ca22
Show file tree
Hide file tree
Showing 3 changed files with 161 additions and 107 deletions.
41 changes: 16 additions & 25 deletions src/components/ComboBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,9 @@ type ComboBoxProps = Exclude<ComboBoxInputProps, 'children'> & {
inputProps?: InputProps
filter?: ComboBoxStateOptions<object>['defaultFilter']
loading?: boolean
} & Omit<
titleContent?: ReactNode
} & Pick<InputProps, 'suffix' | 'prefix' | 'titleContent' | 'showClearButton'> &
Omit<
ComboBoxStateOptions<object>,
'onLoadMore' | 'isLoading' | 'validationState' | 'placeholder'
>
Expand Down Expand Up @@ -152,6 +154,7 @@ function ComboBoxInput({
isOpen,
onInputClick,
loading,
...props
}: ComboBoxInputProps & InputProps) {
outerInputProps = {
...outerInputProps,
Expand All @@ -170,37 +173,16 @@ function ComboBoxInput({

let themeExtension: any = {}

if (startIcon) {
themeExtension = mergeTheme(themeExtension, {
Input: {
Root: [
{
position: 'relative',
paddingLeft: 0,
},
],
InputBase: [{ paddingLeft: theme.spacing.xxlarge }],
StartIcon: [
{
position: 'absolute',
top: 0,
left: 0,
bottom: 0,
pointerEvents: 'none',
},
],
},
})
}

if (showArrow) {
themeExtension = mergeTheme(themeExtension, {
Input: {
Root: [{ paddingRight: 0 }],
InputBase: [{ paddingRight: 0 }],
EndIcon: [
{
alignSelf: 'stretch',
paddingHorizontal: 0,
paddingLeft: 0,
paddingRight: 0,
marginLeft: 0,
marginRight: 0,
},
Expand Down Expand Up @@ -230,6 +212,7 @@ function ComboBoxInput({
...innerInputProps,
}}
{...outerInputProps}
{...props}
/>
)
}
Expand Down Expand Up @@ -258,6 +241,10 @@ function ComboBox({
maxHeight,
inputProps: outerInputProps = {},
loading,
suffix,
prefix,
titleContent,
showClearButton,
...props
}: ComboBoxProps) {
const nextFocusedKeyRef = useRef<Key>(null)
Expand Down Expand Up @@ -406,6 +393,10 @@ function ComboBox({
buttonProps={buttonProps}
showArrow={showArrow}
isOpen={state.isOpen}
suffix={suffix}
prefix={prefix}
titleContent={titleContent}
showClearButton={showClearButton}
setIsOpen={setIsOpen}
startIcon={startIcon}
outerInputProps={outerInputProps}
Expand Down
2 changes: 1 addition & 1 deletion src/components/Table.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export type TableProps = Omit<
| 'scrollTopMargin'
| 'virtualizeRows'
| 'virtualizerOptions'
| 'lockColumnsOnFirstScroll'
| 'lockColumnsOnScroll'
| 'reactVirtualOptions'
| 'reactTableOptions'
| 'onRowClick'
Expand Down
225 changes: 144 additions & 81 deletions src/stories/ComboBox.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import Fuse from 'fuse.js'

import {
AppIcon,
BrowseAppsIcon,
Card,
Chip,
ComboBox,
Expand Down Expand Up @@ -171,14 +172,24 @@ const itemsByKey = items.reduce(
)
const itemKeys = items.map((item) => item.key)

const TagPicker = styled.div(({ theme: _theme }) => ({}))
const TagPicker = styled.div(({ theme }) => ({
display: 'flex',
flexDirection: 'column',
gap: theme.spacing.small,
}))

const ChipList = styled(ListBoxItemChipList)(({ theme }) => ({
marginTop: theme.spacing.small,
const ChipList = styled(ListBoxItemChipList)(({ theme: _ }) => ({
justifyContent: 'start',
}))

function Template({ onFillLevel, ...args }: { onFillLevel: any }) {
function Template({
onFillLevel,
withTitleContent,
...args
}: {
onFillLevel: any
withTitleContent: boolean
}) {
const [selectedKeys, setSelectedKeys] = useState(new Set<Key>())
const [inputValue, setInputValue] = useState('')

Expand Down Expand Up @@ -241,7 +252,19 @@ function Template({ onFillLevel, ...args }: { onFillLevel: any }) {
inputValue={inputValue}
onSelectionChange={onSelectionChange}
onInputChange={onInputChange}
inputProps={{ placeholder: 'Pick something' }}
inputProps={{
placeholder: 'Pick something',
}}
{...(withTitleContent
? {
titleContent: (
<>
<BrowseAppsIcon marginRight="small" />
Marketplace
</>
),
}
: {})}
{...args}
>
{searchResults.map(
Expand All @@ -257,31 +280,40 @@ function Template({ onFillLevel, ...args }: { onFillLevel: any }) {
)
)}
</ComboBox>
<ChipList
maxVisible={Infinity}
chips={[...selectedKeys].map((key) => (
<Chip
size="small"
clickable
onClick={() => {
const newKeys = new Set(selectedKeys)

newKeys.delete(key)
setSelectedKeys(newKeys)
}}
closeButton
>
{(itemsByKey as any)[key]?.label}
</Chip>
))}
/>
{!(selectedKeys.size === 0) && (
<ChipList
maxVisible={Infinity}
chips={[...selectedKeys].map((key) => (
<Chip
size="small"
clickable
onClick={() => {
const newKeys = new Set(selectedKeys)

newKeys.delete(key)
setSelectedKeys(newKeys)
}}
closeButton
>
{(itemsByKey as any)[key]?.label}
</Chip>
))}
/>
)}
</TagPicker>
</Flex>
</WrapWithIf>
)
}

function TagsTemplate({ ...args }: any) {
function TagsTemplate({
onFillLevel,
withTitleContent,
...args
}: {
onFillLevel: any
withTitleContent: boolean
}) {
const [selectedKeys, setSelectedKeys] = useState(new Set<Key>())
const [inputValue, setInputValue] = useState('')
const [isOpen, setIsOpen] = useState(false)
Expand Down Expand Up @@ -344,74 +376,105 @@ function TagsTemplate({ ...args }: any) {
}

return (
<Flex
flexDirection="column"
gap="large"
maxWidth={512}
<WrapWithIf
condition={onFillLevel > 0}
wrapper={
<Card
display="flex"
flexDirection="column"
gap="large"
padding="large"
fillLevel={onFillLevel}
/>
}
>
<TagPicker>
<ComboBox
isOpen={isOpen}
inputValue={inputValue}
onSelectionChange={onSelectionChange}
onFooterClick={() => {
setSelectedKeys(new Set([...selectedKeys, newKey]))
setInputValue('')
setIsOpen(false)
}}
onInputChange={onInputChange}
inputProps={{ placeholder: 'Pick something' }}
onOpenChange={(isOpen, _trigger) => {
setIsOpen(isOpen)
}}
dropdownFooter={
newKey ? (
<ListBoxFooterPlus>Create new tag, '{newKey}'</ListBoxFooterPlus>
) : undefined
}
maxHeight={232}
allowsEmptyCollection={!!newKey}
{...args}
>
{searchResults.map(({ item, score: _score, refIndex: _refIndex }) => (
<ListBoxItem
key={item.key}
label={item.key}
textValue={`${item.key}`}
selected={selectedKeys.has(item.key)}
<Flex
flexDirection="column"
gap="large"
maxWidth={512}
>
<TagPicker>
<ComboBox
isOpen={isOpen}
inputValue={inputValue}
onSelectionChange={onSelectionChange}
onFooterClick={() => {
setSelectedKeys(new Set([...selectedKeys, newKey]))
setInputValue('')
setIsOpen(false)
}}
onInputChange={onInputChange}
inputProps={{ placeholder: 'Pick something' }}
onOpenChange={(isOpen, _trigger) => {
setIsOpen(isOpen)
}}
dropdownFooter={
newKey ? (
<ListBoxFooterPlus>
Create new tag, '{newKey}'
</ListBoxFooterPlus>
) : undefined
}
maxHeight={232}
allowsEmptyCollection={!!newKey}
{...(withTitleContent
? {
titleContent: (
<>
<BrowseAppsIcon marginRight="small" />
Marketplace
</>
),
}
: {})}
{...args}
>
{searchResults.map(
({ item, score: _score, refIndex: _refIndex }) => (
<ListBoxItem
key={item.key}
label={item.key}
textValue={`${item.key}`}
selected={selectedKeys.has(item.key)}
/>
)
)}
</ComboBox>
{!(selectedKeys.size === 0) && (
<ChipList
maxVisible={Infinity}
chips={[...selectedKeys].map((key) => (
<Chip
size="small"
clickable
onClick={() => {
const newKeys = new Set(selectedKeys)

newKeys.delete(key)
setSelectedKeys(newKeys)
}}
closeButton
>
{key}
</Chip>
))}
/>
))}
</ComboBox>
<ChipList
maxVisible={Infinity}
chips={[...selectedKeys].map((key) => (
<Chip
size="small"
clickable
onClick={() => {
const newKeys = new Set(selectedKeys)

newKeys.delete(key)
setSelectedKeys(newKeys)
}}
closeButton
>
{key}
</Chip>
))}
/>
</TagPicker>
</Flex>
)}
</TagPicker>
</Flex>
</WrapWithIf>
)
}

export const Default = Template.bind({})

Default.args = {
loading: false,
withTitleContent: false,
}

export const Tags = TagsTemplate.bind({})
Default.args = {
Tags.args = {
loading: false,
withTitleContent: false,
}

0 comments on commit 460ca22

Please sign in to comment.