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

feat(UI): add shared AutoCompleteResult component #12725

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
import { BADGE } from '@geometricpanda/storybook-addon-badges';
import { Meta, StoryObj } from '@storybook/react';
import React from 'react';
import AutoComplete from './AutoComplete';

// Auto Docs
const meta = {
title: 'Components / AutoComplete',
component: AutoComplete,

// Display Properties
parameters: {
layout: 'centered',
badges: [BADGE.STABLE, 'readyForDesignReview'],
docs: {
subtitle: 'This component allows to add autocompletion',
},
},

// Component-level argTypes
argTypes: {
dataTestId: {
description: 'Optional property to set data-testid',
control: 'text',
},
className: {
description: 'Optional class names to pass into AutoComplete',
control: 'text',
},
value: {
description: 'Selected option',
},
defaultValue: {
description: 'Selected option by default',
},
options: {
description: 'Options available in dropdown',
table: {
type: {
summary: 'OptionType',
detail: `{
label: React.ReactNode;
value?: string | number | null;
disabled?: boolean;
[name: string]: any;
children?: Omit<OptionType, 'children'>[];
}
`,
},
},
},
open: {
description: 'Controlled open state of dropdown',
},
defaultActiveFirstOption: {
description: 'Whether active first option by default',
},
filterOption: {
description: 'If true, filter options by input, if function, filter options against it',
},
dropdownContentHeight: {
description: "Height of dropdown's content",
},
onSelect: {
description: 'Called when a option is selected',
},
onSearch: {
description: 'Called when searching items',
},
onChange: {
description: 'Called when selecting an option or changing an input value',
},
onDropdownVisibleChange: {
description: 'Called when dropdown opened/closed',
},
dropdownRender: {
description: 'Customize dropdown content',
},
style: {
description: 'Additional styles for the wrapper of the children',
},
dropdownStyle: {
description: 'Additional styles for the dropdown',
},
showWrapping: {
description: 'Whether to add a wrapper around the children and the dropdown',
},
},

// Define defaults
args: {
options: [
{ label: 'test', value: 'test' },
{ label: 'test2', value: 'test2' },
],
},
} satisfies Meta<typeof AutoComplete>;

export default meta;

// Stories

type Story = StoryObj<typeof meta>;

// Basic story is what is displayed 1st in storybook & is used as the code sandbox
// Pass props to this so that it can be customized via the UI props panel
export const sandbox: Story = {
tags: ['dev'],
render: (props) => (
<AutoComplete {...props}>
<input />
</AutoComplete>
),
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
import { AutoComplete as AntdAutoComplete } from 'antd';
import React from 'react';
import { colors, spacing } from '@src/alchemy-components/theme';
import radius from '@src/alchemy-components/theme/foundations/radius';
import { BOX_SHADOW, ChildrenWrapper, DropdownWrapper } from './components';
import { AutoCompleteProps } from './types';

// Additional offset to handle wrapper's padding (when `showWrapping` is enabled)
const DROPDOWN_ALIGN_WITH_WRAPPING = { offset: [0, -8] };

export default function AutoComplete({
children,
showWrapping,
dropdownContentHeight,
dataTestId,
...props
}: React.PropsWithChildren<AutoCompleteProps>) {
const { open } = props;

return (
<div>
<AntdAutoComplete
{...props}
listHeight={dropdownContentHeight}
data-testid={dataTestId}
dropdownRender={(menu) => {
return <DropdownWrapper>{props?.dropdownRender?.(menu) ?? menu}</DropdownWrapper>;
}}
dropdownAlign={{ ...(showWrapping ? DROPDOWN_ALIGN_WITH_WRAPPING : {}) }}
dropdownStyle={{
...(showWrapping
? {
padding: spacing.xsm,
borderRadius: `${radius.none} ${radius.none} ${radius.lg} ${radius.lg}`,
backgroundColor: colors.gray[1500],
boxShadow: BOX_SHADOW,
}
: { borderRadius: radius.lg }),
...(props?.dropdownStyle ?? {}),
}}
>
<ChildrenWrapper $open={open} $showWrapping={showWrapping}>
{children}
</ChildrenWrapper>
</AntdAutoComplete>
</div>
);
}

Check warning on line 48 in datahub-web-react/src/alchemy-components/components/AutoComplete/AutoComplete.tsx

View check run for this annotation

Codecov / codecov/patch

datahub-web-react/src/alchemy-components/components/AutoComplete/AutoComplete.tsx#L11-L48

Added lines #L11 - L48 were not covered by tests
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { colors, radius, transition } from '@src/alchemy-components/theme';
import styled from 'styled-components';

export const BOX_SHADOW = `0px -3px 12px 0px rgba(236, 240, 248, 0.5) inset,
0px 3px 12px 0px rgba(255, 255, 255, 0.5) inset,
0px 20px 60px 0px rgba(0, 0, 0, 0.12)`;

export const DropdownWrapper = styled.div`
& .rc-virtual-list-scrollbar-thumb {
background: rgba(193, 196, 208, 0.8) !important;
}
& .rc-virtual-list-scrollbar-show {
background: rgba(193, 196, 208, 0.3) !important;
}

background: ${colors.white};
border-radius: ${radius.lg};
box-shadow: ${BOX_SHADOW};
backdrop-filter: blur(20px);
`;

export const ChildrenWrapper = styled.div<{ $open?: boolean; $showWrapping?: boolean }>`
background: transparent;

${(props) =>
props.$showWrapping &&
`
padding: ${radius.md};
transition: all ${transition.easing['ease-in']} ${transition.duration.slow};
border-radius: ${radius.lg} ${radius.lg} ${radius.none} ${radius.none};

Check warning on line 30 in datahub-web-react/src/alchemy-components/components/AutoComplete/components.tsx

View check run for this annotation

Codecov / codecov/patch

datahub-web-react/src/alchemy-components/components/AutoComplete/components.tsx#L26-L30

Added lines #L26 - L30 were not covered by tests
`}

${(props) =>
props.$open &&
props.$showWrapping &&
`
background: ${colors.gray[1500]};
box-shadow: ${BOX_SHADOW};

Check warning on line 38 in datahub-web-react/src/alchemy-components/components/AutoComplete/components.tsx

View check run for this annotation

Codecov / codecov/patch

datahub-web-react/src/alchemy-components/components/AutoComplete/components.tsx#L34-L38

Added lines #L34 - L38 were not covered by tests
`}
`;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
import AutoComplete from './AutoComplete';

export { AutoComplete };
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import React from 'react';
import { DefaultOptionType } from 'antd/lib/select';

export type ValueType = string;
export type OptionType = DefaultOptionType;
export interface AutoCompleteProps {
dataTestId?: string;
className?: string;

value?: ValueType;
defaultValue?: ValueType;
options: OptionType[];
open?: boolean;

defaultActiveFirstOption?: boolean;
filterOption?: boolean | ((inputValue: ValueType, option?: OptionType) => boolean);
dropdownContentHeight?: number;

onSelect?: (value: ValueType, option: OptionType) => void;
onSearch?: (value: ValueType) => void;
onChange?: (value: ValueType, option: OptionType | OptionType[]) => void;
onDropdownVisibleChange?: (isOpen: boolean) => void;

dropdownRender?: (menu: React.ReactElement) => React.ReactElement | undefined;

style?: React.CSSProperties;
dropdownStyle?: React.CSSProperties;

showWrapping?: boolean;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
import React from 'react';

import type { Meta, StoryObj } from '@storybook/react';
import { BADGE } from '@geometricpanda/storybook-addon-badges';

import MatchText from './MatchText';
import { matchTextDefaults } from './defaults';

// Auto Docs
const meta = {
title: 'Typography / MatchText',
component: MatchText,

// Display Properties
parameters: {
layout: 'centered',
badges: [BADGE.STABLE, 'readyForDesignReview'],
docs: {
subtitle: 'Used to highlight text parts dynamically',
},
},

// Component-level argTypes
argTypes: {
text: {
description: 'The initial text to matching',
table: {
type: {
summary: 'string',
},
},
},
highlight: {
description: 'The text to highlight',
table: {
type: {
summary: 'string',
},
},
},
type: {
description: 'The type of text to display.',
table: {
defaultValue: { summary: matchTextDefaults.type },
},
},
size: {
description: 'Override the size of the text.',
table: {
defaultValue: { summary: `${matchTextDefaults.size}` },
},
},
color: {
description: 'Override the color of the text.',
table: {
defaultValue: { summary: matchTextDefaults.color },
},
},
weight: {
description: 'Override the weight of the text.',
table: {
defaultValue: { summary: matchTextDefaults.weight },
},
},
highlightedTextProps: {
description: 'Overide text props for highlighted parts',
table: {
defaultValue: { summary: JSON.stringify(matchTextDefaults.highlightedTextProps) },
},
},
},

// Define default args
args: {
text: `Lorem ipsum dolor sit amet, consectetur adipiscing elit.
Maecenas aliquet nulla id felis vehicula, et posuere dui dapibus.
Nullam rhoncus massa non tortor convallis, in blandit turpis rutrum.
Morbi tempus velit mauris, at mattis metus mattis sed. Nunc molestie efficitur lectus, vel mollis eros.`,
highlight: 'ipsum',
type: matchTextDefaults.type,
size: matchTextDefaults.size,
color: matchTextDefaults.color,
weight: matchTextDefaults.weight,
highlightedTextProps: matchTextDefaults.highlightedTextProps,
},
} satisfies Meta<typeof MatchText>;

export default meta;

// Stories

type Story = StoryObj<typeof meta>;

// Basic story is what is displayed 1st in storybook
// Pass props to this so that it can be customized via the UI props panel
export const sandbox: Story = {
tags: ['dev'],
render: (props) => <MatchText {...props} />,
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import React from 'react';
import { Text } from '../Text';
import { matchTextDefaults } from './defaults';
import { MatchTextProps } from './types';
import { annotateHighlightedText } from './utils';

export default function MatchText({
text,
highlight,
highlightedTextProps = matchTextDefaults.highlightedTextProps,
...props
}: MatchTextProps) {
const markedTextParts = annotateHighlightedText(text, highlight);

return (
<Text {...props}>
{markedTextParts.map((part) => {
if (part.highlighted)
return (
<Text {...{ ...props, ...highlightedTextProps }} type="span">
{part.text}
</Text>
);
return part.text;
})}
</Text>
);
}

Check warning on line 28 in datahub-web-react/src/alchemy-components/components/MatchText/MatchText.tsx

View check run for this annotation

Codecov / codecov/patch

datahub-web-react/src/alchemy-components/components/MatchText/MatchText.tsx#L7-L28

Added lines #L7 - L28 were not covered by tests
Loading
Loading