diff --git a/src/blocks/ContentLayout/README.md b/src/blocks/ContentLayout/README.md index c628f5ea8..1004cc57c 100644 --- a/src/blocks/ContentLayout/README.md +++ b/src/blocks/ContentLayout/README.md @@ -1,6 +1,6 @@ `properties:` — Content cube properties (optional) -- `size?: 's' | 'l'` — Cube size that defines font sizes (defaults to l) +- `size?: 's' | 'l'` — Cube size that defines font sizes ('l' by default) - `background?: BackgroundImage` — Special background properties described in the **Content blocks** section. - `centered?: false | true` — Indicates if text is centered (false by default). - `theme?: 'default' | 'dark' | 'light'` — Cube theme: default, dark, or monochrome light ('default' by default). diff --git a/src/blocks/Tabs/README.md b/src/blocks/Tabs/README.md index a1caabe1c..ad68e3c9a 100644 --- a/src/blocks/Tabs/README.md +++ b/src/blocks/Tabs/README.md @@ -1,17 +1,31 @@ Tabs block -`type: tabs-block` — Title +`type: tabs-block` -`title: Title` — Subtitle +`title?: Title | string` - `items: TabsBlockItem[]` — Tab description +`description?: string` - > `tabName: string` — Tab title. +`animated?: boolean` — Enables/disables animation for the block (enabled by default). - > `image: string` — Image. +`centered?: false | true` - Aligns all content to the center ('false' by default) - > `caption?: string` — Image caption. +`tabsColSizes?: Object` — Width of buttons tabs, the value ranges from 1 to 12 columns. If 12 columns, buttons takes up the entire width of the row. - > `text: string` —Text. +- `all: number` — On all screens. +- `sm: number` — On a screen wider than 577px. +- `md: number` — On a screen wider than 769px. +- `lg: number` — On a screen wider than 1081px. +- `xl: number` — On a screen wider than 1185px. - > `link?: Link` — Link below the text. +`items: TabsBlockItem[]` — Tab description + +- `tabName: string` — Tab title. +- `title?: string` — Item's title +- `text?: string` — Item's text (with YFM support) +- `additionalInfo?: string` — Gray text (with YFM support) +- `links?: Link[]` — An array with link objects (see [Content blocks](?path=/story/information--common-types&viewMode=docs)) +- `buttons?: Button[]` — An array with button objects (see [Content blocks](?path=/story/information--common-types&viewMode=docs)) +- `image?: string | ImageObjectProps` — Image. +- [`media: Media` — Media description](?path=/story/information--common-types&viewMode=docs#media---picvideodatalens) +- `caption?: string` — Image caption. diff --git a/src/blocks/Tabs/Tabs.scss b/src/blocks/Tabs/Tabs.scss index 524896e4f..77c44fa76 100644 --- a/src/blocks/Tabs/Tabs.scss +++ b/src/blocks/Tabs/Tabs.scss @@ -1,20 +1,37 @@ @import '../../../styles/mixins'; @import '../../../styles/variables'; -$block: '.#{$ns}TabsBlock'; +$block: '.#{$ns}tabs-block'; #{$block} { $class: &; &__block-title { - margin-bottom: 12px; + margin-bottom: $indentSM; + + &_centered { + display: flex; + justify-content: center; + flex-wrap: wrap; + margin-left: auto; + margin-right: auto; + text-align: center; + } } &__tabs { - @include add-specificity(&) { - flex-wrap: nowrap; - overflow-x: auto; - margin-bottom: $indentM; + &_centered { + display: flex; + justify-content: center; + flex-wrap: wrap; + } + } + + &__row_reverse { + flex-direction: row-reverse; + + #{$class}__content-wrapper { + margin: $indentSM $indentM 0 0; } } @@ -40,6 +57,16 @@ $block: '.#{$ns}TabsBlock'; &__content { display: flex; flex-direction: column; + + &_centered { + margin: 0 auto; + } + } + + &__col { + &_centered { + margin: 0 auto; + } } &__content-wrapper { @@ -58,17 +85,41 @@ $block: '.#{$ns}TabsBlock'; } } - &__tabs, - &__link { - @include text-size(body-2); - } - @media (max-width: map-get($gridBreakpoints, 'md')) { + &__tabs { + display: flex; + flex-wrap: nowrap; + justify-content: flex-start; + overflow: auto; + margin-left: -$indentL; + margin-right: -$indentL; + padding-left: $indentL; + padding-right: $indentL - $indentXXXS; + } + &__content-wrapper { &_margin { margin: 0 0 $contentMargin 0; } } + + &__row_reverse { + flex-direction: column-reverse; + + #{$class}__content > * { + margin-top: $indentM; + padding-bottom: 0; + } + } + } + + @media (max-width: map-get($gridBreakpoints, 'sm')) { + &__tabs { + margin-left: -$indentSM; + margin-right: -$indentSM; + padding-left: $indentSM; + padding-right: $indentXS; + } } @include animate(#{$class}__media); diff --git a/src/blocks/Tabs/Tabs.tsx b/src/blocks/Tabs/Tabs.tsx index a8af243f4..59f6c8da5 100644 --- a/src/blocks/Tabs/Tabs.tsx +++ b/src/blocks/Tabs/Tabs.tsx @@ -1,101 +1,123 @@ import React, {Fragment, useContext, useState} from 'react'; -import {Tabs} from '@gravity-ui/uikit'; import {block, getThemedValue} from '../../utils'; import {Row, Col, GridColumnOrderClasses} from '../../grid'; -import YFMWrapper from '../../components/YFMWrapper/YFMWrapper'; import {TabsBlockProps} from '../../models'; import AnimateBlock from '../../components/AnimateBlock/AnimateBlock'; import BlockHeader from '../../components/BlockHeader/BlockHeader'; import FullScreenImage from '../../components/FullscreenImage/FullscreenImage'; import Media from '../../components/Media/Media'; -import Links from '../../components/Link/Links'; import {ThemeValueContext} from '../../context/theme/ThemeValueContext'; import {getMediaImage} from '../../components/Media/Image/utils'; +import ButtonTabs, {ButtonTabsItemProps} from '../../components/ButtonTabs/ButtonTabs'; +import {Content} from '../../sub-blocks'; import './Tabs.scss'; -const b = block('TabsBlock'); +const b = block('tabs-block'); -export const TabsBlock = ({items, title, description, animated}: TabsBlockProps) => { +export const TabsBlock = ({ + items, + title, + description, + animated, + tabsColSizes, + centered, + direction = 'media-content', +}: TabsBlockProps) => { const [activeTab, setActiveTab] = useState(items[0].tabName); const [play, setPlay] = useState(false); const {themeValue: theme} = useContext(ThemeValueContext); - const tabs = items.map(({tabName}) => ({title: tabName, id: tabName})); + const tabs: ButtonTabsItemProps[] = items.map(({tabName}) => ({title: tabName, id: tabName})); const activeTabData = items.find(({tabName}) => tabName === activeTab); + const isReverse = direction === 'content-media'; let imageProps; if (activeTabData) { const themedImage = getThemedValue(activeTabData.image, theme); + imageProps = themedImage && getMediaImage(themedImage); } const showMedia = Boolean(activeTabData?.media || imageProps); + const showText = Boolean(activeTabData?.text); + + const textContent = activeTabData && showText && ( + +
+ +
+ + ); + + const mediaContent = showMedia && ( + + {activeTabData?.media && ( + + )} + {imageProps && ( + + + {activeTabData?.caption && ( +

{activeTabData.caption}

+ )} +
+ )} + + ); return ( setPlay(true)} animate={animated}> - - + + + + + {activeTabData && ( - - {showMedia && ( - - {activeTabData?.media && ( - - )} - {imageProps && ( - - - {activeTabData && ( -

{activeTabData.caption}

- )} -
- )} - - )} - -
-

- -

- - -
- + + {mediaContent} + {textContent} )}
diff --git a/src/blocks/Tabs/__stories__/Tabs.stories.tsx b/src/blocks/Tabs/__stories__/Tabs.stories.tsx index 3d92991f5..333f9b879 100644 --- a/src/blocks/Tabs/__stories__/Tabs.stories.tsx +++ b/src/blocks/Tabs/__stories__/Tabs.stories.tsx @@ -1,9 +1,9 @@ -import React from 'react'; +import React, {Fragment} from 'react'; import {Meta, Story} from '@storybook/react/types-6-0'; import {yfmTransform} from '../../../../.storybook/utils'; -import {TabsBlockModel} from '../../../models'; +import {TabsBlockModel, TabsBlockProps} from '../../../models'; import Tabs from '../Tabs'; -import {PageConstructor} from '../../../containers/PageConstructor/PageConstructor'; +import {PageConstructor} from '../../../containers/PageConstructor'; import data from './data.json'; @@ -19,17 +19,97 @@ const DefaultTemplate: Story = (args) => ( ); +const ButtonsColSizesTemplate: Story = (args) => ( + + + + +); + +const DirectionTemplate: Story = (args) => ( + + + + +); + export const Default = DefaultTemplate.bind({}); -export const WithTheme = DefaultTemplate.bind({}); -export const Media = DefaultTemplate.bind({}); +export const OnlyMedia = DefaultTemplate.bind({}); +export const OnlyText = DefaultTemplate.bind({}); +export const TabsButtonsColSizes = ButtonsColSizesTemplate.bind({}); +export const Centered = DefaultTemplate.bind({}); +export const Direction = DirectionTemplate.bind({}); +export const Caption = DefaultTemplate.bind({}); -Default.args = { +const DefaultArgs = { ...data.default.content, items: data.default.content.items.map((item) => ({ ...item, - title: yfmTransform(item.title), text: yfmTransform(item.text), + additionalInfo: item.additionalInfo && yfmTransform(item.additionalInfo), + })), +}; + +Default.args = { + ...DefaultArgs, + description: yfmTransform(data.description), +} as TabsBlockProps; + +OnlyMedia.args = { + ...DefaultArgs, + items: DefaultArgs.items.map((item) => ({ + ...item, + text: undefined, + })), +} as TabsBlockModel; + +OnlyText.args = { + ...DefaultArgs, + items: DefaultArgs.items.map((item) => ({ + ...item, + media: undefined, + image: undefined, + })), +} as TabsBlockModel; + +TabsButtonsColSizes.args = { + ...data.default.content, + items: DefaultArgs.items.concat( + DefaultArgs.items.map((item, index) => { + return { + ...item, + tabName: `${item.tabName} ${index}`, + }; + }), + DefaultArgs.items.map((item, index) => { + return { + ...item, + tabName: `${item.tabName} ${index} ${index}`, + }; + }), + ), +} as TabsBlockModel; + +Centered.args = { + ...DefaultArgs, + description: yfmTransform(data.description), + centered: true, +} as TabsBlockModel; + +Direction.args = {...DefaultArgs} as TabsBlockModel; + +Caption.args = { + ...DefaultArgs, + items: DefaultArgs.items.map((item) => ({ + ...item, + caption: item.title, })), } as TabsBlockModel; -WithTheme.args = data.theme.content as TabsBlockModel; -Media.args = data.media.content as TabsBlockModel; diff --git a/src/blocks/Tabs/__stories__/data.json b/src/blocks/Tabs/__stories__/data.json index 67270ea73..f78d6cc4f 100644 --- a/src/blocks/Tabs/__stories__/data.json +++ b/src/blocks/Tabs/__stories__/data.json @@ -8,77 +8,28 @@ "items": [ { "tabName": "Dolor sit amet", - "title": "Dolor sit amet", - "text": "* Ut enim ad minim veniam\n* Ut enim ad minim veniam", - "link": { - "url": "https://example.com", - "text": "Link", - "theme": "normal", - "arrow": true - } - }, - { - "tabName": "Consectetur adipiscing elit", - "title": "Consectetur adipiscing elit", - "text": "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur.", - "link": { - "url": "https://example.com", - "text": "Link", - "theme": "normal" - } - } - ] - } - }, - "theme": { - "content": { - "type": "tabs-block", - "title": { - "text": "Lorem ipsum" - }, - "items": [ - { - "tabName": "Dolor sit amet", - "title": "Dolor sit amet", - "image": { - "light": { - "src": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/img_8-12_light.png", - "disableCompress": true + "title": "Lorem ipsum dolor sit amet", + "text": "**Ut enim ad minim veniam** [quis nostrud](https://example.com) exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.", + "buttons": [ + { + "text": "Button", + "theme": "action", + "url": "https://example.com" }, - "dark": { - "src": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/img_8-12_dark.png" + { + "text": "Button", + "theme": "outlined", + "url": "https://example.com" } - }, - "caption": "Dolor sit amet", - "text": "* Ut enim ad minim veniam\n* Ut enim ad minim veniam" - }, - { - "tabName": "Consectetur adipiscing elit", - "title": "Consectetur adipiscing elit", + ], "image": { - "light": { - "src": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/img_8-12_light.png" - }, - "dark": { - "src": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/img_8-12_dark.png" - } - }, - "caption": "Consectetur adipiscing elit", - "text": "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." - } - ] - } - }, - "media": { - "content": { - "type": "tabs-block", - "title": { - "text": "Lorem ipsum" - }, - "items": [ + "light": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/img_8-12_white.png", + "dark": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/img_8-12_dark.png" + } + }, { - "tabName": "Dolor sit amet", - "title": "Dolor sit amet", + "tabName": "Lorem ipsum", + "title": "Lorem ipsum", "media": { "light": { "video": { @@ -108,19 +59,50 @@ } }, "caption": "Dolor sit amet", - "text": "* Ut enim ad minim veniam\n* Ut enim ad minim veniam" + "text": "* Ut enim ad minim veniam\n* Ut enim ad minim veniam", + "links": [ + { + "url": "https://example.com", + "text": "Link", + "theme": "normal", + "arrow": true + } + ] }, { "tabName": "Consectetur adipiscing elit", "title": "Consectetur adipiscing elit", + "additionalInfo": "Duis aute irure dolor in [reprehenderit](https://example.com) n voluptate velit esse cillum dolore eu fugiat nulla pariatur.", "media": { - "youtube": "https://youtu.be/0Qd3T6skprA", - "previewImg": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/video_8-12_dark.png" + "light": { + "youtube": "https://youtu.be/0Qd3T6skprA", + "previewImg": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/video_8-12_light.png" + }, + "dark": { + "youtube": "https://youtu.be/0Qd3T6skprA", + "previewImg": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/video_8-12_dark.png" + } }, "caption": "Consectetur adipiscing elit", "text": "Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." } ] } - } + }, + "buttonsColSizes": { + "wide": { + "title": "Tabs buttons with col sizes 12 columns", + "colSizes": { + "all": 12 + } + }, + "narrow": { + "title": "Tabs buttons with col sizes 8 columns", + "colSizes": { + "all": 12, + "md": 8 + } + } + }, + "description": "**Ut enim ad minim veniam** [quis nostrud](https://example.com) exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum." } diff --git a/src/blocks/Tabs/schema.ts b/src/blocks/Tabs/schema.ts index 7dc44b57e..036f7627e 100644 --- a/src/blocks/Tabs/schema.ts +++ b/src/blocks/Tabs/schema.ts @@ -5,23 +5,25 @@ import { BlockBaseProps, TitleProps, MediaProps, + containerSizesArray, + sizeNumber, + mediaDirection, } from '../../schema/validators/common'; import {ImageProps} from '../../components/Image/schema'; +import _ from 'lodash'; +import {ContentBase} from '../../sub-blocks/Content/schema'; + +const TabsItemContentProps = _.omit(ContentBase, ['size', 'colSizes', 'centered', 'theme']); export const tabsItem = { type: 'object', additionalProperties: false, - required: ['tabName', 'text'], + required: ['tabName'], properties: { + ...TabsItemContentProps, tabName: { type: 'string', }, - title: { - type: 'string', - }, - text: { - type: 'string', - }, caption: { type: 'string', }, @@ -31,7 +33,6 @@ export const tabsItem = { }), //TODO deprecated link: LinkProps, - links: filteredArray(LinkProps), image: withTheme(ImageProps), }, }; @@ -46,6 +47,15 @@ export const TabsBlock = { description: { type: 'string', }, + tabsColSizes: containerSizesArray.reduce( + (acc, size) => ({...acc, [size]: sizeNumber}), + {}, + ), + direction: { + type: 'string', + enum: mediaDirection, + }, + centered: {type: 'boolean'}, items: filteredArray(tabsItem), }, }, diff --git a/src/components/ButtonTabs/ButtonTabs.scss b/src/components/ButtonTabs/ButtonTabs.scss new file mode 100644 index 000000000..05d01cebc --- /dev/null +++ b/src/components/ButtonTabs/ButtonTabs.scss @@ -0,0 +1,17 @@ +@import '../../../styles/variables'; +@import '../../../styles/mixins'; + +$block: '.#{$ns}button-tabs'; + +#{$block} { + margin-bottom: $indentS; + + &__item { + margin-right: $indentXXXS; + margin-bottom: $indentXXS; + + &_active { + pointer-events: none; + } + } +} diff --git a/src/components/ButtonTabs/ButtonTabs.tsx b/src/components/ButtonTabs/ButtonTabs.tsx new file mode 100644 index 000000000..3b2515d4c --- /dev/null +++ b/src/components/ButtonTabs/ButtonTabs.tsx @@ -0,0 +1,64 @@ +import React, {useCallback, useMemo} from 'react'; +import {block} from '../../utils'; + +import {ButtonProps} from '../../models'; +import {Button} from '../index'; + +import './ButtonTabs.scss'; + +const b = block('button-tabs'); + +export interface ButtonTabsItemProps + extends Omit { + id: string; + title: string; +} + +export interface ButtonTabsProps { + className?: string; + items: ButtonTabsItemProps[]; + activeTab?: string; + onSelectTab?: (tabId: string) => void; +} + +const ButtonTabs = (props: ButtonTabsProps) => { + const {className, items, activeTab, onSelectTab} = props; + + const activeTabId: string = useMemo(() => { + if (activeTab) { + return activeTab; + } + + return items[0].id; + }, [activeTab, items]); + + const handleClick = useCallback( + (tabId: string) => { + if (onSelectTab) { + onSelectTab(tabId); + } + }, + [onSelectTab], + ); + + return ( +
+ {items.map((item) => { + const isActive = item.id === activeTabId; + + return ( +
+ ); +}; + +export default ButtonTabs; diff --git a/src/components/Image/Image.scss b/src/components/Image/Image.scss new file mode 100644 index 000000000..e02bdef46 --- /dev/null +++ b/src/components/Image/Image.scss @@ -0,0 +1,8 @@ +@import '../../../styles/variables.scss'; + +$block: '.#{$ns}image'; + +#{$block} { + height: 100%; + width: 100%; +} diff --git a/src/components/Image/Image.tsx b/src/components/Image/Image.tsx index 0998f6923..aab83b3bc 100644 --- a/src/components/Image/Image.tsx +++ b/src/components/Image/Image.tsx @@ -2,6 +2,11 @@ import React, {CSSProperties, MouseEventHandler, useContext, useState, Fragment} import {ProjectSettingsContext} from '../../context/projectSettingsContext'; import {BREAKPOINTS} from '../../constants'; import {ImageDeviceProps, ImageObjectProps} from '../../models'; +import {block} from '../../utils'; + +import './Image.scss'; + +const b = block('image'); export interface ImageProps extends Partial, Partial { style?: CSSProperties; @@ -32,7 +37,7 @@ const Image = (props: ImageProps) => { imgLoadingError; return ( - + {mobile && ( {!disableWebp && ( diff --git a/src/models/constructor-items/blocks.ts b/src/models/constructor-items/blocks.ts index 2ef8f2d12..36bd39747 100644 --- a/src/models/constructor-items/blocks.ts +++ b/src/models/constructor-items/blocks.ts @@ -286,19 +286,22 @@ export interface TableBlockProps { table: TableProps; } -export interface TabsBlockItem { +export interface TabsBlockItem + extends Omit { tabName: string; - title: string; - text: string; + /** + * @deprecated Use array links from ContentBlockProps instead + */ link?: LinkProps; image?: ThemedImage; - disableCompress?: boolean; caption?: string; media?: ThemedMediaProps; - links?: LinkProps[]; } export interface TabsBlockProps extends BlockHeaderProps, Animatable { + tabsColSizes?: GridColumnSizesType; + centered?: boolean; + direction?: MediaDirection; items: TabsBlockItem[]; } diff --git a/src/sub-blocks/Content/README.md b/src/sub-blocks/Content/README.md index 9c08683f4..7063d49c4 100644 --- a/src/sub-blocks/Content/README.md +++ b/src/sub-blocks/Content/README.md @@ -7,3 +7,17 @@ [`links?: Link[]` — An array with link objects](?path=/story/information--common-types&viewMode=docs#link---link) [`buttons?: Button[]` — An array with button objects](?path=/story/information--common-types&viewMode=docs#button---button) + +`centered?: false | true` - Aligns all content to the center ('false' by default) + +`theme?: 'default' | 'dark' | 'light'` — Component's theme: default, dark, or monochrome light ('default' by default). + +- `size?: 's' | 'l'` — Component's size that defines font sizes ('l' by default) + +`сolSizes?: Object` — Width of buttons tabs, the value ranges from 1 to 12 columns. If 12 columns, buttons takes up the entire width of the row. + +- `all: number` — On all screens. +- `sm: number` — On a screen wider than 577px. +- `md: number` — On a screen wider than 769px. +- `lg: number` — On a screen wider than 1081px. +- `xl: number` — On a screen wider than 1185px. diff --git a/src/text-transform/blocks.ts b/src/text-transform/blocks.ts index d56fd19b5..abb359734 100644 --- a/src/text-transform/blocks.ts +++ b/src/text-transform/blocks.ts @@ -2,7 +2,6 @@ import _ from 'lodash'; import { Block, BlockType, - SubBlockType, ContentBlockProps, ExtendedFeaturesItem, PriceDetailedProps, @@ -10,6 +9,7 @@ import { PriceDetailsSettingsProps, PromoFeaturesItem, SliderProps, + SubBlockType, TableProps, TitleProps, } from '../models'; @@ -46,8 +46,6 @@ export const createItemsParser = (fields: string[]) => (transformer: Transformer } }); -const parseItems = createItemsParser(['title', 'text']); - function parseTableBlock(transformer: Transformer, content: TableProps) { const legend = content?.legend; @@ -89,10 +87,16 @@ const parseTitle = (transformer: Transformer, title: TitleProps | string) => ? {...title, text: transformer(title.text)} : title && transformer(title); +const parseItemsTitle = (transformer: Transformer, items: ExtendedFeaturesItem[]) => + items.map(({title, ...rest}) => ({ + title: title && parseTitle(transformer, title), + ...rest, + })); + function parsePriceDetailedBlock(transformer: Transformer, block: PriceDetailedProps) { const {priceType} = block; - const transformedBlockItems = block.items.map((item) => { + block.items = block.items.map((item) => { const {description, items: details = []} = item; if (priceType === 'marked-list') { @@ -114,8 +118,6 @@ function parsePriceDetailedBlock(transformer: Transformer, block: PriceDetailedP return item; }); - block.items = transformedBlockItems; - return block; } @@ -291,7 +293,12 @@ const config: BlocksConfig = { { fields: ['items'], transformer: yfmTransformer, - parser: parseItems, + parser: createItemsParser(['text', 'additionalInfo']), + }, + { + fields: ['items'], + transformer: typografTransformer, + parser: parseItemsTitle, }, ], [BlockType.TableBlock]: [