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(Form): добавляем новый компонент Form на замену FormLayout #4576

Closed
wants to merge 19 commits into from
Closed
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
11 changes: 9 additions & 2 deletions packages/vkui/src/components/Calendar/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ const Example = () => {
const [size, setSize] = useState('m');
const [listenDayChangesForUpdate, setListenDayChangesForUpdate] = useState(false);

const onSubmit = () => {
console.log('Выбранная дата сохранена!');
};

return (
<FormLayout>
<Form onSubmit={onSubmit}>
<FormLayoutGroup mode="vertical">
<FormItem top="Выбранная дата">{format(value, 'YYYY-MM-DD HH:mm:ss')}</FormItem>
<FormItem top="Выбор времени">
Expand Down Expand Up @@ -115,7 +119,10 @@ const Example = () => {
</LocaleProvider>
</FormItem>
</FormLayoutGroup>
</FormLayout>
<FormItem>
<Button type="submit">Сохранить</Button>
</FormItem>
</Form>
);
};

Expand Down
11 changes: 9 additions & 2 deletions packages/vkui/src/components/CalendarRange/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@ const Example = () => {
const [disablePickers, setDisablePickers] = useState(false);
const [locale, setLocale] = useState('ru');

const onSubmit = () => {
console.log('Значение CalendarRange сохранено!');
};

return (
<FormLayout>
<Form onSubmit={onSubmit}>
<FormLayoutGroup mode="vertical">
<FormItem top="Выбранная дата">
{format(value[0], 'YYYY-MM-DD')} - {format(value[1], 'YYYY-MM-DD')}
Expand Down Expand Up @@ -71,7 +75,10 @@ const Example = () => {
</LocaleProvider>
</FormItem>
</FormLayoutGroup>
</FormLayout>
<FormItem>
<Button type="submit">Сохранить</Button>
</FormItem>
</Form>
);
};

Expand Down
11 changes: 9 additions & 2 deletions packages/vkui/src/components/DateInput/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,12 @@ const Example = () => {
const [disableCalendar, setDisableCalendar] = useState(false);
const [locale, setLocale] = useState('ru');

const onSubmit = () => {
console.log('Выбранная дата сохранена!');
};

return (
<FormLayout>
<Form onSubmit={onSubmit}>
<FormLayoutGroup mode="vertical">
<FormItem top="Выбор времени">
<Checkbox checked={enableTime} onChange={(e) => setEnableTime(e.target.checked)}>
Expand Down Expand Up @@ -106,7 +110,10 @@ const Example = () => {
</div>
</FormItem>
</FormLayoutGroup>
</FormLayout>
<FormItem>
<Button type="submit">Сохранить</Button>
</FormItem>
</Form>
);
};

Expand Down
11 changes: 9 additions & 2 deletions packages/vkui/src/components/DateRangeInput/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,12 @@ const Example = () => {
const [disableCalendar, setDisableCalendar] = useState(false);
const [locale, setLocale] = useState('ru');

const onSubmit = () => {
console.log('Выбранная дата сохранена!');
};

return (
<FormLayout>
<Form onSubmit={onSubmit}>
<FormLayoutGroup mode="vertical">
<FormItem top="Запрет выбора прошлых дат">
<Checkbox checked={disablePast} onChange={(e) => setDisablePast(e.target.checked)}>
Expand Down Expand Up @@ -89,7 +93,10 @@ const Example = () => {
</div>
</FormItem>
</FormLayoutGroup>
</FormLayout>
<FormItem>
<Button type="submit">Сохранить</Button>
</FormItem>
</Form>
);
};

Expand Down
7 changes: 7 additions & 0 deletions packages/vkui/src/components/Form/Form.a11y.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
import * as React from 'react';
import { a11yBasicTest } from '../../testing/a11y';
import { Form } from './Form';

describe('Form', () => {
a11yBasicTest((props) => <Form {...props} />);
});
4 changes: 4 additions & 0 deletions packages/vkui/src/components/Form/Form.module.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
.Form {
position: relative;
display: block;
}
47 changes: 47 additions & 0 deletions packages/vkui/src/components/Form/Form.stories.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
import React from 'react';
import { Meta, StoryObj } from '@storybook/react';
import { withSinglePanel, withVKUILayout } from '../../storybook/VKUIDecorators';
import { CanvasFullLayout, DisableCartesianParam } from '../../storybook/constants';
import { Button } from '../Button/Button';
import { FormItem } from '../FormItem/FormItem';
import { Group } from '../Group/Group';
import { Input } from '../Input/Input';
import { Form, FormProps } from './Form';

const story: Meta<FormProps> = {
title: 'Forms/Form',
component: Form,
parameters: { ...CanvasFullLayout, ...DisableCartesianParam },
};

export default story;

export const Playground: StoryObj<FormProps> = {
render: (props) => (
<Form {...props}>
<FormItem top="Пароль">
<Input type="password" placeholder="Введите пароль" />
</FormItem>
<FormItem>
<Button type="submit" size="l">
Сохранить
</Button>
</FormItem>
</Form>
),
args: {
preventDefault: true,
onSubmit: () => {
console.log('Форма сохранена!');
},
},
decorators: [
(Component, context) => (
<Group>
<Component {...context.args} />
</Group>
),
withSinglePanel,
withVKUILayout,
],
};
46 changes: 46 additions & 0 deletions packages/vkui/src/components/Form/Form.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as React from 'react';
import { createEvent, fireEvent, render } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { baselineComponent } from '../../testing/utils';
import { Button } from '../Button/Button';
import { Form } from './Form';

describe('Form', () => {
baselineComponent(Form);

describe('checks e.preventDefault()', () => {
const handlePreventDefault = (preventDefault = true) => {
const { getByTestId } = render(
<Form data-testid="form" preventDefault={preventDefault}>
<Button type="submit">__submit__</Button>
</Form>,
);
const form = getByTestId('form');
const submitForm = createEvent.submit(form);

fireEvent(form, submitForm);
expect(submitForm.defaultPrevented).toBe(preventDefault);
};

it('if preventDefault={true} call e.preventDefault()', () => {
return handlePreventDefault(true);
});

it("if preventDefault={false} DON'T call e.preventDefault()", () => {
return handlePreventDefault(false);
});
});

it('calls passed onSubmit()', () => {
const onSubmit = jest.fn();

const { getByText } = render(
<Form onSubmit={onSubmit}>
<Button type="submit">__submit__</Button>
</Form>,
);

userEvent.click(getByText('__submit__'));
expect(onSubmit).toBeCalledTimes(1);
});
});
41 changes: 41 additions & 0 deletions packages/vkui/src/components/Form/Form.tsx
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Может нам и не нужен компонент Form? Ведь формы это уже что-то посложнее и от проекта к проекту отличаются

С нашей стороны мы отдаём FormLayoutGroup, который помогает настроить визуальную часть, а всё остальное уже не задача ui кита

Пользователь сам своей стороне оборачивает в <form> или использует готовую библиотеку для работы с формами (например, react-final-form)


И вот задепрейкить FormLayout точно надо 👍

Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as React from 'react';
import { classNames } from '@vkontakte/vkjs';
import { HasComponent, HasRootRef } from '../../types';
import styles from './Form.module.css';

export interface FormProps
extends React.AllHTMLAttributes<HTMLElement>,
HasRootRef<HTMLElement>,
HasComponent {
preventDefault?: boolean;
}

/**
* @since v5.4.0
* @see https://vkcom.github.io/VKUI/#/Form
*/
export const Form = ({
Component = 'form',
onSubmit: onSubmitProp,
preventDefault = true,
getRootRef,
className,
children,
...restProps
}: FormProps) => {
const onSubmit = (e: React.FormEvent<HTMLElement>) => {
preventDefault && e.preventDefault();
onSubmitProp?.(e);
};

return (
<Component
{...restProps}
className={classNames(styles['Form'], className)}
onSubmit={onSubmit}
ref={getRootRef}
>
{children}
</Component>
);
};
43 changes: 43 additions & 0 deletions packages/vkui/src/components/Form/Readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
Компонент-надстройка над `form`. Принимает все валидные для этого элемента свойства.

По умолчанию в `onSubmit` происходит `e.preventDefault()`, чтобы избежать перезагрузки страницы. Вы можете управлять этим поведением с помощью свойства `preventDefault`.

Не забудьте добавить любую кнопку с `type="submit"`. Тогда данные вашей формы будут успешно отправляться как по клику на нее, так и по нажатию Enter.

```jsx
const Example = () => {
const onSubmit = () => {
console.log('Способ оплаты сохранен!');
};

return (
<View activePanel="panel">
<Panel id="panel">
<PanelHeader>Form</PanelHeader>
<Group>
<Form onSubmit={onSubmit}>
<FormItem top="Откуда списать">
<Radio name="radio" value="1" description="Баланс 7 320 ₽" defaultChecked>
VK Pay
</Radio>
<Radio name="radio" value="2">
Mastercard **** 1234
</Radio>
<Radio name="radio" value="3" description="Заблокирована" disabled>
Visa **** 4321
</Radio>
</FormItem>
<FormItem>
<Button stretched size="l" type="submit">
Сохранить способ оплаты
</Button>
</FormItem>
</Form>
</Group>
</Panel>
</View>
);
};

<Example />;
```
10 changes: 7 additions & 3 deletions packages/vkui/src/components/FormItem/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,12 +29,16 @@ const Example = () => {

const onRemove = () => setShowPatronymic(false);

const onSubmit = () => {
console.log('Форма отправлена!');
};

return (
<View activePanel="new-user">
<Panel id="new-user">
<PanelHeader>Регистрация</PanelHeader>
<Group>
<FormLayout>
<Form onSubmit={onSubmit}>
<FormItem
top="E-mail"
status={email ? 'valid' : 'error'}
Expand Down Expand Up @@ -146,11 +150,11 @@ const Example = () => {
Согласен со всем <Link>этим</Link>
</Checkbox>
<FormItem>
<Button size="l" stretched>
<Button type="submit" size="l" stretched>
Зарегистрироваться
</Button>
</FormItem>
</FormLayout>
</Form>
</Group>
</Panel>
</View>
Expand Down
10 changes: 10 additions & 0 deletions packages/vkui/src/components/FormLayout/FormLayout.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as React from 'react';
import { classNames } from '@vkontakte/vkjs';
import { warnOnce } from '../../lib/warnOnce';
import { HasComponent, HasRef } from '../../types';
import styles from './FormLayout.module.css';

Expand All @@ -9,8 +10,13 @@ export type FormLayoutProps = React.AllHTMLAttributes<HTMLElement> &
HasRef<HTMLElement> &
HasComponent;

const warn = warnOnce('FormLayout');
/**
* @see https://vkcom.github.io/VKUI/#/FormLayout
* @deprecated v5.4.0
*
* Компонент устарел и будет удален в v6. Используйте
* `<Form />` https://vkcom.github.io/VKUI/#/Form
*/
export const FormLayout = ({
children,
Expand All @@ -20,6 +26,10 @@ export const FormLayout = ({
className,
...restProps
}: FormLayoutProps) => {
if (process.env.NODE_ENV === 'development') {
warn('Компонент устарел и будет удален в v6. Используйте https://vkcom.github.io/VKUI/#/Form');
}

return (
<Component
{...restProps}
Expand Down
11 changes: 9 additions & 2 deletions packages/vkui/src/components/FormLayoutGroup/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,16 @@ const Example = () => {
setShowDates(value);
};

const onSubmit = () => {
console.log('Данные формы сохранены!');
};

return (
<View activePanel="FormLayoutGroup">
<Panel id="FormLayoutGroup">
<PanelHeader>FormLayoutGroup</PanelHeader>
<Group>
<FormLayout>
<Form onSubmit={onSubmit}>
<FormLayoutGroup mode="vertical">
<FormItem top="Имя">
<Input />
Expand Down Expand Up @@ -52,7 +56,10 @@ const Example = () => {
</FormItem>
</FormLayoutGroup>
)}
</FormLayout>
<FormItem>
<Button type="submit">Сохранить</Button>
</FormItem>
</Form>
</Group>
</Panel>
</View>
Expand Down
Loading