Skip to content
Closed
Show file tree
Hide file tree
Changes from 1 commit
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
78 changes: 68 additions & 10 deletions src/components/Title/README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,79 @@
# Title

`type: "title"`

`title:`
The **Title** component is used to display a section heading, optionally with a subtitle (description) and configurable styles, alignment, and link behavior.

---

## 🔧 Props

### `title`

Defines the main title content.
It can be either a simple string or an object with the following structure:

| Property | Type | Default | Description |
| ------------- | ------------------------------------------ | --------- | ------------------------------------------------------------------------------------------------------------------------------------ |
| `text` | `string` | — | Main title text. |
| `textSize` | `'s'` \| `'m'` \| `'l'` \|`'xs'` \| `'sm'` | `'m'` | Title font size. |
| `url` | `string` | — | Optional URL. When set, the title becomes a clickable link, and an arrow is automatically displayed at the end. |
| `resetMargin` | `boolean` | `true` | When `true`, removes automatic top margin. When `false`, the top margin depends on the `textSize` (see [_Margins_](#margins) below). |
| `anchor` | `string` | — | Optional anchor ID for navigation. |
| `justify` | `'start'` \| `'center'` \| `'end'` | `'start'` | Text alignment. |
| `urlTitle` | `string` | — | Accessibility title attribute for the link. |
| `onClick` | `() => void` | — | Optional click handler. |
| `custom` | `string \| React.ReactNode` | — | Custom React node or text appended to the title. |
| `navTitle` | `string` | — | Optional navigation title for use in table of contents. |

---

### `subtitle`

`subtitle?: string`

Optional subtitle (description) text.
Supports **YFM (Yandex Flavored Markdown)** formatting.

---

### `className`

`className?: string`

Optional CSS class name for the container.

---

### `colSizes`

- `text: string` - Title text
`colSizes?: GridColumnSizesType`

- `textSize?: 's' | 'm' | 'l'` — Title font size
Grid column size configuration for responsive layouts.
Default: `{ all: 12, sm: 8 }`.

- `url?: string` — URL for a redirect on clicking the title, an arrow is automatically added at the end.
---

- `resetMargin?: boolean` - default `true`. Without this property `margin-top` will be proportional to `textSize` (see section _Margins_ below)
### `id`

`description: string` - text (with YFM support)
`id?: string`

**Margins for title without reset:**
Optional HTML `id` attribute for the title container.

`textSize s - top: m`
---

`textSize m - top: l`
## 🧩 Example

`textSize l - top: xl`
```tsx
<Title
title={{
text: 'Section Heading',
textSize: 'l',
url: 'https://example.com',
urlTitle: 'Go to example',
resetMargin: false,
}}
subtitle="**This is** a subtitle with [YFM](https://example.com) support."
colSizes={{all: 12, sm: 6}}
/>
```
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
29 changes: 20 additions & 9 deletions src/components/Title/__stories__/Title.stories.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,25 @@ import Title, {TitleProps} from '../Title';
import data from './data.json';

export default {
component: Title,
title: 'Components/Title',
} as Meta;
component: Title,
parameters: {
layout: 'centered',
controls: {expanded: true},
},
argTypes: {
Copy link
Collaborator

Choose a reason for hiding this comment

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

This should work automatically. If it doesn't work, then you need to understand why.

Look at the reasons that I described in the comments, maybe it's them?
#1322

title: {control: 'object'},
subtitle: {control: 'text'},
className: {control: 'text'},
id: {control: 'text'},
colSizes: {control: 'object'},
},
} as Meta<TitleProps & ClassNameProps>;

const DefaultTemplate: StoryFn<TitleProps & ClassNameProps> = (args) => <Title {...args} />;

const SizesTemplate: StoryFn<TitleProps & ClassNameProps> = (args) => {
const titleItemObjectProps = typeof args.title === 'object' ? args.title : {};

return (
<div>
{Object.entries(data.sizes).map(([size, props]) => (
Expand Down Expand Up @@ -46,10 +56,9 @@ export const CustomTitle = DefaultTemplate.bind({});
export const Sizes = SizesTemplate.bind({});
export const SizesWithLinks = SizesTemplate.bind({});
export const TitleWithoutDescription = SizesTemplate.bind({});
export const WithCustomColSizes = DefaultTemplate.bind({});

Default.args = {
...DefaultArgs,
} as TitleProps;
Default.args = {...DefaultArgs} as TitleProps;
TitleLink.args = {
...DefaultArgs,
title: data.titleLink.content.title,
Expand All @@ -58,13 +67,15 @@ CustomTitle.args = {
...DefaultArgs,
title: data.customTitle.content.title,
} as TitleProps;
Sizes.args = {
...DefaultArgs,
} as TitleProps;
Sizes.args = {...DefaultArgs} as TitleProps;
Copy link
Collaborator

Choose a reason for hiding this comment

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

image Controls should be array

Copy link
Collaborator

Choose a reason for hiding this comment

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

In this story and in "Sizes With Link" and in "Title Without Description"

SizesWithLinks.args = {
...DefaultArgs,
title: data.titleLink.content.title,
} as TitleProps;
TitleWithoutDescription.args = {
title: data.default.content.title,
} as TitleProps;
WithCustomColSizes.args = {
...DefaultArgs,
colSizes: {all: 6, sm: 6, md: 4},
};
2 changes: 1 addition & 1 deletion src/components/Title/__stories__/data.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
"title": {
"text": "Lorem ipsum",
"url": "https://example.com",
"custom": "Some react node",
"custom": "⭐️",
"urlTitle": "Example website. Opens in a new window"
}
}
Expand Down
59 changes: 59 additions & 0 deletions src/components/Title/__tests__/Title.visual.test.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import {test} from '../../../../playwright/core/index';

import {
CustomTitle,
Default,
Sizes,
SizesWithLinks,
TitleLink,
TitleWithoutDescription,
WithCustomColSizes,
} from './helpers';

test.describe('Title', () => {
test('render stories <Default>', async ({mount, expectScreenshot, defaultDelay}) => {
await mount(<Default />);
await defaultDelay();
await expectScreenshot({skipTheme: 'dark'});
});

test('render stories <TitleLink>', async ({mount, expectScreenshot, defaultDelay}) => {
await mount(<TitleLink />);
await defaultDelay();
await expectScreenshot({skipTheme: 'dark'});
});

test('render stories <CustomTitle>', async ({mount, expectScreenshot, defaultDelay}) => {
await mount(<CustomTitle />);
await defaultDelay();
await expectScreenshot({skipTheme: 'dark'});
});

test('render stories <Sizes>', async ({mount, expectScreenshot, defaultDelay}) => {
await mount(<Sizes />);
await defaultDelay();
await expectScreenshot({skipTheme: 'dark'});
});

test('render stories <SizesWithLinks>', async ({mount, expectScreenshot, defaultDelay}) => {
await mount(<SizesWithLinks />);
await defaultDelay();
await expectScreenshot({skipTheme: 'dark'});
});

test('render stories <TitleWithoutDescription>', async ({
mount,
expectScreenshot,
defaultDelay,
}) => {
await mount(<TitleWithoutDescription />);
await defaultDelay();
await expectScreenshot({skipTheme: 'dark'});
});

test('render stories <WithCustomColSizes>', async ({mount, expectScreenshot, defaultDelay}) => {
await mount(<WithCustomColSizes />);
await defaultDelay();
await expectScreenshot({skipTheme: 'dark'});
});
});
15 changes: 15 additions & 0 deletions src/components/Title/__tests__/helpers.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {composeStories} from '@storybook/react';

import * as TitleStories from '../__stories__/Title.stories';

const composed = composeStories(TitleStories) as Record<string, React.ComponentType<any>>;

Check warning on line 5 in src/components/Title/__tests__/helpers.ts

View workflow job for this annotation

GitHub Actions / Verify Files

Unexpected any. Specify a different type

export const {
CustomTitle,
Default,
Sizes,
SizesWithLinks,
TitleLink,
TitleWithoutDescription,
WithCustomColSizes,
} = composed;
Loading