Skip to content

Commit

Permalink
Merge branch 'main' into feat/link_underline
Browse files Browse the repository at this point in the history
  • Loading branch information
rLukoyanov authored Jun 15, 2024
2 parents 045b2cf + 4374858 commit 75851fe
Show file tree
Hide file tree
Showing 15 changed files with 320 additions and 43 deletions.
16 changes: 16 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,21 @@
# Changelog

## [6.18.0](https://github.com/gravity-ui/uikit/compare/v6.17.0...v6.18.0) (2024-06-14)


### Features

* **Breadcrumbs:** new component ([#1497](https://github.com/gravity-ui/uikit/issues/1497)) ([5cdc675](https://github.com/gravity-ui/uikit/commit/5cdc6753d4461b8e531870bcd9f4724dc6782d80))
* **Select:** support form ([#1644](https://github.com/gravity-ui/uikit/issues/1644)) ([1ad73b6](https://github.com/gravity-ui/uikit/commit/1ad73b69679a55001d50e97db1d40484d3e04c8c))
* support RSC ([#1582](https://github.com/gravity-ui/uikit/issues/1582)) ([770d787](https://github.com/gravity-ui/uikit/commit/770d787ef5952de5ccc45595065fa50b1f1d48f9))
* **Table:** add filter to colum settings ([#1627](https://github.com/gravity-ui/uikit/issues/1627)) ([6eca546](https://github.com/gravity-ui/uikit/commit/6eca54635f8fbbcf6960ff6bb96563273b458700))


### Bug Fixes

* **Button:** remove useless pointer-events style for icon content ([#1641](https://github.com/gravity-ui/uikit/issues/1641)) ([47b9850](https://github.com/gravity-ui/uikit/commit/47b985030df97f46fc16d283e75a4f8b395ff4db))
* **PinInput:** add use client ([#1646](https://github.com/gravity-ui/uikit/issues/1646)) ([d0bdede](https://github.com/gravity-ui/uikit/commit/d0bdede7c79e5102db41b73b0350056c49c67ace))

## [6.17.0](https://github.com/gravity-ui/uikit/compare/v6.16.0...v6.17.0) (2024-06-11)


Expand Down
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@gravity-ui/uikit",
"version": "6.17.0",
"version": "6.18.0",
"description": "Gravity UI base styling and components",
"license": "MIT",
"engines": {
Expand Down
2 changes: 2 additions & 0 deletions src/components/PinInput/PinInput.tsx
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use client';

import React from 'react';

import {KeyCode} from '../../constants';
Expand Down
21 changes: 17 additions & 4 deletions src/components/Select/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@ import {errorPropsMapper} from '../controls/utils';
import {useMobile} from '../mobile';
import type {CnMods} from '../utils/cn';

import {EmptyOptions, SelectControl, SelectFilter, SelectList, SelectPopup} from './components';
import {
EmptyOptions,
HiddenSelect,
SelectControl,
SelectFilter,
SelectList,
SelectPopup,
} from './components';
import {DEFAULT_VIRTUALIZATION_THRESHOLD, selectBlock} from './constants';
import {useQuickSearch} from './hooks';
import {getSelectFilteredOptions, useSelectOptions} from './hooks-public';
Expand Down Expand Up @@ -63,6 +70,7 @@ export const Select = React.forwardRef<HTMLButtonElement, SelectProps>(function
getOptionGroupHeight,
filterOption,
name,
form,
className,
controlClassName,
popupClassName,
Expand Down Expand Up @@ -130,6 +138,7 @@ export const Select = React.forwardRef<HTMLButtonElement, SelectProps>(function
open,
activeIndex,
toggleOpen,
setValue,
handleSelection,
handleClearValue,
setActiveIndex,
Expand Down Expand Up @@ -326,7 +335,6 @@ export const Select = React.forwardRef<HTMLButtonElement, SelectProps>(function
ref={handleControlRef}
className={controlClassName}
qa={qa}
name={name}
view={view}
size={size}
pin={pin}
Expand All @@ -347,7 +355,6 @@ export const Select = React.forwardRef<HTMLButtonElement, SelectProps>(function
renderCounter={renderCounter}
title={title}
/>

<SelectPopup
ref={controlWrapRef}
className={popupClassName}
Expand All @@ -363,11 +370,17 @@ export const Select = React.forwardRef<HTMLButtonElement, SelectProps>(function
>
{renderPopup({renderFilter: _renderFilter, renderList: _renderList})}
</SelectPopup>

<OuterAdditionalContent
errorMessage={isErrorMsgVisible ? errorMessage : null}
errorMessageId={errorMessageId}
/>
<HiddenSelect
name={name}
value={value}
disabled={disabled}
form={form}
onReset={setValue}
/>
</div>
);
}) as unknown as SelectComponent;
Expand Down
100 changes: 67 additions & 33 deletions src/components/Select/__stories__/Select.stories.tsx
Original file line number Diff line number Diff line change
@@ -1,15 +1,16 @@
import React from 'react';

import type {Meta, StoryFn} from '@storybook/react';
import type {Meta, StoryObj} from '@storybook/react';

import {Select} from '..';
import type {SelectProps} from '..';
import {Button} from '../../Button';

import {SelectPopupWidthShowcase} from './SelectPopupWidthShowcase';
import {SelectShowcase} from './SelectShowcase';
import {UseSelectOptionsShowcase} from './UseSelectOptionsShowcase';

export default {
const meta: Meta = {
title: 'Components/Inputs/Select',
component: Select,
parameters: {
Expand All @@ -26,35 +27,68 @@ export default {
},
},
},
} as Meta;

const DefaultTemplate: StoryFn<SelectProps> = (args) => (
<Select {...args} title="Select sample">
<Select.Option value="val1" content="Value1" />
<Select.Option value="val2" content="Value2" />
<Select.Option value="val3" content="Value3" />
<Select.Option value="val4" content="Value4" />
</Select>
);
const ShowcaseTemplate: StoryFn<SelectProps> = (args: SelectProps) => <SelectShowcase {...args} />;
const SelectPopupWidthShowcaseTemplate: StoryFn<SelectProps> = (args) => (
<SelectPopupWidthShowcase {...args} />
);
const UseSelectOptionsShowcaseTemplate = () => {
return <UseSelectOptionsShowcase />;
};
export const Default = DefaultTemplate.bind({});
export const Showcase = ShowcaseTemplate.bind({});
export const PopupWidth = SelectPopupWidthShowcaseTemplate.bind({});
export const UseSelectOptions = UseSelectOptionsShowcaseTemplate.bind({});

Showcase.args = {
view: 'normal',
size: 'm',
multiple: false,
filterable: false,
disabled: false,
placeholder: 'Values',
label: '',
hasClear: false,
};

export default meta;

type Story = StoryObj<SelectProps>;

export const Default = {
render: (args) => (
<Select {...args} title="Select sample">
<Select.Option value="val1" content="Value1" />
<Select.Option value="val2" content="Value2" />
<Select.Option value="val3" content="Value3" />
<Select.Option value="val4" content="Value4" />
</Select>
),
} satisfies Story;

export const Showcase = {
render: (args: SelectProps) => <SelectShowcase {...args} />,
args: {
view: 'normal',
size: 'm',
multiple: false,
filterable: false,
disabled: false,
placeholder: 'Values',
label: '',
hasClear: false,
},
} satisfies Story;

export const PopupWidth = {
render: (args) => <SelectPopupWidthShowcase {...args} />,
} satisfies Story;

export const UseSelectOptions = {
render: () => <UseSelectOptionsShowcase />,
parameters: {
controls: {
disabled: true,
},
},
} satisfies Story;

export const Form = {
render: (args) => (
<form
id="form"
onSubmit={(event) => {
event.preventDefault();
alert(JSON.stringify([...new FormData(event.currentTarget).entries()]));
}}
>
<label style={{display: 'flex', gap: 8, alignItems: 'center'}}>
Value: {Default.render({name: 'value', ...args})}
</label>
<div style={{marginBlockStart: '1em', display: 'flex', gap: 8}}>
<Button type="submit" view="action">
Submit
</Button>
<Button type="reset">Reset</Button>
</div>
</form>
),
} satisfies Story;
120 changes: 120 additions & 0 deletions src/components/Select/__tests__/Select.form.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/* eslint-disable testing-library/no-node-access */
import React from 'react';

import userEvent from '@testing-library/user-event';

import {render, screen, within} from '../../../../test-utils/utils';
import {Select} from '../Select';

describe('Select form', () => {
it('should submit empty option by default', async () => {
let value;
const onSubmit = jest.fn((e) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
value = formData.getAll('select');
});
render(
<form data-qa="form" onSubmit={onSubmit}>
<Select name="select" label="Test">
<Select.Option value="one">One</Select.Option>
<Select.Option value="two">Two</Select.Option>
<Select.Option value="three">Three</Select.Option>
</Select>
<button type="submit" data-qa="submit">
submit
</button>
</form>,
);
await userEvent.click(screen.getByTestId('submit'));
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(value).toEqual(['']);
});

it('should submit default option', async () => {
let value;
const onSubmit = jest.fn((e) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
value = formData.getAll('select');
});
render(
<form data-qa="form" onSubmit={onSubmit}>
<Select defaultValue={['one']} name="select">
<Select.Option value="one">One</Select.Option>
<Select.Option value="two">Two</Select.Option>
<Select.Option value="three">Three</Select.Option>
</Select>
<button type="submit" data-qa="submit">
submit
</button>
</form>,
);
await userEvent.click(screen.getByTestId('submit'));
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(value).toEqual(['one']);
});

it('should submit multiple option', async () => {
let value;
const onSubmit = jest.fn((e) => {
e.preventDefault();
const formData = new FormData(e.currentTarget);
value = formData.getAll('select');
});
render(
<form data-qa="form" onSubmit={onSubmit}>
<Select defaultValue={['one', 'three']} name="select" multiple>
<Select.Option value="one">One</Select.Option>
<Select.Option value="two">Two</Select.Option>
<Select.Option value="three">Three</Select.Option>
</Select>
<button type="submit" data-qa="submit">
submit
</button>
</form>,
);
await userEvent.click(screen.getByTestId('submit'));
expect(onSubmit).toHaveBeenCalledTimes(1);
expect(value).toEqual(['one', 'three']);
});

it('supports form reset', async () => {
function Test() {
const [value, setValue] = React.useState(['one']);
return (
<form>
<Select name="select" value={value} onUpdate={setValue} qa="select">
<Select.Option value="one">One</Select.Option>
<Select.Option value="two">Two</Select.Option>
<Select.Option value="three">Three</Select.Option>
</Select>
<input type="reset" data-qa="reset" />
</form>
);
}

render(<Test />);
const select = screen.getByTestId('select');
let inputs = document.querySelectorAll('[name=select]');
expect(inputs.length).toBe(1);
expect(inputs[0]).toHaveValue('one');

await userEvent.click(select);

const listbox = screen.getByRole('listbox');
const items = within(listbox).getAllByRole('option');
expect(items.length).toBe(3);

await userEvent.click(items[1]);
inputs = document.querySelectorAll('[name=select]');
expect(inputs.length).toBe(1);
expect(inputs[0]).toHaveValue('two');

const button = screen.getByTestId('reset');
await userEvent.click(button);
inputs = document.querySelectorAll('[name=select]');
expect(inputs.length).toBe(1);
expect(inputs[0]).toHaveValue('one');
});
});
Loading

0 comments on commit 75851fe

Please sign in to comment.