Skip to content

Commit

Permalink
feat(select): popoverPosition, render to body, test issues (#428)
Browse files Browse the repository at this point in the history
* feat(select): add popoverPosition

* refactor(picker-button): popover position, tests and fixes (#429)

* feat(select): add preventFlip prop

* feat(select): render to body, calc options list width

* feat(intl-phone-input): prevent flip, calc options list width

* test(picker-button): update tests

* fix(select): use root ref for width, fix menu closing

* feat(select): testing issues

* fix(select): bulletproof isOptionShape, z-index

* chore(select): update storybook
  • Loading branch information
reme3d2y committed Dec 30, 2020
1 parent b2caa05 commit 7688ec7
Show file tree
Hide file tree
Showing 23 changed files with 1,106 additions and 381 deletions.
9 changes: 5 additions & 4 deletions .storybook/public/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -189,7 +189,7 @@ div.benefits {
counter-reset: item;

border: solid #e7e8ea;
border-width: 1px 1px 0 1px;
border-width: 1px 1px 0;
border-radius: 0 44px 0 0;
}

Expand Down Expand Up @@ -309,6 +309,7 @@ h2.sbdocs-h2:first-of-type {
margin: 48px -16px 16px;
padding: 12px 16px;
color: rgba(11, 31, 53, 1);

/* font-size: 24px; */
font-size: 24px;
line-height: 1.2;
Expand Down Expand Up @@ -681,8 +682,8 @@ span.lib-title__line:before {
position: relative;
padding: 12px 86px 14px 16px;
border: solid #e7e8ea;
border-width: 0 1px 1px 1px;
border-radius: 0 0 44px 0;
border-width: 0 1px 1px;
border-radius: 0 0 44px;
}

span.lib-desc__about {
Expand Down Expand Up @@ -771,7 +772,7 @@ div.lib-welcome {
justify-content: center;
align-items: center;
border: solid #e7e8ea;
border-width: 0 1px 1px 1px;
border-width: 0 1px 1px;
box-sizing: border-box;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,12 +39,6 @@ exports[`IntlPhoneInput should match snapshot 1`] = `
/>
</div>
</div>
<div
aria-labelledby="downshift-1-label"
class="listWrapper"
id="downshift-1-menu"
role="listbox"
/>
</div>
</div>
<div
Expand Down
44 changes: 25 additions & 19 deletions packages/intl-phone-input/src/component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -17,25 +17,23 @@ const countriesHash = getCountriesHash();

const MAX_DIAL_CODE_LENGTH = 4;

export type IntlPhoneInputProps = Omit<
InputProps,
'value' | 'onChange' | 'type' | 'defaultValue'
> & {
/**
* Значение
*/
value: string;

/**
* Обработчик события изменения значения
*/
onChange: (value: string) => void;

/**
* Дефолтный код страны
*/
defaultCountryIso2?: string;
};
export type IntlPhoneInputProps = Omit<InputProps, 'value' | 'onChange' | 'type' | 'defaultValue'> &
Pick<SelectProps, 'preventFlip'> & {
/**
* Значение
*/
value: string;

/**
* Обработчик события изменения значения
*/
onChange: (value: string) => void;

/**
* Дефолтный код страны
*/
defaultCountryIso2?: string;
};

export const IntlPhoneInput = forwardRef<HTMLInputElement, IntlPhoneInputProps>(
(
Expand All @@ -46,13 +44,15 @@ export const IntlPhoneInput = forwardRef<HTMLInputElement, IntlPhoneInputProps>(
value,
onChange,
defaultCountryIso2 = 'ru',
preventFlip,
...restProps
},
ref,
) => {
const [countryIso2, setCountryIso2] = useState(defaultCountryIso2);

const inputRef = useRef<HTMLInputElement>(null);
const inputWrapperRef = useRef<HTMLDivElement>(null);

const phoneLibUtils = useRef<typeof AsYouType>();

Expand Down Expand Up @@ -175,6 +175,7 @@ export const IntlPhoneInput = forwardRef<HTMLInputElement, IntlPhoneInputProps>(
value={value}
type='tel'
ref={mergeRefs([inputRef, ref])}
wrapperRef={inputWrapperRef}
className={cn(className, styles[size])}
addonsClassName={styles.addons}
size={size}
Expand All @@ -186,6 +187,11 @@ export const IntlPhoneInput = forwardRef<HTMLInputElement, IntlPhoneInputProps>(
selected={countryIso2}
countries={countries}
onChange={handleSelectChange}
fieldWidth={
inputWrapperRef.current &&
inputWrapperRef.current.getBoundingClientRect().width
}
preventFlip={preventFlip}
/>
}
/>
Expand Down
23 changes: 17 additions & 6 deletions packages/intl-phone-input/src/components/select/component.tsx
Original file line number Diff line number Diff line change
@@ -1,26 +1,26 @@
import React, { FC, useMemo } from 'react';
import React, { FC, useCallback, useMemo } from 'react';

import { Select, SelectProps } from '@alfalab/core-components-select';
import { OptionsList, Select, SelectProps } from '@alfalab/core-components-select';
import { Country } from '@alfalab/utils';

import { SelectField } from '../select-field';
import { FlagIcon } from '../flag-icon';

import styles from './index.module.css';

type CountriesSelectProps = {
disabled: boolean;
size: SelectProps['size'];
type CountriesSelectProps = Pick<SelectProps, 'size' | 'disabled' | 'onChange' | 'preventFlip'> & {
selected: string;
countries: Country[];
onChange: SelectProps['onChange'];
fieldWidth: number | null;
};

export const CountriesSelect: FC<CountriesSelectProps> = ({
disabled,
size,
selected,
countries,
fieldWidth,
preventFlip,
onChange,
}) => {
const options = useMemo(
Expand All @@ -42,6 +42,15 @@ export const CountriesSelect: FC<CountriesSelectProps> = ({
[countries],
);

const renderOptionsList = useCallback(
props => (
<div style={{ width: fieldWidth || 0 }}>
<OptionsList {...props} />
</div>
),
[fieldWidth],
);

return (
<Select
disabled={disabled}
Expand All @@ -50,6 +59,8 @@ export const CountriesSelect: FC<CountriesSelectProps> = ({
selected={selected}
onChange={onChange}
Field={SelectField}
OptionsList={renderOptionsList}
preventFlip={preventFlip}
className={styles.component}
/>
);
Expand Down
51 changes: 34 additions & 17 deletions packages/picker-button/src/Component.stories.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,9 @@ import { PickerButton } from '@alfalab/core-components-picker-button';
};
const CustomOptionList = (props) => (
<div>
<span style={{ display: 'inline-block', color: '#b6bcc3', fontSize: '14px', padding: '16px 24px' }}>Выберите счёт получателя</span>
<span style={{ display: 'inline-block', color: '#b6bcc3', fontSize: '14px', padding: '16px 24px' }}>
Выберите счёт получателя
</span>
<OptionsList {...props} />
</div>
);
Expand All @@ -133,30 +135,45 @@ import { PickerButton } from '@alfalab/core-components-picker-button';
size='s'
view='primary'
allowUnselect={true}
popoverPosition='bottom-end'
/>
);
})}
</div>

### Разные размеры
<div style={containerStyle}>
<PickerButton label='Secondary xs' options={options} size='xs' />
<PickerButton label='Secondary s' options={options} size='s' />
<PickerButton label='Secondary m' options={options} size='m' />
</div>

<Preview>
<div style={containerStyle}>
<PickerButton label='Secondary xs' options={options} size='xs' />
<PickerButton label='Secondary s' options={options} size='s' />
<PickerButton label='Secondary m' options={options} size='m' />
</div>
</Preview>

### Разные типы кнопок
<div style={containerStyle}>
<PickerButton label='Primary m' options={options} view='primary' />
<PickerButton label='Outlined m' options={options} view='outlined' />
<PickerButton label='Ghost m' options={options} view='ghost' />
</div>
<Preview>
<div style={containerStyle}>
<PickerButton label='Primary m' options={options} view='primary' />
<PickerButton label='Outlined m' options={options} view='outlined' />
<PickerButton label='Ghost m' options={options} view='ghost' />
</div>
</Preview>

### Разные состояния кнопок
<div style={containerStyle}>
<PickerButton label='Secondary disabled' options={options} disabled={true} />
<PickerButton label='Secondary loading' options={options} loading={true} />
</div>
<Preview>
<div style={containerStyle}>
<PickerButton label='Secondary disabled' options={options} disabled={true} />
<PickerButton label='Secondary loading' options={options} loading={true} />
</div>
</Preview>

### Позиционирование меню
<Preview>
<div style={containerStyle}>
<PickerButton label='start' options={options} popoverPosition='bottom-start' size='xs' />
<PickerButton label='center' options={options} popoverPosition='bottom' size='xs'/>
<PickerButton label='end' options={options} popoverPosition='bottom-end' size='xs' />
</div>
</Preview>

<Props of={PickerButton} />
<Props of={PickerButton} />
45 changes: 24 additions & 21 deletions packages/picker-button/src/Component.test.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import { render, fireEvent } from '@testing-library/react';
import { render, fireEvent, waitFor } from '@testing-library/react';

import { PickerButton } from './index';

Expand All @@ -24,21 +24,26 @@ const options = [
{ key: '15', content: 'Bohrium' },
];

const clickPickerButton = () => {
const button = document.querySelector('button') as HTMLButtonElement;
fireEvent.click(button);
};

describe('Snapshots tests', () => {
it('should display correctly', () => {
const { container } = render(<PickerButton label={label} options={options} />);

expect(container).toMatchSnapshot();
});

it('should display opened correctly', () => {
const { container } = render(<PickerButton options={options} />);

const button = document.querySelector('button');
it('should display opened correctly', async () => {
const { baseElement } = render(<PickerButton options={options} />);

if (button) fireEvent.click(button);
clickPickerButton();

expect(container).toMatchSnapshot();
await waitFor(() => {
expect(baseElement).toMatchSnapshot();
});
});
});

Expand Down Expand Up @@ -109,27 +114,25 @@ describe('Render tests', () => {
expect(icon.getAttribute('height')).toBe(iconSize);
});

it('should have open class if opened', () => {
it('should have open class if opened', async () => {
render(<PickerButton label={label} options={options} />);

const button = document.querySelector('button');
clickPickerButton();

const iconContainer = document.querySelector('.iconContainer');

if (button) fireEvent.click(button);

expect(iconContainer).toHaveClass('open');
await waitFor(() => {
const iconContainer = document.querySelector('.iconContainer');
expect(iconContainer).toHaveClass('open');
});
});

it('should have options if opened', () => {
it('should have options if opened', async () => {
render(<PickerButton label={label} options={options} />);

const button = document.querySelector('button') as HTMLButtonElement;

fireEvent.click(button);

const renderedOptions = document.querySelectorAll('.option');
clickPickerButton();

expect(renderedOptions).toHaveLength(options.length);
await waitFor(() => {
const renderedOptions = document.querySelectorAll('.option');
expect(renderedOptions).toHaveLength(options.length);
});
});
});
2 changes: 1 addition & 1 deletion packages/picker-button/src/Component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ export const PickerButton = forwardRef<HTMLInputElement, PickerButtonProps>(
ref,
) => (
<BaseSelect
{...restProps}
ref={ref}
Option={Option}
Field={DefaultField}
Expand All @@ -67,7 +68,6 @@ export const PickerButton = forwardRef<HTMLInputElement, PickerButtonProps>(
Optgroup={Optgroup}
OptionsList={OptionsList}
className={cn(styles.container, className)}
{...restProps}
selected={[]}
closeOnSelect={true}
/>
Expand Down

0 comments on commit 7688ec7

Please sign in to comment.