diff --git a/src/components/Title/README.md b/src/components/Title/README.md index 3057d2407..b334d4c2d 100644 --- a/src/components/Title/README.md +++ b/src/components/Title/README.md @@ -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 + +``` diff --git a/src/components/Title/Title.tsx b/src/components/Title/Title.tsx index 67d912ff1..d076a8635 100644 --- a/src/components/Title/Title.tsx +++ b/src/components/Title/Title.tsx @@ -9,18 +9,12 @@ import './Title.scss'; const b = block('title'); -export interface TitleProps extends TitleParams { +export interface TitleProps extends TitleParams, ClassNameProps { colSizes?: GridColumnSizesType; id?: string; } -const Title = ({ - title, - subtitle, - className, - colSizes = {all: 12, sm: 8}, - id, -}: TitleProps & ClassNameProps) => { +const Title = ({title, subtitle, className, colSizes = {all: 12, sm: 8}, id}: TitleProps) => { if (!title && !subtitle) { return null; } diff --git a/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-CustomTitle-light-chromium-linux.png b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-CustomTitle-light-chromium-linux.png new file mode 100644 index 000000000..a06dd450e Binary files /dev/null and b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-CustomTitle-light-chromium-linux.png differ diff --git a/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-CustomTitle-light-webkit-linux.png b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-CustomTitle-light-webkit-linux.png new file mode 100644 index 000000000..5b49843dd Binary files /dev/null and b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-CustomTitle-light-webkit-linux.png differ diff --git a/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-Default-light-chromium-linux.png b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-Default-light-chromium-linux.png new file mode 100644 index 000000000..029f3f711 Binary files /dev/null and b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-Default-light-chromium-linux.png differ diff --git a/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-Default-light-webkit-linux.png b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-Default-light-webkit-linux.png new file mode 100644 index 000000000..4389940a8 Binary files /dev/null and b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-Default-light-webkit-linux.png differ diff --git a/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-Sizes-light-chromium-linux.png b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-Sizes-light-chromium-linux.png new file mode 100644 index 000000000..053eb6a7f Binary files /dev/null and b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-Sizes-light-chromium-linux.png differ diff --git a/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-Sizes-light-webkit-linux.png b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-Sizes-light-webkit-linux.png new file mode 100644 index 000000000..7fb24f5ea Binary files /dev/null and b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-Sizes-light-webkit-linux.png differ diff --git a/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-SizesWithLinks-light-chromium-linux.png b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-SizesWithLinks-light-chromium-linux.png new file mode 100644 index 000000000..e01d5f615 Binary files /dev/null and b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-SizesWithLinks-light-chromium-linux.png differ diff --git a/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-SizesWithLinks-light-webkit-linux.png b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-SizesWithLinks-light-webkit-linux.png new file mode 100644 index 000000000..15be96356 Binary files /dev/null and b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-SizesWithLinks-light-webkit-linux.png differ diff --git a/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-TitleLink-light-chromium-linux.png b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-TitleLink-light-chromium-linux.png new file mode 100644 index 000000000..a00b1501a Binary files /dev/null and b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-TitleLink-light-chromium-linux.png differ diff --git a/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-TitleLink-light-webkit-linux.png b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-TitleLink-light-webkit-linux.png new file mode 100644 index 000000000..242068b0c Binary files /dev/null and b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-TitleLink-light-webkit-linux.png differ diff --git a/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-TitleWithoutDescription-light-chromium-linux.png b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-TitleWithoutDescription-light-chromium-linux.png new file mode 100644 index 000000000..4bc98198c Binary files /dev/null and b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-TitleWithoutDescription-light-chromium-linux.png differ diff --git a/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-TitleWithoutDescription-light-webkit-linux.png b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-TitleWithoutDescription-light-webkit-linux.png new file mode 100644 index 000000000..bcdeb3ea8 Binary files /dev/null and b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-TitleWithoutDescription-light-webkit-linux.png differ diff --git a/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-WithCustomColSizes-light-chromium-linux.png b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-WithCustomColSizes-light-chromium-linux.png new file mode 100644 index 000000000..55246b977 Binary files /dev/null and b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-WithCustomColSizes-light-chromium-linux.png differ diff --git a/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-WithCustomColSizes-light-webkit-linux.png b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-WithCustomColSizes-light-webkit-linux.png new file mode 100644 index 000000000..315a4e57a Binary files /dev/null and b/src/components/Title/__snapshots__/Title.visual.test.tsx-snapshots/Title-render-stories-WithCustomColSizes-light-webkit-linux.png differ diff --git a/src/components/Title/__stories__/Title.stories.tsx b/src/components/Title/__stories__/Title.stories.tsx index d00d22f16..83b4b47db 100644 --- a/src/components/Title/__stories__/Title.stories.tsx +++ b/src/components/Title/__stories__/Title.stories.tsx @@ -1,21 +1,26 @@ -import {Meta, StoryFn} from '@storybook/react'; +import {Meta, StoryFn, StoryObj} from '@storybook/react'; -import {yfmTransform} from '../../../../.storybook/utils'; -import {ClassNameProps, TitleItemProps} from '../../../models'; +import {blockTransform, yfmTransform} from '../../../../.storybook/utils'; +import {CustomBlock, TitleItemProps} from '../../../models'; 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}, + }, +} as Meta<TitleProps>; -const DefaultTemplate: StoryFn<TitleProps & ClassNameProps> = (args) => <Title {...args} />; +const DefaultTemplate: StoryFn<TitleProps> = (args) => ( + <Title {...(blockTransform(args as unknown as CustomBlock) as TitleProps)} /> +); -const SizesTemplate: StoryFn<TitleProps & ClassNameProps> = (args) => { +const SizesTemplate: StoryFn<TitleProps> = (args) => { const titleItemObjectProps = typeof args.title === 'object' ? args.title : {}; - return ( <div> {Object.entries(data.sizes).map(([size, props]) => ( @@ -40,16 +45,15 @@ const DefaultArgs = { subtitle: yfmTransform(data.default.content.subtitle), }; -export const Default = DefaultTemplate.bind({}); -export const TitleLink = DefaultTemplate.bind({}); -export const CustomTitle = DefaultTemplate.bind({}); -export const Sizes = SizesTemplate.bind({}); -export const SizesWithLinks = SizesTemplate.bind({}); -export const TitleWithoutDescription = SizesTemplate.bind({}); +export const Default: StoryObj<typeof Title> = DefaultTemplate.bind({}); +export const TitleLink: StoryObj<typeof Title> = DefaultTemplate.bind({}); +export const CustomTitle: StoryObj<typeof Title> = DefaultTemplate.bind({}); +export const Sizes: StoryObj<typeof Title> = SizesTemplate.bind({}); +export const SizesWithLinks: StoryObj<typeof Title> = SizesTemplate.bind({}); +export const TitleWithoutDescription: StoryObj<typeof Title> = SizesTemplate.bind({}); +export const WithCustomColSizes: StoryObj<typeof Title> = DefaultTemplate.bind({}); -Default.args = { - ...DefaultArgs, -} as TitleProps; +Default.args = {...DefaultArgs} as TitleProps; TitleLink.args = { ...DefaultArgs, title: data.titleLink.content.title, @@ -58,9 +62,7 @@ CustomTitle.args = { ...DefaultArgs, title: data.customTitle.content.title, } as TitleProps; -Sizes.args = { - ...DefaultArgs, -} as TitleProps; +Sizes.args = {...DefaultArgs} as TitleProps; SizesWithLinks.args = { ...DefaultArgs, title: data.titleLink.content.title, @@ -68,3 +70,7 @@ SizesWithLinks.args = { TitleWithoutDescription.args = { title: data.default.content.title, } as TitleProps; +WithCustomColSizes.args = { + ...DefaultArgs, + colSizes: {all: 6, sm: 6, md: 4}, +}; diff --git a/src/components/Title/__stories__/data.json b/src/components/Title/__stories__/data.json index 6f16ede75..31346a8c2 100644 --- a/src/components/Title/__stories__/data.json +++ b/src/components/Title/__stories__/data.json @@ -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" } } diff --git a/src/components/Title/__tests__/Title.visual.test.tsx b/src/components/Title/__tests__/Title.visual.test.tsx new file mode 100644 index 000000000..7c0143348 --- /dev/null +++ b/src/components/Title/__tests__/Title.visual.test.tsx @@ -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'}); + }); +}); diff --git a/src/components/Title/__tests__/helpers.ts b/src/components/Title/__tests__/helpers.ts new file mode 100644 index 000000000..d000feac9 --- /dev/null +++ b/src/components/Title/__tests__/helpers.ts @@ -0,0 +1,15 @@ +import {composeStories} from '@storybook/react'; + +import * as TitleStories from '../__stories__/Title.stories'; + +const composed = composeStories(TitleStories); + +export const { + CustomTitle, + Default, + Sizes, + SizesWithLinks, + TitleLink, + TitleWithoutDescription, + WithCustomColSizes, +} = composed;