123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139 |
- import {memo, useEffect, useMemo} from 'react';
- import styled from '@emotion/styled';
- import AutoComplete from 'sentry/components/autoComplete';
- import space from 'sentry/styles/space';
- import {Item} from './types';
- type ItemSize = 'zero' | 'small';
- type AutoCompleteChildrenArgs<T extends Item> = Parameters<
- AutoComplete<T>['props']['children']
- >[0];
- type Props<T extends Item> = Pick<
- AutoCompleteChildrenArgs<T>,
- 'getItemProps' | 'registerVisibleItem' | 'inputValue'
- > &
- Omit<Parameters<AutoCompleteChildrenArgs<T>['getItemProps']>[0], 'index'> & {
- /**
- * Is the row 'active'
- */
- isHighlighted: boolean;
- /**
- * Size for dropdown items
- */
- itemSize?: ItemSize;
- /**
- * Style is used by react-virtualized for alignment
- */
- style?: React.CSSProperties;
- };
- function Row<T extends Item>({
- item,
- style,
- itemSize,
- isHighlighted,
- inputValue,
- getItemProps,
- registerVisibleItem,
- }: Props<T>) {
- const {index} = item;
- useEffect(() => registerVisibleItem(item.index, item), [registerVisibleItem, item]);
- const itemProps = useMemo(
- () => getItemProps({item, index}),
- [getItemProps, item, index]
- );
- if (item.groupLabel) {
- return (
- <LabelWithBorder style={style}>
- {item.label && <GroupLabel>{item.label}</GroupLabel>}
- </LabelWithBorder>
- );
- }
- return (
- <AutoCompleteItem
- itemSize={itemSize}
- disabled={item.disabled}
- isHighlighted={isHighlighted}
- style={style}
- {...itemProps}
- >
- {typeof item.label === 'function' ? item.label({inputValue}) : item.label}
- </AutoCompleteItem>
- );
- }
- // XXX(epurkhiser): We memoize the row component since there will be many of
- // them, we do not want them re-rendering every time we change the
- // highlightedIndex in the parent List.
- export default memo(Row);
- const getItemPaddingForSize = (itemSize?: ItemSize) => {
- if (itemSize === 'small') {
- return `${space(0.5)} ${space(1)}`;
- }
- if (itemSize === 'zero') {
- return '0';
- }
- return space(1);
- };
- const LabelWithBorder = styled('div')`
- display: flex;
- align-items: center;
- background-color: ${p => p.theme.backgroundSecondary};
- border-bottom: 1px solid ${p => p.theme.innerBorder};
- border-width: 1px 0;
- color: ${p => p.theme.subText};
- font-size: ${p => p.theme.fontSizeMedium};
- :first-child {
- border-top: none;
- }
- :last-child {
- border-bottom: none;
- }
- `;
- const GroupLabel = styled('div')`
- padding: ${space(0.25)} ${space(1)};
- `;
- const AutoCompleteItem = styled('div')<{
- isHighlighted: boolean;
- disabled?: boolean;
- itemSize?: ItemSize;
- }>`
- position: relative;
- /* needed for virtualized lists that do not fill parent height */
- /* e.g. breadcrumbs (org height > project, but want same fixed height for both) */
- display: flex;
- flex-direction: column;
- justify-content: center;
- scroll-margin: 20px 0;
- font-size: ${p => p.theme.fontSizeMedium};
- background-color: ${p => (p.isHighlighted ? p.theme.hover : 'transparent')};
- color: ${p => (p.isHighlighted ? p.theme.textColor : 'inherit')};
- padding: ${p => getItemPaddingForSize(p.itemSize)};
- cursor: ${p => (p.disabled ? 'not-allowed' : 'pointer')};
- border-bottom: 1px solid ${p => p.theme.innerBorder};
- :last-child {
- border-bottom: none;
- }
- :hover {
- color: ${p => p.theme.textColor};
- background-color: ${p => p.theme.hover};
- }
- `;
|