diff --git a/.storybook/utils.ts b/.storybook/utils.ts index c2b854b56..205a9f1b9 100644 --- a/.storybook/utils.ts +++ b/.storybook/utils.ts @@ -1,3 +1,26 @@ import yfm from '@diplodoc/transform'; +import {TitleItemProps} from '../src'; export const yfmTransform = (content: string) => yfm(content).result.html; +export const yfmTransformInline = (content: string) => + yfm(content, {renderInline: true}).result.html; +export const transformTitle = (title: string | TitleItemProps) => { + if (!title) { + return undefined; + } + + if (typeof title === 'string') { + return yfmTransformInline(title); + } + + const {text, ...rest} = title; + + return {...rest, text: yfmTransformInline(text)}; +}; +export const transformOptionalTitle = (title?: string | TitleItemProps) => { + if (!title) { + return undefined; + } + + return transformTitle(title); +}; diff --git a/package-lock.json b/package-lock.json index 768e69a5a..9b1b8a3ae 100644 --- a/package-lock.json +++ b/package-lock.json @@ -127,7 +127,7 @@ "webpack-shell-plugin-next": "^2.3.1" }, "peerDependencies": { - "@diplodoc/transform": "^4.10.4", + "@diplodoc/transform": "^4.28.2", "@gravity-ui/uikit": "^6.0.0", "react": "^16.0.0 || ^17.0.0 || ^18.0.0" } @@ -3589,9 +3589,9 @@ } }, "node_modules/@diplodoc/tabs-extension": { - "version": "2.0.18", - "resolved": "https://registry.npmjs.org/@diplodoc/tabs-extension/-/tabs-extension-2.0.18.tgz", - "integrity": "sha512-O3N9Xi2omiQqtdr6wdqrQISMHPx77X0sAJ1JHXhivPyc3KWi5BiE1KBypXYIishLUZKJD8dPcT1bbDm7mRVQ8w==", + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@diplodoc/tabs-extension/-/tabs-extension-3.3.0.tgz", + "integrity": "sha512-f+LRsmv0uDnYtqBytLbZQiz7GTBedXrQlagSSU2j/sgMZ8dsA0D9YHJpCQdUTbGg3U2jYxMI2+EJaYrVbnT4JQ==", "dev": true, "peerDependencies": { "react": "^16.8.0 || ^17.0.0 || ^18.0.0" @@ -3603,18 +3603,18 @@ } }, "node_modules/@diplodoc/transform": { - "version": "4.10.8", - "resolved": "https://registry.npmjs.org/@diplodoc/transform/-/transform-4.10.8.tgz", - "integrity": "sha512-Vr8wBIv/1qqsXLxkThrOJJ2KUNmTKGOwgLkRd9IzonlfyvJeIjPGcYMLVHvZ+M7WCYzloEdrfFAb1wEDtXtJbA==", + "version": "4.28.2", + "resolved": "https://registry.npmjs.org/@diplodoc/transform/-/transform-4.28.2.tgz", + "integrity": "sha512-XbcsE/U3YkoBoyEjeY2K4ELq3W+kOAFD1NizuTiWfbir2luTWheCwtzesaWB5DgWD7EvuG92czExWEs3j4SrjQ==", "dev": true, "dependencies": { - "@diplodoc/tabs-extension": "^2.0.18", - "chalk": "4.1.2", + "@diplodoc/tabs-extension": "^3.3.0", + "chalk": "^4.1.2", "cheerio": "^1.0.0-rc.12", "css": "^3.0.0", "cssfilter": "0.0.10", "get-root-node-polyfill": "1.0.0", - "github-slugger": "1.4.0", + "github-slugger": "^1.5.0", "js-yaml": "^4.1.0", "lodash": "4.17.21", "markdown-it": "^13.0.2", @@ -3622,10 +3622,11 @@ "markdown-it-deflist": "2.1.0", "markdown-it-meta": "0.0.1", "markdown-it-sup": "1.0.0", - "markdownlint": "^0.25.1", + "markdownlint": "^0.32.1", "markdownlint-rule-helpers": "0.17.2", "sanitize-html": "^2.11.0", - "slugify": "1.6.5" + "slugify": "1.6.5", + "svgo": "^3.2.0" }, "peerDependencies": { "highlight.js": "^10.0.3 || ^11" @@ -3648,9 +3649,9 @@ } }, "node_modules/@diplodoc/transform/node_modules/github-slugger": { - "version": "1.4.0", - "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.4.0.tgz", - "integrity": "sha512-w0dzqw/nt51xMVmlaV1+JRzN+oCa1KfcgGEWhxUG16wbdA+Xnt/yoFO8Z8x/V82ZcZ0wy6ln9QDup5avbhiDhQ==", + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/github-slugger/-/github-slugger-1.5.0.tgz", + "integrity": "sha512-wIh+gKBI9Nshz2o46B0B3f5k/W+WI9ZAv6y5Dn5WJ5SK1t0TnDimB4WE5rmTD05ZAIn8HALCZVmCsvj0w0v0lw==", "dev": true }, "node_modules/@diplodoc/transform/node_modules/source-map": { @@ -7579,6 +7580,15 @@ "node": ">= 10" } }, + "node_modules/@trysound/sax": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/@trysound/sax/-/sax-0.2.0.tgz", + "integrity": "sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==", + "dev": true, + "engines": { + "node": ">=10.13.0" + } + }, "node_modules/@tsconfig/node10": { "version": "1.0.9", "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", @@ -11426,6 +11436,19 @@ "url": "https://github.com/sponsors/fb55" } }, + "node_modules/css-tree": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz", + "integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.30", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0" + } + }, "node_modules/css-what": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", @@ -11487,6 +11510,39 @@ "integrity": "sha512-FAaLDaplstoRsDR8XGYH51znUN0UY7nMc6Z9/fvE8EXGwvJE9hu7W2vHwx1+bd6gCYnln9nLbzxFTrcO9YQDZw==", "dev": true }, + "node_modules/csso": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/csso/-/csso-5.0.5.tgz", + "integrity": "sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==", + "dev": true, + "dependencies": { + "css-tree": "~2.2.0" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/css-tree": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.2.1.tgz", + "integrity": "sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==", + "dev": true, + "dependencies": { + "mdn-data": "2.0.28", + "source-map-js": "^1.0.1" + }, + "engines": { + "node": "^10 || ^12.20.0 || ^14.13.0 || >=15.0.0", + "npm": ">=7.0.0" + } + }, + "node_modules/csso/node_modules/mdn-data": { + "version": "2.0.28", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.28.tgz", + "integrity": "sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==", + "dev": true + }, "node_modules/cssom": { "version": "0.5.0", "resolved": "https://registry.npmjs.org/cssom/-/cssom-0.5.0.tgz", @@ -19809,15 +19865,28 @@ } }, "node_modules/markdownlint": { - "version": "0.25.1", - "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.25.1.tgz", - "integrity": "sha512-AG7UkLzNa1fxiOv5B+owPsPhtM4D6DoODhsJgiaNg1xowXovrYgOnLqAgOOFQpWOlHFVQUzjMY5ypNNTeov92g==", + "version": "0.32.1", + "resolved": "https://registry.npmjs.org/markdownlint/-/markdownlint-0.32.1.tgz", + "integrity": "sha512-3sx9xpi4xlHlokGyHO9k0g3gJbNY4DI6oNEeEYq5gQ4W7UkiJ90VDAnuDl2U+yyXOUa6BX+0gf69ZlTUGIBp6A==", "dev": true, "dependencies": { - "markdown-it": "12.3.2" + "markdown-it": "13.0.2", + "markdownlint-micromark": "0.1.7" }, "engines": { - "node": ">=12" + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/DavidAnson" + } + }, + "node_modules/markdownlint-micromark": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/markdownlint-micromark/-/markdownlint-micromark-0.1.7.tgz", + "integrity": "sha512-BbRPTC72fl5vlSKv37v/xIENSRDYL/7X/XoFzZ740FGEbs9vZerLrIkFRY0rv7slQKxDczToYuMmqQFN61fi4Q==", + "dev": true, + "engines": { + "node": ">=16" } }, "node_modules/markdownlint-rule-helpers": { @@ -19829,40 +19898,6 @@ "node": ">=12" } }, - "node_modules/markdownlint/node_modules/entities": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/entities/-/entities-2.1.0.tgz", - "integrity": "sha512-hCx1oky9PFrJ611mf0ifBLBRW8lUUVRlFolb5gWRfIELabBlbp9xZvrqZLZAs+NxFnbfQoeGd8wDkygjg7U85w==", - "dev": true, - "funding": { - "url": "https://github.com/fb55/entities?sponsor=1" - } - }, - "node_modules/markdownlint/node_modules/linkify-it": { - "version": "3.0.3", - "resolved": "https://registry.npmjs.org/linkify-it/-/linkify-it-3.0.3.tgz", - "integrity": "sha512-ynTsyrFSdE5oZ/O9GEf00kPngmOfVwazR5GKDq6EYfhlpFug3J2zybX56a2PRRpc9P+FuSoGNAwjlbDs9jJBPQ==", - "dev": true, - "dependencies": { - "uc.micro": "^1.0.1" - } - }, - "node_modules/markdownlint/node_modules/markdown-it": { - "version": "12.3.2", - "resolved": "https://registry.npmjs.org/markdown-it/-/markdown-it-12.3.2.tgz", - "integrity": "sha512-TchMembfxfNVpHkbtriWltGWc+m3xszaRD0CZup7GFFhzIgQqxIfn3eGj1yZpfuflzPvfkt611B2Q/Bsk1YnGg==", - "dev": true, - "dependencies": { - "argparse": "^2.0.1", - "entities": "~2.1.0", - "linkify-it": "^3.0.1", - "mdurl": "^1.0.1", - "uc.micro": "^1.0.5" - }, - "bin": { - "markdown-it": "bin/markdown-it.js" - } - }, "node_modules/marked": { "version": "0.7.0", "resolved": "https://registry.npmjs.org/marked/-/marked-0.7.0.tgz", @@ -20257,6 +20292,12 @@ "url": "https://opencollective.com/unified" } }, + "node_modules/mdn-data": { + "version": "2.0.30", + "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz", + "integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==", + "dev": true + }, "node_modules/mdurl": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/mdurl/-/mdurl-1.0.1.tgz", @@ -28244,6 +28285,99 @@ "integrity": "sha512-ovssysQTa+luh7A5Weu3Rta6FJlFBBbInjOh722LIt6klpU2/HtdUbszju/G4devcvk8PGt7FCLv5wftu3THUA==", "dev": true }, + "node_modules/svgo": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/svgo/-/svgo-3.3.2.tgz", + "integrity": "sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==", + "dev": true, + "dependencies": { + "@trysound/sax": "0.2.0", + "commander": "^7.2.0", + "css-select": "^5.1.0", + "css-tree": "^2.3.1", + "css-what": "^6.1.0", + "csso": "^5.0.5", + "picocolors": "^1.0.0" + }, + "bin": { + "svgo": "bin/svgo" + }, + "engines": { + "node": ">=14.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/svgo" + } + }, + "node_modules/svgo/node_modules/commander": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-7.2.0.tgz", + "integrity": "sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==", + "dev": true, + "engines": { + "node": ">= 10" + } + }, + "node_modules/svgo/node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dev": true, + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/svgo/node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dev": true, + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/svgo/node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dev": true, + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, "node_modules/swiper": { "version": "6.8.4", "resolved": "https://registry.npmjs.org/swiper/-/swiper-6.8.4.tgz", diff --git a/package.json b/package.json index 8ff67f0e0..421cc47cd 100644 --- a/package.json +++ b/package.json @@ -116,7 +116,7 @@ "uuid": "^9.0.0" }, "peerDependencies": { - "@diplodoc/transform": "^4.10.4", + "@diplodoc/transform": "^4.28.2", "@gravity-ui/uikit": "^6.0.0", "react": "^16.0.0 || ^17.0.0 || ^18.0.0" }, diff --git a/playwright/README.md b/playwright/README.md index 4f5031f32..5973bd60b 100644 --- a/playwright/README.md +++ b/playwright/README.md @@ -136,3 +136,4 @@ - `npm run playwright:docker` - run tests using docker - `npm run playwright:docker:update` - update screenshots using docker - `npm run playwright:docker:clear-cache` - clear node_modules cache for docker container and clear cache vite +- `npx playwright show-report ./playwright-report-docker` - show report diff --git a/playwright/playwright.config.ts b/playwright/playwright.config.ts index a8e7c7f6f..258c2b12b 100644 --- a/playwright/playwright.config.ts +++ b/playwright/playwright.config.ts @@ -72,7 +72,6 @@ const config: PlaywrightTestConfig = { icon: true, }, }), - commonjs(), ], resolve: { diff --git a/src/blocks/Banner/__stories__/Banner.stories.tsx b/src/blocks/Banner/__stories__/Banner.stories.tsx index c72dd87df..72a410c6e 100644 --- a/src/blocks/Banner/__stories__/Banner.stories.tsx +++ b/src/blocks/Banner/__stories__/Banner.stories.tsx @@ -2,6 +2,7 @@ import React from 'react'; import {Meta, StoryFn} from '@storybook/react'; +import {yfmTransformInline} from '../../../../.storybook/utils'; import {PageConstructor} from '../../../containers/PageConstructor'; import {BannerBlockModel, BannerBlockProps} from '../../../models'; import Banner from '../Banner'; @@ -27,5 +28,8 @@ const WithThemeTemplate: StoryFn = (args) => ( export const Default = DefaultTemplate.bind({}); export const DarkTheme = WithThemeTemplate.bind({}); -Default.args = data.default.content as BannerBlockProps; +Default.args = { + ...data.default.content, + title: yfmTransformInline(data.default.content.title), +} as BannerBlockProps; DarkTheme.args = data.darkTheme.content as BannerBlockProps; diff --git a/src/blocks/CardLayout/__stories__/CardLayout.stories.tsx b/src/blocks/CardLayout/__stories__/CardLayout.stories.tsx index de2b76f29..864b86ade 100644 --- a/src/blocks/CardLayout/__stories__/CardLayout.stories.tsx +++ b/src/blocks/CardLayout/__stories__/CardLayout.stories.tsx @@ -2,6 +2,7 @@ import React, {Fragment} from 'react'; import {Meta, StoryFn} from '@storybook/react'; +import {yfmTransformInline} from '../../../../.storybook/utils'; import {PageConstructor} from '../../../containers/PageConstructor'; import {CardLayoutBlockModel, CardLayoutBlockProps, SubBlockModels} from '../../../models'; import CardLayout from '../CardLayout'; @@ -43,14 +44,17 @@ const DefaultTemplate: StoryFn = (args) => ( children: [ { ...data.cards.priceCard, + title: yfmTransformInline(data.cards.priceCard.title), buttons: [data.buttons.outlined], }, { ...data.cards.priceCard, + title: yfmTransformInline(data.cards.priceCard.title), buttons: [data.buttons.action], }, { ...data.cards.priceCard, + title: yfmTransformInline(data.cards.priceCard.title), buttons: [data.buttons.monochrome], }, ], diff --git a/src/blocks/CardLayout/__stories__/data.json b/src/blocks/CardLayout/__stories__/data.json index 77e3b7104..57783d42f 100644 --- a/src/blocks/CardLayout/__stories__/data.json +++ b/src/blocks/CardLayout/__stories__/data.json @@ -126,7 +126,7 @@ } }, "content": { - "title": "Lorem ipsum", + "title": "Lorem ipsum", "text": "Dolor sit amet" } }, @@ -149,7 +149,7 @@ } }, "content": { - "title": "Lorem ipsum", + "title": "Lorem ipsum", "text": "Dolor sit amet" } }, diff --git a/src/blocks/ContentLayout/__stories__/ContentLayout.stories.tsx b/src/blocks/ContentLayout/__stories__/ContentLayout.stories.tsx index cdaa86fce..a571cdc58 100644 --- a/src/blocks/ContentLayout/__stories__/ContentLayout.stories.tsx +++ b/src/blocks/ContentLayout/__stories__/ContentLayout.stories.tsx @@ -2,7 +2,7 @@ import React from 'react'; import {Meta, StoryFn} from '@storybook/react'; -import {yfmTransform} from '../../../../.storybook/utils'; +import {yfmTransform, yfmTransformInline} from '../../../../.storybook/utils'; import {PageConstructor} from '../../../containers/PageConstructor/PageConstructor'; import { ButtonProps, @@ -20,10 +20,15 @@ export default { component: Content, } as Meta; -const getSizeTitle = (size: string) => data.size.title.replace('{{size}}', size); -const getThemeTitle = (theme: string) => data.theme.title.replace('{{theme}}', theme); +const getSizeTitle = (size: string) => { + console.log(yfmTransformInline(data.size.title.replace('{{size}}', size)), data.size.title); + return yfmTransformInline(data.size.title.replace('{{size}}', size)); +}; + +const getThemeTitle = (theme: string) => + yfmTransformInline(data.theme.title.replace('{{theme}}', theme)); const getTextWidthTitle = (textWidth: string) => - data.textWidth.title.replace('{{textWidth}}', textWidth); + yfmTransformInline(data.textWidth.title.replace('{{textWidth}}', textWidth)); const DefaultTemplate: StoryFn = (args) => ( = (args) => ( ...args, textContent: { ...args.textContent, + title: + args.textContent.title && typeof args.textContent.title === 'string' + ? yfmTransformInline(args.textContent.title) + : undefined, additionalInfo: yfmTransform(data.common.additionalInfo), }, }, { ...args, - textContent: {...args.textContent, links: data.common.links as LinkProps[]}, + textContent: { + ...args.textContent, + title: + args.textContent.title && typeof args.textContent.title === 'string' + ? yfmTransformInline(args.textContent.title) + : undefined, + links: data.common.links as LinkProps[], + }, }, { ...args, textContent: { ...args.textContent, + title: + args.textContent.title && typeof args.textContent.title === 'string' + ? yfmTransformInline(args.textContent.title) + : undefined, buttons: data.common.buttons as ButtonProps[], }, }, @@ -51,6 +71,10 @@ const DefaultTemplate: StoryFn = (args) => ( ...args, textContent: { ...args.textContent, + title: + args.textContent.title && typeof args.textContent.title === 'string' + ? yfmTransformInline(args.textContent.title) + : undefined, list: data.common.list.map((item) => { return { ...item, diff --git a/src/blocks/ExtendedFeatures/ExtendedFeatures.scss b/src/blocks/ExtendedFeatures/ExtendedFeatures.scss index 03af22206..3a3094ef1 100644 --- a/src/blocks/ExtendedFeatures/ExtendedFeatures.scss +++ b/src/blocks/ExtendedFeatures/ExtendedFeatures.scss @@ -22,15 +22,22 @@ $block: '.#{$ns}ExtendedFeaturesBlock'; padding-right: $indentM; } + &-title-container { + margin: inherit; + display: block; + margin-block: 0 $indentXXXS; + } + &-title { - @include heading4(); + @include add-specificity(&) { + @include heading4(); - display: block; - position: relative; - margin-bottom: $indentXXXS; + position: relative; + margin-bottom: $indentXXXS; - a { - @include link(); + a { + @include link(); + } } } diff --git a/src/blocks/ExtendedFeatures/ExtendedFeatures.tsx b/src/blocks/ExtendedFeatures/ExtendedFeatures.tsx index f9ad4ab4b..a3c894118 100644 --- a/src/blocks/ExtendedFeatures/ExtendedFeatures.tsx +++ b/src/blocks/ExtendedFeatures/ExtendedFeatures.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import {AnimateBlock, HTML, Title} from '../../components/'; +import {AnimateBlock, Title, YFMWrapper} from '../../components/'; import Image from '../../components/Image/Image'; import {getMediaImage} from '../../components/Media/Image/utils'; import {useTheme} from '../../context/theme'; @@ -63,21 +63,21 @@ export const ExtendedFeaturesBlock = ({ )}
- {itemTitle && - React.createElement( - itemTitleHeadingTag, - { - className: b('item-title'), - }, - - {itemTitle} - {label && ( - - {label} - - )} - , - )} + {itemTitle && ( + + {label && ( + {label} + )} + + )} = (args) => ( const extendedFeaturesItems = (items: ExtendedFeaturesItem[]) => { return items.map((item) => ({ ...item, + title: transformOptionalTitle(item.title), list: item.list?.map((listItem) => ({ ...listItem, + title: transformOptionalTitle(listItem.title), text: listItem?.text && yfmTransform(listItem.text), })), text: item.text && yfmTransform(item.text), @@ -48,6 +50,7 @@ const ColSizesTemplate: StoryFn = (args) => ( { ...args, ...data.colSizes.four, + title: transformOptionalTitle(data.colSizes.four.title), description: yfmTransform(data.colSizes.four.description), items: extendedFeaturesItems( data.colSizes.four.items as ExtendedFeaturesItem[], @@ -56,11 +59,13 @@ const ColSizesTemplate: StoryFn = (args) => ( { ...args, ...data.colSizes.three, + title: transformOptionalTitle(data.colSizes.three.title), description: yfmTransform(data.colSizes.three.description), }, { ...args, ...data.colSizes.two, + title: transformOptionalTitle(data.colSizes.two.title), description: yfmTransform(data.colSizes.two.description), items: extendedFeaturesItems(data.colSizes.two.items as ExtendedFeaturesItem[]), }, @@ -75,6 +80,7 @@ export const ColSizes = ColSizesTemplate.bind({}); const DefaultArgs = { ...data.default.content, + title: transformOptionalTitle(data.default.content.title), description: yfmTransform(data.default.content.description), items: extendedFeaturesItems(data.default.content.items as ExtendedFeaturesItem[]), }; diff --git a/src/blocks/ExtendedFeatures/__stories__/data.json b/src/blocks/ExtendedFeatures/__stories__/data.json index 7a3968855..6252207e8 100644 --- a/src/blocks/ExtendedFeatures/__stories__/data.json +++ b/src/blocks/ExtendedFeatures/__stories__/data.json @@ -3,8 +3,7 @@ "content": { "type": "extended-features-block", "title": { - "text": "Lorem ipsum dolor sit amet", - "textSize": "m" + "text": "Lorem ipsum dolor sit amet" }, "description": "Three **cards in a row on the desktop**, two cards in a row on a tablet, one card in a row on a mobile phone.", "items": [ diff --git a/src/blocks/Header/Header.scss b/src/blocks/Header/Header.scss index 796ab7edd..d5b097afb 100644 --- a/src/blocks/Header/Header.scss +++ b/src/blocks/Header/Header.scss @@ -24,17 +24,19 @@ $backgroundWidth: 1440px; height: 100%; &_theme_dark { - --g-color-line-focus: var(--pc-color-line-focus-dark); + @include add-specificity(&) { + --g-color-line-focus: var(--pc-color-line-focus-dark); - #{$block}__title, - #{$block}__overtitle { - color: var(--g-color-text-light-primary); - } - - #{$block}__description { - .yfm { + #{$block}__title, + #{$block}__overtitle { color: var(--g-color-text-light-primary); } + + #{$block}__description { + .yfm { + color: var(--g-color-text-light-primary); + } + } } } @@ -72,15 +74,21 @@ $backgroundWidth: 1440px; } &__title { - @include heading1(); + @include add-specificity(&) { + @include heading1(); - position: relative; + position: relative; - a { - @include link(); + a { + @include link(); + } } } + &__title-container { + margin: 0; + } + &__description { margin-top: $indentXS; diff --git a/src/blocks/Header/Header.tsx b/src/blocks/Header/Header.tsx index 27576b749..022ee7fb7 100644 --- a/src/blocks/Header/Header.tsx +++ b/src/blocks/Header/Header.tsx @@ -2,7 +2,7 @@ import React, {useContext} from 'react'; import {useUniqId} from '@gravity-ui/uikit'; -import {Button, HTML, Media, RouterLink} from '../../components'; +import {Button, Media, RouterLink} from '../../components'; import HeaderBreadcrumbs from '../../components/HeaderBreadcrumbs/HeaderBreadcrumbs'; import {getMediaImage} from '../../components/Media/Image/utils'; import YFMWrapper from '../../components/YFMWrapper/YFMWrapper'; @@ -134,14 +134,29 @@ export const HeaderBlock = (props: React.PropsWithChildren > {overtitle && ( -
- {overtitle} -
+ )} -

+ {status} - {renderTitle ? renderTitle(title) : {title}} -

+ {renderTitle ? renderTitle(title) : null} +
{description && (
; -const getSizeTitle = (size: string) => data.size.title.replace('{{size}}', size); -const getImageTitle = (text: string) => data.image.title.replace('{{text}}', text); +const getSizeTitle = (size: string) => + yfmTransformInline(data.size.title.replace('{{size}}', size)); +const getImageTitle = (text: string) => + yfmTransformInline(data.image.title.replace('{{text}}', text)); const getVerticalOffsetTitle = (offset: string) => - data.verticalOffset.title.replace('{{offset}}', offset); -const getBreadcrumbsTitle = (theme: string) => data.breadcrumbs.title.replace('{{theme}}', theme); + yfmTransformInline(data.verticalOffset.title.replace('{{offset}}', offset)); +const getBreadcrumbsTitle = (theme: string) => + yfmTransformInline(data.breadcrumbs.title.replace('{{theme}}', theme)); export default { title: 'Blocks/Header', @@ -36,6 +39,7 @@ export default { const DefaultArgs = { ...data.default.content, + title: yfmTransformInline(data.default.content.title), description: yfmTransform(data.default.content.description), }; @@ -92,12 +96,12 @@ const BackgroundTemplate: StoryFn = (args) => ( @@ -107,7 +111,7 @@ const FullWithBackgroundTemplate: StoryFn = (args) => ( = (args) => ( /> = (args) => ( = (args) => ( />
) => { - if (!children) { - return null; + contentPosition = 'start', + tagName = 'span', + onlyContent = false, + ...rest +}: HTMLProps) => { + const renderedContent = useMemo(() => { + return content + ? React.createElement(selectTagName({content, block, tagName, children}), { + dangerouslySetInnerHTML: {__html: content}, + className: contentClassName, + 'data-qa': qa, + ...rest, + }) + : null; + }, [block, children, content, contentClassName, qa, rest, tagName]); + + if (onlyContent) { + return renderedContent; + } + + if (children) { + return React.createElement( + tagName, + { + className, + }, + contentPosition === 'start' ? renderedContent : null, + children, + contentPosition === 'end' ? renderedContent : null, + ); } - return React.createElement(block || hasBlockTag(children) ? 'div' : 'span', { - dangerouslySetInnerHTML: {__html: children}, - className, - itemProp, - id, - 'data-qa': qa, - }); + return renderedContent; }; export default HTML; diff --git a/src/components/MetaInfo/MetaInfo.scss b/src/components/MetaInfo/MetaInfo.scss index 151ab98c0..afb8c0b03 100644 --- a/src/components/MetaInfo/MetaInfo.scss +++ b/src/components/MetaInfo/MetaInfo.scss @@ -10,8 +10,10 @@ $block: '.#{$ns}meta-info'; align-items: center; &__item { - &:not(:first-child) { - margin-left: $indentXS; + @include add-specificity(&) { + &:not(:first-child) { + margin-left: $indentXS; + } } } } diff --git a/src/components/MetaInfo/MetaInfo.tsx b/src/components/MetaInfo/MetaInfo.tsx index 0dda2f9fd..fe477a8cb 100644 --- a/src/components/MetaInfo/MetaInfo.tsx +++ b/src/components/MetaInfo/MetaInfo.tsx @@ -18,7 +18,7 @@ const MetaInfo = ({items, className}: MetaInfpoProps) => ( ))} diff --git a/src/components/Table/Table.scss b/src/components/Table/Table.scss index a40e9a2fc..deccd3c9b 100644 --- a/src/components/Table/Table.scss +++ b/src/components/Table/Table.scss @@ -96,7 +96,9 @@ $block: '.#{$ns}table'; } &__legent-item-text { - margin-left: 6px; + @include add-specificity(&) { + margin-left: 6px; + } } @media (max-width: map-get($gridBreakpoints, 'sm')) { diff --git a/src/components/Table/Table.tsx b/src/components/Table/Table.tsx index 920fd2b05..0262f1421 100644 --- a/src/components/Table/Table.tsx +++ b/src/components/Table/Table.tsx @@ -3,7 +3,7 @@ import React from 'react'; import {Check, Minus} from '@gravity-ui/icons'; import {Icon} from '@gravity-ui/uikit'; -import {HTML, YFMWrapper} from '../'; +import {YFMWrapper} from '../'; import {ClassNameProps, Justify, LegendTableMarkerType, TableProps} from '../../models'; import {block} from '../../utils'; @@ -47,7 +47,13 @@ export default class Table extends React.Component {legend && i && j ? ( this.renderMarker(marker, cell) ) : ( - {cell} + )}
))} @@ -81,7 +87,7 @@ export default class Table extends React.Component
{this.renderMarker(marker, String(index))} { const {hostname} = useContext(LocationContext); const textMarkup = ( - {text} + {custom && (   diff --git a/src/components/YFMWrapper/YFMWrapper.tsx b/src/components/YFMWrapper/YFMWrapper.tsx index b726940ad..5de5d254e 100644 --- a/src/components/YFMWrapper/YFMWrapper.tsx +++ b/src/components/YFMWrapper/YFMWrapper.tsx @@ -1,6 +1,6 @@ /* we won't use 'pc' class prefix here to let you opportunity to define yfm styles in your project via global 'yfm' class */ -import React from 'react'; +import React, {PropsWithChildren} from 'react'; import toSnakeCase from 'snakecase-keys'; @@ -8,24 +8,28 @@ import {HTML} from '../../components'; import {ClassNameProps, Modifiers} from '../../models'; import {QAProps} from '../../models/common'; import {cn} from '../../utils'; +import {HTMLExtraProps} from '../HTML/HTML'; const yfm = cn('yfm'); -export interface YFMWrapperProps extends ClassNameProps, QAProps { +export interface YFMWrapperProps + extends PropsWithChildren, + ClassNameProps, + QAProps, + HTMLExtraProps, + React.HTMLProps<{}> { content: string; modifiers?: Modifiers; itemProp?: string; id?: string; } -const YFMWrapper = ({content, modifiers, className, itemProp, id, qa}: YFMWrapperProps) => ( +const YFMWrapper = ({contentClassName, modifiers, children, ...rest}: YFMWrapperProps) => ( - {content} + {children} ); diff --git a/src/models/common.ts b/src/models/common.ts index 32a312157..638142dc9 100644 --- a/src/models/common.ts +++ b/src/models/common.ts @@ -62,3 +62,5 @@ export type AnalyticsEventsProp = AnalyticsEvent | AnalyticsEvent[]; export interface AnalyticsEventsBase { analyticsEvents?: AnalyticsEventsProp; } + +export type TagName = 'span' | 'div' | 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6' | 'section' | 'p'; diff --git a/src/sub-blocks/BannerCard/BannerCard.scss b/src/sub-blocks/BannerCard/BannerCard.scss index 5db86b3e2..5693e8124 100644 --- a/src/sub-blocks/BannerCard/BannerCard.scss +++ b/src/sub-blocks/BannerCard/BannerCard.scss @@ -28,10 +28,12 @@ $block: '.#{$ns}banner-card'; } &__title { - @include heading2(); + @include add-specificity(&) { + @include heading2(); - a { - @include link(); + a { + @include link(); + } } } @@ -57,12 +59,14 @@ $block: '.#{$ns}banner-card'; } &__subtitle { - display: inline-block; - margin-top: 8px; - @include subtitle(); - - & p { + @include add-specificity(&) { + display: inline-block; + margin-top: $indentXXXS; @include subtitle(); + + & p { + @include subtitle(); + } } } diff --git a/src/sub-blocks/BannerCard/BannerCard.tsx b/src/sub-blocks/BannerCard/BannerCard.tsx index 3510a7d2d..c802830fb 100644 --- a/src/sub-blocks/BannerCard/BannerCard.tsx +++ b/src/sub-blocks/BannerCard/BannerCard.tsx @@ -1,6 +1,6 @@ import React from 'react'; -import {BackgroundImage, Button, HTML, RouterLink, YFMWrapper} from '../../components'; +import {BackgroundImage, Button, RouterLink, YFMWrapper} from '../../components'; import {useTheme} from '../../context/theme'; import {BannerCardProps} from '../../models'; import {block, getThemedValue} from '../../utils'; @@ -32,12 +32,17 @@ export const BannerCard = (props: BannerCardProps) => {
-

- {title} -

+ {subtitle && ( diff --git a/src/sub-blocks/Content/Content.tsx b/src/sub-blocks/Content/Content.tsx index 230bc45aa..bbd760ef8 100644 --- a/src/sub-blocks/Content/Content.tsx +++ b/src/sub-blocks/Content/Content.tsx @@ -75,6 +75,7 @@ const Content = (props: ContentProps) => { content={text} modifiers={{constructor: true, [`constructor-size-${size}`]: true}} id={textId} + qa={qaAttributes.list} />
)} diff --git a/src/sub-blocks/PriceCard/PriceCard.scss b/src/sub-blocks/PriceCard/PriceCard.scss index 3ee6d7552..7b9b1ca1e 100644 --- a/src/sub-blocks/PriceCard/PriceCard.scss +++ b/src/sub-blocks/PriceCard/PriceCard.scss @@ -63,8 +63,10 @@ $block: '.#{$ns}price-card'; } &__title { - @include text-size(subheader-3); - margin-bottom: $indentSM; + @include add-specificity(&) { + @include text-size(subheader-3); + margin-bottom: $indentSM; + } } &__price { diff --git a/src/sub-blocks/PriceCard/PriceCard.tsx b/src/sub-blocks/PriceCard/PriceCard.tsx index 2276d243d..3a3bcac9a 100644 --- a/src/sub-blocks/PriceCard/PriceCard.tsx +++ b/src/sub-blocks/PriceCard/PriceCard.tsx @@ -2,7 +2,7 @@ import React from 'react'; import Check from '@gravity-ui/icons/Check'; -import {BackgroundImage, Buttons, CardBase, ContentList, HTML, Links} from '../../components'; +import {BackgroundImage, Buttons, CardBase, ContentList, Links, YFMWrapper} from '../../components'; import {PriceCardProps} from '../../models'; import {block} from '../../utils'; @@ -30,7 +30,12 @@ const PriceCard = (props: PriceCardProps) => {
- {title} +
{price} diff --git a/src/sub-blocks/Quote/Quote.scss b/src/sub-blocks/Quote/Quote.scss index 62e667d29..9b42b28b9 100644 --- a/src/sub-blocks/Quote/Quote.scss +++ b/src/sub-blocks/Quote/Quote.scss @@ -5,15 +5,18 @@ $block: '.#{$ns}quote'; @mixin comma-type($name, $opening, $closing, $left-offset) { &_#{$name} { - &::before { - position: absolute; - left: $left-offset; - content: $opening; - } + @include add-specificity(&) { + &::before { + position: absolute; + left: $left-offset; + content: $opening; + } - #{$block}__text { - &::after { - content: $closing; + #{$block}__text { + &::after { + content: $closing; + left: auto; + } } } } diff --git a/src/sub-blocks/Quote/Quote.tsx b/src/sub-blocks/Quote/Quote.tsx index aac831b10..ac163ae43 100644 --- a/src/sub-blocks/Quote/Quote.tsx +++ b/src/sub-blocks/Quote/Quote.tsx @@ -1,6 +1,6 @@ import React, {useCallback} from 'react'; -import {Author, Button, HTML, Image, YFMWrapper} from '../../components'; +import {Author, Button, Image, YFMWrapper} from '../../components'; import {getMediaImage} from '../../components/Media/Image/utils'; import {useTheme} from '../../context/theme'; import {useAnalytics} from '../../hooks'; @@ -68,6 +68,8 @@ const Quote = (props: QuoteProps) => { const themedLogoProps = getThemedValue(logo, theme); const logoProps = getMediaImage(themedLogoProps); + const textLocal = yfmText || text; + return (
{
- {text && ( - - {text} - - )} - {yfmText && ( + {textLocal && ( )} diff --git a/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-BorderLine-light-chromium-linux.png b/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-BorderLine-light-chromium-linux.png index 821d371e3..6a552c3d2 100644 Binary files a/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-BorderLine-light-chromium-linux.png and b/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-BorderLine-light-chromium-linux.png differ diff --git a/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-BorderLine-light-webkit-linux.png b/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-BorderLine-light-webkit-linux.png index 43003caa7..f40bf9671 100644 Binary files a/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-BorderLine-light-webkit-linux.png and b/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-BorderLine-light-webkit-linux.png differ diff --git a/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-Default-light-chromium-linux.png b/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-Default-light-chromium-linux.png index e6d02464e..f281cd753 100644 Binary files a/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-Default-light-chromium-linux.png and b/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-Default-light-chromium-linux.png differ diff --git a/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-Default-light-webkit-linux.png b/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-Default-light-webkit-linux.png index db27e9e80..88487e219 100644 Binary files a/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-Default-light-webkit-linux.png and b/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-Default-light-webkit-linux.png differ diff --git a/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-QuoteTypes-light-chromium-linux.png b/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-QuoteTypes-light-chromium-linux.png index 62cc442ec..1be730823 100644 Binary files a/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-QuoteTypes-light-chromium-linux.png and b/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-QuoteTypes-light-chromium-linux.png differ diff --git a/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-QuoteTypes-light-webkit-linux.png b/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-QuoteTypes-light-webkit-linux.png index 57573e8e3..6ef401103 100644 Binary files a/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-QuoteTypes-light-webkit-linux.png and b/src/sub-blocks/Quote/__snapshots__/Quote.visual.test.tsx-snapshots/Quote-render-stories-QuoteTypes-light-webkit-linux.png differ diff --git a/src/sub-blocks/Quote/__stories__/Quote.stories.tsx b/src/sub-blocks/Quote/__stories__/Quote.stories.tsx index d58234db3..e089feb27 100644 --- a/src/sub-blocks/Quote/__stories__/Quote.stories.tsx +++ b/src/sub-blocks/Quote/__stories__/Quote.stories.tsx @@ -2,7 +2,7 @@ import React from 'react'; import {Meta, StoryFn} from '@storybook/react'; -import {yfmTransform} from '../../../../.storybook/utils'; +import {yfmTransformInline} from '../../../../.storybook/utils'; import {QuoteProps, QuoteType} from '../../../models'; import Quote from '../Quote'; @@ -36,7 +36,7 @@ export const DarkTheme = DefaultTemplate.bind({}); const DefaultArgs = { ...data.default.content, - yfmText: yfmTransform(data.default.content.yfmText), + yfmText: yfmTransformInline(data.default.content.yfmText), } as QuoteProps; Default.args = DefaultArgs; diff --git a/src/utils/blocks.ts b/src/utils/blocks.ts index 6a8c32655..a46cd9978 100644 --- a/src/utils/blocks.ts +++ b/src/utils/blocks.ts @@ -1,7 +1,9 @@ +import {ReactNode} from 'react'; + import camelCase from 'lodash/camelCase'; import flatten from 'lodash/flatten'; -import {ConstructorBlock, CustomConfig, PCShareSocialNetwork, TextSize} from '../models'; +import {ConstructorBlock, CustomConfig, PCShareSocialNetwork, TagName, TextSize} from '../models'; const BLOCK_ELEMENTS = [ 'div', @@ -58,9 +60,24 @@ export function getHeaderTag(size: TextSize) { } } -export function hasBlockTag(content: string): boolean { +type SelectVariantArgs = { + block?: boolean; + content?: string; + children?: ReactNode; + tagName?: TagName; +}; + +export function selectTagName({content, children, tagName}: SelectVariantArgs): string { + if (!children && tagName) { + return tagName; + } + + if (!content) { + return 'span'; + } + const regex = new RegExp(BLOCK_ELEMENTS_REGEX, 'g'); - return regex.test(content); + return regex.test(content) ? 'div' : 'span'; } export function getBlockKey(block: ConstructorBlock, index: number) {