Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore: cascader updates #378

Merged
merged 32 commits into from
Sep 17, 2024
Merged
Show file tree
Hide file tree
Changes from 30 commits
Commits
Show all changes
32 commits
Select commit Hold shift + click to select a range
f80ea27
feat: adds README for UPS (#302)
Seebiscuit Jun 27, 2024
0550de6
chore: add autoFocus to queryItem numberInput (#313)
jared-dickman Jun 27, 2024
36a2fd1
Merge branch 'main' of github.com:mParticle/aquarium
jared-dickman Jul 31, 2024
ff5f5e9
Merge branch 'main' of github.com:mParticle/aquarium
jared-dickman Jul 31, 2024
2d1625f
Merge branch 'main' of github.com:mParticle/aquarium
jared-dickman Aug 7, 2024
61b75ca
Merge remote-tracking branch 'origin/main'
jared-dickman Aug 22, 2024
2cd11a8
Merge branch 'main' of github.com:mParticle/aquarium
jared-dickman Aug 26, 2024
16f9d0d
fix: allow any component as a Label, include placement prop in base c…
jared-dickman Aug 26, 2024
d5230c4
chore(release): 1.29.0-chore-cascader-updates.1 [skip ci]
mparticle-automation Aug 26, 2024
bb80cdc
feat: add searchLabel to queryItemCascader, and defaultOpen prop
jared-dickman Aug 29, 2024
642ff85
Merge branch 'chore/cascader-updates' of github.com:mParticle/aquariu…
jared-dickman Aug 29, 2024
c6c7591
chore(release): 1.29.0-chore-cascader-updates.2 [skip ci]
mparticle-automation Aug 29, 2024
b2df338
chore: allow searchLabel to be optional
jared-dickman Aug 29, 2024
1f708db
Merge branch 'chore/cascader-updates' of github.com:mParticle/aquariu…
jared-dickman Aug 29, 2024
3f4ddfe
chore(release): 1.29.0-chore-cascader-updates.3 [skip ci]
mparticle-automation Aug 29, 2024
8e559e3
chore: autofocus input, and allow searchLabel when using ReactNode as…
jared-dickman Aug 29, 2024
fc1a1ea
Merge branch 'chore/cascader-updates' of github.com:mParticle/aquariu…
jared-dickman Aug 29, 2024
369bab9
chore(release): 1.29.0-chore-cascader-updates.4 [skip ci]
mparticle-automation Aug 29, 2024
b691903
fix: input display when selecting a reactNode label
jared-dickman Aug 30, 2024
841075f
Merge branch 'chore/cascader-updates' of github.com:mParticle/aquariu…
jared-dickman Aug 30, 2024
abcc0fe
chore(release): 1.29.0-chore-cascader-updates.5 [skip ci]
mparticle-automation Aug 30, 2024
8ba50b7
Merge remote-tracking branch 'origin/main' into chore/cascader-updates
jared-dickman Aug 30, 2024
ebdf18d
chore(release): 1.30.0-chore-cascader-updates.1 [skip ci]
mparticle-automation Aug 30, 2024
41d0e90
Merge remote-tracking branch 'origin/main' into chore/cascader-updates
jared-dickman Sep 5, 2024
e333ab9
Merge branch 'chore/cascader-updates' of github.com:mParticle/aquariu…
jared-dickman Sep 5, 2024
e79e471
chore(release): 1.31.0-chore-cascader-updates.1 [skip ci]
mparticle-automation Sep 5, 2024
6489fd0
Merge remote-tracking branch 'origin/main' into chore/cascader-updates
jared-dickman Sep 10, 2024
6579601
Merge branch 'chore/cascader-updates' of github.com:mParticle/aquariu…
jared-dickman Sep 10, 2024
868095f
chore(release): 1.31.0-chore-cascader-updates.2 [skip ci]
mparticle-automation Sep 10, 2024
ca87ecb
Merge branch 'chore/cascader-updates' of github.com:mParticle/aquariu…
jared-dickman Sep 10, 2024
4381eff
Merge branch 'main' into chore/cascader-updates
jared-dickman Sep 12, 2024
90cfbcf
Merge branch 'main' into chore/cascader-updates
jared-dickman Sep 17, 2024
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
34 changes: 33 additions & 1 deletion src/components/data-entry/QueryItem/Cascader.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type Meta, type StoryObj } from '@storybook/react'
import { type IQueryItemCascaderProps, QueryItem } from 'src/components'
import { Flex, Icon, type IQueryItemCascaderProps, QueryItem, Typography } from 'src/components'

const options: IQueryItemCascaderProps['options'] = [
{
Expand Down Expand Up @@ -151,3 +151,35 @@ export const Loading: Story = {
},
},
}

export const SearchLabel: Story = {
args: {
options: [
...options,
{
value: 'G',
label: 'G',
children: [
{
value: 'H',
label: 'H',
children: [
{
value: 'IJK',
label: (
<>
<Flex>
<Icon name="alicorn" />
<Typography.Text>IJK</Typography.Text>
</Flex>
</>
),
searchLabel: 'IJK',
},
],
},
],
},
],
},
}
60 changes: 32 additions & 28 deletions src/components/data-entry/QueryItem/Cascader.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/* eslint-disable @typescript-eslint/no-use-before-define */
import './query-item.css'
import { type GetProp } from 'antd'
import { type DefaultOptionType } from 'antd/es/select'
import { type ReactNode, useCallback, useEffect, useState } from 'react'
import {
Cascader as BaseCascader,
Expand All @@ -15,9 +16,10 @@ import { type Icons } from 'src/constants/Icons'
import { useMount } from 'src/hooks/useMount'
import { debounce } from 'src/utils/utils'

export interface ICascaderOption {
export interface ICascaderOption extends DefaultOptionType {
value: string
label: string
label: ReactNode
searchLabel?: string // useful when label is a reactNode and not a string
danielsiemens marked this conversation as resolved.
Show resolved Hide resolved
children?: ICascaderOption[]
disabled?: boolean
}
Expand All @@ -31,18 +33,20 @@ export interface IQueryItemCascaderProps {
loadData?: (value: string) => Promise<void>
value?: Array<number | string>
disabled?: boolean
placement?: IBaseCascaderProps['placement']
defaultOpen?: IBaseCascaderProps['defaultOpen']
}

const Cascader = (props: IQueryItemCascaderProps) => {
type DefaultOptionType = GetProp<IBaseCascaderProps, 'options'>[number]
type ICascaderOption = GetProp<IBaseCascaderProps, 'options'>[number]

const options: ICascaderOption[] = []
const [items, setItems] = useState(props.options ?? options)
const [searchValue, setSearchValue] = useState('')
const [isLoading, setIsLoading] = useState(false)
const [selectedValue, setSelectedValue] = useState<Array<number | string>>(props.value ?? [])
const [selectedDisplayValue, setSelectedDisplayValue] = useState(
props.value && props.value.length > 0 ? (props.value.slice(-1)[0] as any).label : '',
const [selectedOption, setSelectedOption] = useState<ICascaderOption>(
props.value?.length ? props.value.slice(-1)[0] : undefined,
)
const [isOpen, setIsOpen] = useState(false)

Expand Down Expand Up @@ -79,9 +83,11 @@ const Cascader = (props: IQueryItemCascaderProps) => {
setSearchValue(value)
}

const filter = (inputValue: string, path: DefaultOptionType[]) => {
return path.some(option => (option.label as string).toLowerCase().includes(inputValue.toLowerCase()))
}
const getSearchValue = (option: ICascaderOption): string =>
option.searchLabel ?? (typeof option.label === 'string' ? (option.label as string) : '')

const filter = (inputValue: string, path: ICascaderOption[]) =>
path.some(option => getSearchValue(option).toLowerCase().includes(inputValue.toLowerCase()))

let debouncedLoadData: (value: string) => void
if (props.loadData) {
Expand All @@ -98,9 +104,11 @@ const Cascader = (props: IQueryItemCascaderProps) => {
searchValue,
disabled: props.disabled,
value: selectedValue,
defaultOpen: props.defaultOpen,
placement: props.placement ?? 'bottomLeft',
onChange: (values: Array<number | string>, selectedOptions: any): void => {
setSelectedValue(values as string[])
setSelectedDisplayValue(selectedOptions.slice(-1)[0].label)
setSelectedOption(selectedOptions.slice(-1)[0])
void props.onChange?.(values, selectedOptions)
},
dropdownRender: menu => (
Expand All @@ -111,6 +119,7 @@ const Cascader = (props: IQueryItemCascaderProps) => {
<>
<Input
allowClear
autoFocus
value={searchValue}
className="query-item__input-search"
placeholder="Search"
Expand All @@ -125,18 +134,16 @@ const Cascader = (props: IQueryItemCascaderProps) => {
),
showSearch: {
filter,
render: (inputValue: string, paths: ICascaderOption[]): ReactNode => {
return (
<>
{paths.map((path: ICascaderOption, index) => (
<>
{highlightMatches(path.label, inputValue.toLowerCase())}
{index < paths.length - 1 ? ' > ' : ''}
</>
))}
</>
)
},
render: (inputValue: string, options: ICascaderOption[]): ReactNode => (
<>
{options.map((option: ICascaderOption, index) => (
<>
{highlightMatches(getSearchValue(option), inputValue.toLowerCase())}
{index < options.length - 1 ? ' > ' : ''}
</>
))}
</>
),
},
options: items,
onDropdownVisibleChange: value => {
Expand All @@ -149,7 +156,7 @@ const Cascader = (props: IQueryItemCascaderProps) => {
if (isOpen) inputClasses += ' query-item--open'
if (selectedValue && selectedValue.length !== 0) inputClasses += ' query-item--selected'
if (props.errorMessage) inputClasses += ' query-item--error'
const displayValue = selectedDisplayValue ?? selectedValue.slice(-1)
const displayValue = (selectedOption ? getSearchValue(selectedOption) : selectedValue.slice(-1)) as string

return (
<>
Expand All @@ -164,7 +171,7 @@ const Cascader = (props: IQueryItemCascaderProps) => {
prefix={getIcon()}
/>
</BaseCascader>
{props.errorMessage && <Typography.Text type={'danger'}>{props.errorMessage}</Typography.Text>}
{props.errorMessage && <Typography.Text type="danger">{props.errorMessage}</Typography.Text>}
</>
)

Expand All @@ -189,11 +196,8 @@ const Cascader = (props: IQueryItemCascaderProps) => {
)
}

function transformOptionsToPaths(
options: DefaultOptionType[],
prefixPath: DefaultOptionType[],
): DefaultOptionType[][] {
let result: DefaultOptionType[][] = []
function transformOptionsToPaths(options: ICascaderOption[], prefixPath: ICascaderOption[]): ICascaderOption[][] {
let result: ICascaderOption[][] = []
options.forEach(option => {
if (option.children && option.children.length > 0) {
const newPrefix = prefixPath.concat([{ label: option.label, value: option.value }])
Expand Down
Loading