@gravity-ui/page-constructor 4.1.1 → 4.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/cjs/blocks/ExtendedFeatures/ExtendedFeatures.js +7 -3
- package/build/cjs/blocks/FilterBlock/schema.d.ts +6 -0
- package/build/cjs/blocks/FilterBlock/schema.js +2 -2
- package/build/cjs/blocks/PromoFeaturesBlock/PromoFeaturesBlock.js +1 -1
- package/build/cjs/blocks/Questions/QuestionBlockItem/QuestionBlockItem.css +50 -0
- package/build/cjs/blocks/Questions/QuestionBlockItem/QuestionBlockItem.d.ts +2 -0
- package/build/cjs/blocks/Questions/QuestionBlockItem/QuestionBlockItem.js +27 -0
- package/build/cjs/blocks/Questions/Questions.css +0 -48
- package/build/cjs/blocks/Questions/Questions.js +7 -27
- package/build/cjs/blocks/Questions/models.d.ts +10 -0
- package/build/cjs/blocks/Questions/models.js +13 -0
- package/build/cjs/components/BackLink/BackLink.d.ts +2 -1
- package/build/cjs/components/BackLink/BackLink.js +2 -2
- package/build/cjs/components/FileLink/FileLink.js +2 -2
- package/build/cjs/components/FullscreenImage/FullscreenImage.js +1 -1
- package/build/cjs/components/FullscreenImage/i18n/en.json +2 -1
- package/build/cjs/components/FullscreenImage/i18n/ru.json +2 -1
- package/build/cjs/components/Image/i18n/en.json +1 -1
- package/build/cjs/components/Image/i18n/ru.json +1 -1
- package/build/cjs/components/Link/Link.d.ts +2 -2
- package/build/cjs/components/Link/Link.js +6 -6
- package/build/cjs/components/Media/Media.js +1 -2
- package/build/cjs/components/Media/Video/Video.js +3 -3
- package/build/cjs/components/ReactPlayer/ReactPlayer.js +4 -3
- package/build/cjs/components/ReactPlayer/i18n/en.json +3 -0
- package/build/cjs/components/ReactPlayer/i18n/index.d.ts +2 -0
- package/build/cjs/components/ReactPlayer/i18n/index.js +8 -0
- package/build/cjs/components/ReactPlayer/i18n/ru.json +3 -0
- package/build/cjs/components/constants.d.ts +0 -4
- package/build/cjs/components/constants.js +1 -5
- package/build/cjs/grid/Col/Col.d.ts +2 -1
- package/build/cjs/grid/Col/Col.js +2 -2
- package/build/cjs/models/constructor-items/blocks.d.ts +4 -0
- package/build/cjs/models/constructor-items/common.d.ts +7 -3
- package/build/cjs/sub-blocks/Content/ContentList/ContentList.js +11 -1
- package/build/cjs/sub-blocks/LayoutItem/utils.d.ts +1 -0
- package/build/cjs/utils/blocks.d.ts +1 -1
- package/build/cjs/utils/blocks.js +2 -2
- package/build/esm/blocks/ExtendedFeatures/ExtendedFeatures.js +7 -3
- package/build/esm/blocks/FilterBlock/schema.d.ts +6 -0
- package/build/esm/blocks/FilterBlock/schema.js +2 -2
- package/build/esm/blocks/PromoFeaturesBlock/PromoFeaturesBlock.js +1 -1
- package/build/esm/blocks/Questions/QuestionBlockItem/QuestionBlockItem.css +50 -0
- package/build/esm/blocks/Questions/QuestionBlockItem/QuestionBlockItem.d.ts +3 -0
- package/build/esm/blocks/Questions/QuestionBlockItem/QuestionBlockItem.js +23 -0
- package/build/esm/blocks/Questions/Questions.css +0 -48
- package/build/esm/blocks/Questions/Questions.js +6 -26
- package/build/esm/blocks/Questions/models.d.ts +10 -0
- package/build/esm/blocks/Questions/models.js +10 -0
- package/build/esm/components/BackLink/BackLink.d.ts +2 -1
- package/build/esm/components/BackLink/BackLink.js +2 -2
- package/build/esm/components/FileLink/FileLink.js +2 -2
- package/build/esm/components/FullscreenImage/FullscreenImage.js +1 -1
- package/build/esm/components/FullscreenImage/i18n/en.json +2 -1
- package/build/esm/components/FullscreenImage/i18n/ru.json +2 -1
- package/build/esm/components/Image/i18n/en.json +1 -1
- package/build/esm/components/Image/i18n/ru.json +1 -1
- package/build/esm/components/Link/Link.d.ts +2 -2
- package/build/esm/components/Link/Link.js +7 -7
- package/build/esm/components/Media/Media.js +1 -2
- package/build/esm/components/Media/Video/Video.js +3 -3
- package/build/esm/components/ReactPlayer/ReactPlayer.js +4 -3
- package/build/esm/components/ReactPlayer/i18n/en.json +3 -0
- package/build/esm/components/ReactPlayer/i18n/index.d.ts +2 -0
- package/build/esm/components/ReactPlayer/i18n/index.js +5 -0
- package/build/esm/components/ReactPlayer/i18n/ru.json +3 -0
- package/build/esm/components/constants.d.ts +0 -4
- package/build/esm/components/constants.js +0 -4
- package/build/esm/grid/Col/Col.d.ts +2 -1
- package/build/esm/grid/Col/Col.js +2 -2
- package/build/esm/models/constructor-items/blocks.d.ts +4 -0
- package/build/esm/models/constructor-items/common.d.ts +7 -3
- package/build/esm/sub-blocks/Content/ContentList/ContentList.js +11 -1
- package/build/esm/sub-blocks/LayoutItem/utils.d.ts +1 -0
- package/build/esm/utils/blocks.d.ts +1 -1
- package/build/esm/utils/blocks.js +2 -2
- package/package.json +3 -3
- package/server/components/constants.d.ts +0 -4
- package/server/components/constants.js +1 -5
- package/server/models/constructor-items/blocks.d.ts +4 -0
- package/server/models/constructor-items/common.d.ts +7 -3
- package/server/utils/blocks.d.ts +1 -1
- package/server/utils/blocks.js +2 -2
- package/widget/index.js +1 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CSSProperties, ReactNode } from 'react';
|
|
2
2
|
import { ButtonView, ButtonProps as UikitButtonProps } from '@gravity-ui/uikit';
|
|
3
|
-
import { ThemeSupporting } from '../../utils
|
|
3
|
+
import { ThemeSupporting } from '../../utils';
|
|
4
4
|
import { AnalyticsEventsBase, ClassNameProps, PixelEventType, QAProps } from '../common';
|
|
5
5
|
export declare enum AuthorType {
|
|
6
6
|
Column = "column",
|
|
@@ -61,6 +61,9 @@ export interface Stylable {
|
|
|
61
61
|
export interface Animatable {
|
|
62
62
|
animated?: boolean;
|
|
63
63
|
}
|
|
64
|
+
export interface Tabbable {
|
|
65
|
+
tabIndex?: number;
|
|
66
|
+
}
|
|
64
67
|
export interface Background {
|
|
65
68
|
image?: string;
|
|
66
69
|
color?: string;
|
|
@@ -106,7 +109,7 @@ export interface MediaVideoProps extends AnalyticsEventsBase {
|
|
|
106
109
|
controls?: MediaVideoControlsType;
|
|
107
110
|
metrika?: MetrikaVideo;
|
|
108
111
|
}
|
|
109
|
-
export interface LinkProps extends AnalyticsEventsBase, Stylable {
|
|
112
|
+
export interface LinkProps extends AnalyticsEventsBase, Stylable, Tabbable {
|
|
110
113
|
url: string;
|
|
111
114
|
text?: string;
|
|
112
115
|
textSize?: TextSize;
|
|
@@ -117,7 +120,7 @@ export interface LinkProps extends AnalyticsEventsBase, Stylable {
|
|
|
117
120
|
metrikaGoals?: MetrikaGoal;
|
|
118
121
|
pixelEvents?: ButtonPixel;
|
|
119
122
|
}
|
|
120
|
-
export interface FileLinkProps extends ClassNameProps {
|
|
123
|
+
export interface FileLinkProps extends ClassNameProps, Tabbable {
|
|
121
124
|
href: string;
|
|
122
125
|
text: ReactNode;
|
|
123
126
|
type?: FileLinkType;
|
|
@@ -157,6 +160,7 @@ export interface MediaVideoProps {
|
|
|
157
160
|
playButton?: PlayButtonProps;
|
|
158
161
|
controls?: MediaVideoControlsType;
|
|
159
162
|
metrika?: MetrikaVideo;
|
|
163
|
+
ariaLabel?: string;
|
|
160
164
|
}
|
|
161
165
|
export type ThemedMediaVideoProps = ThemeSupporting<MediaVideoProps>;
|
|
162
166
|
export interface MediaComponentVideoProps extends AnalyticsEventsBase {
|
|
@@ -9,6 +9,15 @@ const utils_1 = require("../../../components/Media/Image/utils");
|
|
|
9
9
|
const theme_1 = require("../../../context/theme");
|
|
10
10
|
const utils_2 = require("../../../utils");
|
|
11
11
|
const b = (0, utils_2.block)('content-list');
|
|
12
|
+
function getHeadingLevel(size) {
|
|
13
|
+
switch (size) {
|
|
14
|
+
case 's':
|
|
15
|
+
return 'h4';
|
|
16
|
+
case 'l':
|
|
17
|
+
default:
|
|
18
|
+
return 'h3';
|
|
19
|
+
}
|
|
20
|
+
}
|
|
12
21
|
const ContentList = ({ list, size }) => {
|
|
13
22
|
const theme = (0, theme_1.useTheme)();
|
|
14
23
|
return (react_1.default.createElement("div", { className: b({ size }) }, list === null || list === void 0 ? void 0 : list.map((item) => {
|
|
@@ -18,7 +27,8 @@ const ContentList = ({ list, size }) => {
|
|
|
18
27
|
return (react_1.default.createElement("div", { className: b('item'), key: (0, uuid_1.v4)() },
|
|
19
28
|
react_1.default.createElement(Image_1.default, Object.assign({}, iconData, { className: b('icon') })),
|
|
20
29
|
react_1.default.createElement("div", null,
|
|
21
|
-
title &&
|
|
30
|
+
title &&
|
|
31
|
+
react_1.default.createElement(getHeadingLevel(size), { className: b('title') }, title),
|
|
22
32
|
text && (react_1.default.createElement(components_1.YFMWrapper, { className: b('text'), content: text, modifiers: { constructor: true } })))));
|
|
23
33
|
})));
|
|
24
34
|
};
|
|
@@ -23,6 +23,7 @@ export declare const getLayoutItemLinks: (links: LayoutItemProps['content']['lin
|
|
|
23
23
|
target?: string | undefined;
|
|
24
24
|
}[] | undefined;
|
|
25
25
|
className?: string | undefined;
|
|
26
|
+
tabIndex?: number | undefined;
|
|
26
27
|
}[] | undefined;
|
|
27
28
|
export declare const hasFullscreen: ({ dataLens, image }: MediaProps) => boolean;
|
|
28
29
|
export declare const showFullscreenIcon: ({ youtube }: MediaProps) => boolean;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { ConstructorBlock, CustomConfig, PCShareSocialNetwork, TextSize } from '../models';
|
|
2
|
-
export declare function getHeaderTag(size: TextSize): "h1" | "h2" | "
|
|
2
|
+
export declare function getHeaderTag(size: TextSize): "h1" | "h2" | "h3" | "h4";
|
|
3
3
|
export declare function hasBlockTag(content: string): boolean;
|
|
4
4
|
export declare function getBlockKey(block: ConstructorBlock, index: number): string;
|
|
5
5
|
export declare const getCustomBlockTypes: ({ blocks, headers }?: CustomConfig) => string[];
|
|
@@ -15,6 +15,7 @@ const DEFAULT_SIZES = {
|
|
|
15
15
|
};
|
|
16
16
|
export const ExtendedFeaturesBlock = ({ title, description, items, colSizes = DEFAULT_SIZES, animated, }) => {
|
|
17
17
|
const theme = useTheme();
|
|
18
|
+
const itemTitleHeadingTag = title ? 'h3' : 'h2';
|
|
18
19
|
return (React.createElement(AnimateBlock, { className: b(), animate: animated },
|
|
19
20
|
React.createElement(Title, { title: title, subtitle: description, className: b('header') }),
|
|
20
21
|
React.createElement("div", { className: b('items') },
|
|
@@ -28,9 +29,12 @@ export const ExtendedFeaturesBlock = ({ title, description, items, colSizes = DE
|
|
|
28
29
|
return (React.createElement(Col, { className: b('item'), key: text || itemTitle, sizes: colSizes },
|
|
29
30
|
iconData && React.createElement(Image, Object.assign({}, iconData, { className: b('icon') })),
|
|
30
31
|
React.createElement("div", { className: b('container') },
|
|
31
|
-
itemTitle &&
|
|
32
|
-
React.createElement(
|
|
33
|
-
|
|
32
|
+
itemTitle &&
|
|
33
|
+
React.createElement(itemTitleHeadingTag, {
|
|
34
|
+
className: b('item-title'),
|
|
35
|
+
}, React.createElement(React.Fragment, null,
|
|
36
|
+
React.createElement(HTML, null, itemTitle),
|
|
37
|
+
label && (React.createElement("span", { className: b('item-label') }, label)))),
|
|
34
38
|
React.createElement(Content, { text: text, links: itemLinks, size: "s", colSizes: { all: 12, md: 12 }, buttons: buttons, additionalInfo: additionalInfo }))));
|
|
35
39
|
})))));
|
|
36
40
|
};
|
|
@@ -66,6 +66,9 @@ export declare const FilterProps: {
|
|
|
66
66
|
type: string;
|
|
67
67
|
enum: string[];
|
|
68
68
|
};
|
|
69
|
+
centered: {
|
|
70
|
+
type: string;
|
|
71
|
+
};
|
|
69
72
|
title: {
|
|
70
73
|
oneOf: ({
|
|
71
74
|
type: string;
|
|
@@ -173,6 +176,9 @@ export declare const FilterBlock: {
|
|
|
173
176
|
type: string;
|
|
174
177
|
enum: string[];
|
|
175
178
|
};
|
|
179
|
+
centered: {
|
|
180
|
+
type: string;
|
|
181
|
+
};
|
|
176
182
|
title: {
|
|
177
183
|
oneOf: ({
|
|
178
184
|
type: string;
|
|
@@ -27,7 +27,7 @@ export const FilterItemProps = {
|
|
|
27
27
|
};
|
|
28
28
|
export const FilterProps = {
|
|
29
29
|
additionalProperties: false,
|
|
30
|
-
required: ['
|
|
30
|
+
required: ['tags', 'items'],
|
|
31
31
|
properties: Object.assign(Object.assign(Object.assign(Object.assign({}, BlockBaseProps), AnimatableProps), BlockHeaderProps), { allTag: {
|
|
32
32
|
oneOf: [
|
|
33
33
|
{
|
|
@@ -42,7 +42,7 @@ export const FilterProps = {
|
|
|
42
42
|
}, colSizes: containerSizesObject, tags: filteredArray(FilterTagProps), items: filteredArray(FilterItemProps), tagButtonSize: {
|
|
43
43
|
type: 'string',
|
|
44
44
|
enum: ['s', 'm', 'l', 'xl'],
|
|
45
|
-
} }),
|
|
45
|
+
}, centered: { type: 'boolean' } }),
|
|
46
46
|
};
|
|
47
47
|
export const FilterBlock = {
|
|
48
48
|
'filter-block': FilterProps,
|
|
@@ -28,7 +28,7 @@ const PromoFeaturesBlock = (props) => {
|
|
|
28
28
|
[themeMod]: Boolean(themeMod),
|
|
29
29
|
}) },
|
|
30
30
|
React.createElement("div", { className: b('card-info') },
|
|
31
|
-
React.createElement("
|
|
31
|
+
React.createElement("h3", { className: b('card-title') }, cardTitle),
|
|
32
32
|
React.createElement("div", { className: b('card-text') },
|
|
33
33
|
React.createElement(YFMWrapper, { content: text, modifiers: { constructor: true } }))),
|
|
34
34
|
media && React.createElement(Media, Object.assign({ className: b('card-media') }, media))));
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
.pc-QuestionsBlockItem__title {
|
|
2
|
+
margin: 0;
|
|
3
|
+
}
|
|
4
|
+
|
|
5
|
+
/* use this for style redefinitions to awoid problems with
|
|
6
|
+
unpredictable css rules order in build */
|
|
7
|
+
.pc-QuestionsBlockItem {
|
|
8
|
+
padding-bottom: 32px;
|
|
9
|
+
border-bottom: 1px solid var(--g-color-line-generic);
|
|
10
|
+
}
|
|
11
|
+
.pc-QuestionsBlockItem + .pc-QuestionsBlockItem {
|
|
12
|
+
padding-top: 32px;
|
|
13
|
+
}
|
|
14
|
+
.pc-QuestionsBlockItem__title {
|
|
15
|
+
font-size: var(--g-text-header-1-font-size);
|
|
16
|
+
line-height: var(--g-text-header-1-line-height);
|
|
17
|
+
color: var(--pc-text-header-color);
|
|
18
|
+
font-weight: var(--g-text-accent-font-weight);
|
|
19
|
+
position: relative;
|
|
20
|
+
padding-right: 24px;
|
|
21
|
+
cursor: pointer;
|
|
22
|
+
}
|
|
23
|
+
.pc-QuestionsBlockItem__title a {
|
|
24
|
+
outline: none;
|
|
25
|
+
color: var(--g-color-text-link);
|
|
26
|
+
text-decoration: none;
|
|
27
|
+
cursor: pointer;
|
|
28
|
+
}
|
|
29
|
+
.utilityfocus .pc-QuestionsBlockItem__title a:focus {
|
|
30
|
+
outline: 2px solid #ffdb4d;
|
|
31
|
+
}
|
|
32
|
+
.pc-QuestionsBlockItem__title a:hover, .pc-QuestionsBlockItem__title a:active {
|
|
33
|
+
--pc-text-header-color: var(--g-color-text-link-hover);
|
|
34
|
+
color: var(--g-color-text-link-hover);
|
|
35
|
+
}
|
|
36
|
+
.pc-QuestionsBlockItem__arrow {
|
|
37
|
+
position: absolute;
|
|
38
|
+
right: 0;
|
|
39
|
+
top: 0;
|
|
40
|
+
color: var(--g-color-text-primary);
|
|
41
|
+
}
|
|
42
|
+
.pc-QuestionsBlockItem__link {
|
|
43
|
+
font-size: var(--g-text-body-2-font-size);
|
|
44
|
+
line-height: var(--g-text-body-2-line-height);
|
|
45
|
+
}
|
|
46
|
+
.pc-QuestionsBlockItem__text {
|
|
47
|
+
font-size: var(--g-text-body-2-font-size);
|
|
48
|
+
line-height: var(--g-text-body-2-line-height);
|
|
49
|
+
margin-top: 12px;
|
|
50
|
+
}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { useActionHandlers } from '@gravity-ui/uikit';
|
|
3
|
+
import { Foldable, HTML, ToggleArrow, YFMWrapper } from '../../../components';
|
|
4
|
+
import Link from '../../../components/Link/Link';
|
|
5
|
+
import { block } from '../../../utils';
|
|
6
|
+
import { FaqMicrodataValues } from '../models';
|
|
7
|
+
import './QuestionBlockItem.css';
|
|
8
|
+
const b = block('QuestionsBlockItem');
|
|
9
|
+
export const QuestionBlockItem = ({ title: itemTitle, text: itemText, link, listStyle = 'dash', isOpened, onClick, }) => {
|
|
10
|
+
const { onKeyDown } = useActionHandlers(onClick);
|
|
11
|
+
return (React.createElement("div", { className: b(), itemScope: true, itemProp: FaqMicrodataValues.QuestionProp, itemType: FaqMicrodataValues.QuestionType, role: 'listitem' },
|
|
12
|
+
React.createElement("h3", { className: b('title'), onClick: onClick, "aria-expanded": isOpened, role: 'button', tabIndex: 0, onKeyDown: onKeyDown },
|
|
13
|
+
React.createElement(HTML, { itemProp: FaqMicrodataValues.QuestionNameProp }, itemTitle),
|
|
14
|
+
React.createElement(ToggleArrow, { open: isOpened, size: 16, type: 'vertical', iconType: "navigation", className: b('arrow') })),
|
|
15
|
+
React.createElement(Foldable, { isOpened: isOpened },
|
|
16
|
+
React.createElement("div", { className: b('text'), itemScope: true, itemProp: FaqMicrodataValues.AnswerProp, itemType: FaqMicrodataValues.AnswerType, "aria-hidden": !isOpened },
|
|
17
|
+
React.createElement(YFMWrapper, { content: itemText, modifiers: {
|
|
18
|
+
constructor: true,
|
|
19
|
+
constructorListStyle: true,
|
|
20
|
+
constructorListStyleDash: listStyle === 'dash',
|
|
21
|
+
}, itemProp: FaqMicrodataValues.QuestionTextProp }),
|
|
22
|
+
link && React.createElement(Link, Object.assign({}, link, { tabIndex: isOpened ? 0 : -1, className: b('link') }))))));
|
|
23
|
+
};
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
.pc-QuestionsBlock__item-title {
|
|
2
|
-
margin: 0;
|
|
3
|
-
}
|
|
4
|
-
|
|
5
1
|
/* use this for style redefinitions to awoid problems with
|
|
6
2
|
unpredictable css rules order in build */
|
|
7
3
|
.pc-QuestionsBlock__title {
|
|
@@ -10,50 +6,6 @@ unpredictable css rules order in build */
|
|
|
10
6
|
margin-bottom: 32px;
|
|
11
7
|
margin-right: 64px;
|
|
12
8
|
}
|
|
13
|
-
.pc-QuestionsBlock__item {
|
|
14
|
-
padding-bottom: 32px;
|
|
15
|
-
border-bottom: 1px solid var(--g-color-line-generic);
|
|
16
|
-
}
|
|
17
|
-
.pc-QuestionsBlock__item + .pc-QuestionsBlock__item {
|
|
18
|
-
padding-top: 32px;
|
|
19
|
-
}
|
|
20
|
-
.pc-QuestionsBlock__item-title {
|
|
21
|
-
font-size: var(--g-text-header-1-font-size);
|
|
22
|
-
line-height: var(--g-text-header-1-line-height);
|
|
23
|
-
color: var(--pc-text-header-color);
|
|
24
|
-
font-weight: var(--g-text-accent-font-weight);
|
|
25
|
-
position: relative;
|
|
26
|
-
padding-right: 24px;
|
|
27
|
-
cursor: pointer;
|
|
28
|
-
}
|
|
29
|
-
.pc-QuestionsBlock__item-title a {
|
|
30
|
-
outline: none;
|
|
31
|
-
color: var(--g-color-text-link);
|
|
32
|
-
text-decoration: none;
|
|
33
|
-
cursor: pointer;
|
|
34
|
-
}
|
|
35
|
-
.utilityfocus .pc-QuestionsBlock__item-title a:focus {
|
|
36
|
-
outline: 2px solid #ffdb4d;
|
|
37
|
-
}
|
|
38
|
-
.pc-QuestionsBlock__item-title a:hover, .pc-QuestionsBlock__item-title a:active {
|
|
39
|
-
--pc-text-header-color: var(--g-color-text-link-hover);
|
|
40
|
-
color: var(--g-color-text-link-hover);
|
|
41
|
-
}
|
|
42
|
-
.pc-QuestionsBlock__text {
|
|
43
|
-
font-size: var(--g-text-body-2-font-size);
|
|
44
|
-
line-height: var(--g-text-body-2-line-height);
|
|
45
|
-
margin-top: 12px;
|
|
46
|
-
}
|
|
47
|
-
.pc-QuestionsBlock__arrow {
|
|
48
|
-
position: absolute;
|
|
49
|
-
right: 0;
|
|
50
|
-
top: 0;
|
|
51
|
-
color: var(--g-color-text-primary);
|
|
52
|
-
}
|
|
53
|
-
.pc-QuestionsBlock__link {
|
|
54
|
-
font-size: var(--g-text-body-2-font-size);
|
|
55
|
-
line-height: var(--g-text-body-2-line-height);
|
|
56
|
-
}
|
|
57
9
|
@media (max-width: 769px) {
|
|
58
10
|
.pc-QuestionsBlock__title {
|
|
59
11
|
margin-right: 0;
|
|
@@ -1,28 +1,18 @@
|
|
|
1
1
|
import React, { useState } from 'react';
|
|
2
|
-
import { Foldable, HTML, ToggleArrow, YFMWrapper } from '../../components';
|
|
3
|
-
import Link from '../../components/Link/Link';
|
|
4
2
|
import { Col, Row } from '../../grid';
|
|
5
3
|
import { Content } from '../../sub-blocks';
|
|
6
4
|
import { block } from '../../utils';
|
|
5
|
+
import { QuestionBlockItem } from './QuestionBlockItem/QuestionBlockItem';
|
|
6
|
+
import { FaqMicrodataValues } from './models';
|
|
7
7
|
import './Questions.css';
|
|
8
8
|
const b = block('QuestionsBlock');
|
|
9
|
-
const FaqMicrodataValues = {
|
|
10
|
-
PageType: 'https://schema.org/FAQPage',
|
|
11
|
-
QuestionType: 'https://schema.org/Question',
|
|
12
|
-
QuestionProp: 'mainEntity',
|
|
13
|
-
QuestionNameProp: 'name',
|
|
14
|
-
QuestionTextProp: 'text',
|
|
15
|
-
AnswerType: 'https://schema.org/Answer',
|
|
16
|
-
AnswerProp: 'acceptedAnswer',
|
|
17
|
-
AnswerTextProp: 'text',
|
|
18
|
-
};
|
|
19
9
|
const QuestionsBlock = (props) => {
|
|
20
10
|
const { title, text, additionalInfo, links, buttons, items } = props;
|
|
21
11
|
const [opened, setOpened] = useState([0]);
|
|
22
12
|
const toggleItem = (index) => {
|
|
23
13
|
let newState;
|
|
24
14
|
if (opened.includes(index)) {
|
|
25
|
-
newState = opened.filter((
|
|
15
|
+
newState = opened.filter((itemIndex) => itemIndex !== index);
|
|
26
16
|
}
|
|
27
17
|
else {
|
|
28
18
|
newState = [...opened, index];
|
|
@@ -34,20 +24,10 @@ const QuestionsBlock = (props) => {
|
|
|
34
24
|
React.createElement(Col, { sizes: { all: 12, md: 4 } },
|
|
35
25
|
React.createElement("div", { className: b('title') },
|
|
36
26
|
React.createElement(Content, { title: title, text: text, additionalInfo: additionalInfo, links: links, buttons: buttons, colSizes: { all: 12, md: 12 } }))),
|
|
37
|
-
React.createElement(Col, { sizes: { all: 12, md: 8 } }, items.map(({ title: itemTitle, text: itemText, link, listStyle = 'dash' }, index) => {
|
|
27
|
+
React.createElement(Col, { sizes: { all: 12, md: 8 }, role: 'list' }, items.map(({ title: itemTitle, text: itemText, link, listStyle = 'dash' }, index) => {
|
|
38
28
|
const isOpened = opened.includes(index);
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
React.createElement(HTML, { itemProp: FaqMicrodataValues.QuestionNameProp }, itemTitle),
|
|
42
|
-
React.createElement(ToggleArrow, { open: isOpened, size: 16, type: 'vertical', iconType: "navigation", className: b('arrow') })),
|
|
43
|
-
React.createElement(Foldable, { isOpened: isOpened },
|
|
44
|
-
React.createElement("div", { className: b('text'), itemScope: true, itemProp: FaqMicrodataValues.AnswerProp, itemType: FaqMicrodataValues.AnswerType },
|
|
45
|
-
React.createElement(YFMWrapper, { content: itemText, modifiers: {
|
|
46
|
-
constructor: true,
|
|
47
|
-
constructorListStyle: true,
|
|
48
|
-
constructorListStyleDash: listStyle === 'dash',
|
|
49
|
-
}, itemProp: FaqMicrodataValues.QuestionTextProp }),
|
|
50
|
-
link && React.createElement(Link, Object.assign({}, link, { className: b('link') }))))));
|
|
29
|
+
const onClick = () => toggleItem(index);
|
|
30
|
+
return (React.createElement(QuestionBlockItem, { key: itemTitle, title: itemTitle, text: itemText, link: link, listStyle: listStyle, isOpened: isOpened, onClick: onClick }));
|
|
51
31
|
})))));
|
|
52
32
|
};
|
|
53
33
|
export default QuestionsBlock;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export declare const FaqMicrodataValues: {
|
|
2
|
+
readonly PageType: "https://schema.org/FAQPage";
|
|
3
|
+
readonly QuestionType: "https://schema.org/Question";
|
|
4
|
+
readonly QuestionProp: "mainEntity";
|
|
5
|
+
readonly QuestionNameProp: "name";
|
|
6
|
+
readonly QuestionTextProp: "text";
|
|
7
|
+
readonly AnswerType: "https://schema.org/Answer";
|
|
8
|
+
readonly AnswerProp: "acceptedAnswer";
|
|
9
|
+
readonly AnswerTextProp: "text";
|
|
10
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export const FaqMicrodataValues = {
|
|
2
|
+
PageType: 'https://schema.org/FAQPage',
|
|
3
|
+
QuestionType: 'https://schema.org/Question',
|
|
4
|
+
QuestionProp: 'mainEntity',
|
|
5
|
+
QuestionNameProp: 'name',
|
|
6
|
+
QuestionTextProp: 'text',
|
|
7
|
+
AnswerType: 'https://schema.org/Answer',
|
|
8
|
+
AnswerProp: 'acceptedAnswer',
|
|
9
|
+
AnswerTextProp: 'text',
|
|
10
|
+
};
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { ReactNode } from 'react';
|
|
2
2
|
import { ButtonSize } from '@gravity-ui/uikit';
|
|
3
|
+
import { Tabbable } from '../../models';
|
|
3
4
|
export type Theme = 'default' | 'special';
|
|
4
|
-
export interface BackLinkProps {
|
|
5
|
+
export interface BackLinkProps extends Tabbable {
|
|
5
6
|
url: string;
|
|
6
7
|
title: ReactNode;
|
|
7
8
|
theme?: Theme;
|
|
@@ -6,7 +6,7 @@ import { ArrowSidebar } from '../../icons';
|
|
|
6
6
|
import { DefaultEventNames } from '../../models';
|
|
7
7
|
export default function BackLink(props) {
|
|
8
8
|
const { history } = useContext(LocationContext);
|
|
9
|
-
const { url, title, theme = 'default', size = 'l', className, shouldHandleBackAction = false, onClick, } = props;
|
|
9
|
+
const { url, title, theme = 'default', size = 'l', className, shouldHandleBackAction = false, onClick, tabIndex, } = props;
|
|
10
10
|
const handleAnalytics = useAnalytics(DefaultEventNames.ShareButton, url);
|
|
11
11
|
const backActionHandler = useCallback(async () => {
|
|
12
12
|
handleAnalytics();
|
|
@@ -23,7 +23,7 @@ export default function BackLink(props) {
|
|
|
23
23
|
history.push({ pathname: url });
|
|
24
24
|
}
|
|
25
25
|
}, [handleAnalytics, history, onClick, url]);
|
|
26
|
-
return (React.createElement(Button, { className: className, view: theme === 'special' ? 'flat-contrast' : 'flat-secondary', size: size, href: shouldHandleBackAction ? undefined : url, onClick: shouldHandleBackAction ? backActionHandler : undefined },
|
|
26
|
+
return (React.createElement(Button, { className: className, view: theme === 'special' ? 'flat-contrast' : 'flat-secondary', size: size, href: shouldHandleBackAction ? undefined : url, onClick: shouldHandleBackAction ? backActionHandler : undefined, tabIndex: tabIndex },
|
|
27
27
|
React.createElement(Icon, { data: ArrowSidebar, size: 24 }),
|
|
28
28
|
React.createElement("span", null, title)));
|
|
29
29
|
}
|
|
@@ -37,13 +37,13 @@ const LabelSizeMap = {
|
|
|
37
37
|
};
|
|
38
38
|
const FileLink = (props) => {
|
|
39
39
|
const { hostname } = useContext(LocationContext);
|
|
40
|
-
const { href, text, type = 'vertical', textSize = 'm', className, theme = 'default', onClick, } = props;
|
|
40
|
+
const { href, text, type = 'vertical', textSize = 'm', className, theme = 'default', onClick, tabIndex, } = props;
|
|
41
41
|
const fileExt = getFileExt(href);
|
|
42
42
|
const labelTheme = (FileExtensionThemes[fileExt] || 'unknown');
|
|
43
43
|
const labelSize = LabelSizeMap[textSize];
|
|
44
44
|
return (React.createElement("div", { className: b({ ext: fileExt, type, size: textSize, theme }, className) },
|
|
45
45
|
React.createElement(Label, { className: b('file-label'), size: labelSize, theme: labelTheme }, fileExt),
|
|
46
46
|
React.createElement("div", { className: b('link') },
|
|
47
|
-
React.createElement("a", Object.assign({ href: href }, getLinkProps(href, hostname)
|
|
47
|
+
React.createElement("a", Object.assign({ href: href, onClick: onClick, tabIndex: tabIndex }, getLinkProps(href, hostname)), text))));
|
|
48
48
|
};
|
|
49
49
|
export default FileLink;
|
|
@@ -23,7 +23,7 @@ const FullscreenImage = (props) => {
|
|
|
23
23
|
React.createElement(Icon, { data: Fullscreen, width: FULL_SCREEN_ICON_SIZE, height: FULL_SCREEN_ICON_SIZE, className: b('icon') }))),
|
|
24
24
|
isOpened && (React.createElement(Modal, { open: isOpened, onClose: closeModal, className: b('modal') },
|
|
25
25
|
React.createElement("div", { className: b('modal-content') },
|
|
26
|
-
React.createElement("div", { className: b('icon-wrapper', { visible: true }), onClick: closeModal },
|
|
26
|
+
React.createElement("div", { className: b('icon-wrapper', { visible: true }), onClick: closeModal, "aria-label": i18n('close') },
|
|
27
27
|
React.createElement(Icon, { data: PreviewClose, width: CLOSE_ICON_SIZE, height: CLOSE_ICON_SIZE, className: b('icon', { hover: true }) })),
|
|
28
28
|
React.createElement(Image, Object.assign({}, props, { className: b('modal-image', modalImageClass) })))))));
|
|
29
29
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { ClassNameProps, LinkProps, WithChildren } from '../../models';
|
|
1
|
+
import { ClassNameProps, LinkProps, Tabbable, WithChildren } from '../../models';
|
|
2
2
|
import './Link.css';
|
|
3
|
-
export type LinkFullProps = LinkProps & ClassNameProps;
|
|
3
|
+
export type LinkFullProps = LinkProps & ClassNameProps & Tabbable;
|
|
4
4
|
declare const LinkBlock: (props: WithChildren<LinkFullProps>) => JSX.Element;
|
|
5
5
|
export default LinkBlock;
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import React, { Fragment, useContext } from 'react';
|
|
2
2
|
import { Icon } from '@gravity-ui/uikit';
|
|
3
|
-
import { LocaleContext } from '../../context/localeContext
|
|
4
|
-
import { LocationContext } from '../../context/locationContext
|
|
3
|
+
import { LocaleContext } from '../../context/localeContext';
|
|
4
|
+
import { LocationContext } from '../../context/locationContext';
|
|
5
5
|
import { useAnalytics } from '../../hooks';
|
|
6
6
|
import { useMetrika } from '../../hooks/useMetrika';
|
|
7
7
|
import { Chevron } from '../../icons';
|
|
8
|
-
import { DefaultEventNames } from '../../models';
|
|
8
|
+
import { DefaultEventNames, } from '../../models';
|
|
9
9
|
import { block, getLinkProps, setUrlTld } from '../../utils';
|
|
10
10
|
import BackLink from '../BackLink/BackLink';
|
|
11
11
|
import FileLink from '../FileLink/FileLink';
|
|
@@ -25,7 +25,7 @@ function getArrowSize(size) {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
const LinkBlock = (props) => {
|
|
28
|
-
const { text, url, arrow, metrikaGoals, pixelEvents, analyticsEvents, theme = 'file-link', colorTheme = 'light', textSize = 'm', className, target, children, } = props;
|
|
28
|
+
const { text, url, arrow, metrikaGoals, pixelEvents, analyticsEvents, theme = 'file-link', colorTheme = 'light', textSize = 'm', className, target, children, tabIndex, } = props;
|
|
29
29
|
const handleMetrika = useMetrika();
|
|
30
30
|
const handleAnalytics = useAnalytics(DefaultEventNames.Link, url);
|
|
31
31
|
const { hostname } = useContext(LocationContext);
|
|
@@ -39,14 +39,14 @@ const LinkBlock = (props) => {
|
|
|
39
39
|
const getLinkByType = () => {
|
|
40
40
|
switch (theme) {
|
|
41
41
|
case 'back':
|
|
42
|
-
return React.createElement(BackLink, { title: children || text, url: href, onClick: onClick });
|
|
42
|
+
return (React.createElement(BackLink, { title: children || text, url: href, onClick: onClick, tabIndex: tabIndex }));
|
|
43
43
|
case 'file-link':
|
|
44
44
|
case 'underline':
|
|
45
|
-
return (React.createElement(FileLink, { text: children || text, href: href, type: "horizontal", textSize: textSize, onClick: onClick }));
|
|
45
|
+
return (React.createElement(FileLink, { text: children || text, href: href, type: "horizontal", textSize: textSize, onClick: onClick, tabIndex: tabIndex }));
|
|
46
46
|
case 'normal': {
|
|
47
47
|
const linkProps = getLinkProps(url, hostname, target);
|
|
48
48
|
const content = children || text;
|
|
49
|
-
return (React.createElement("a", Object.assign({ className: b('link', { theme: colorTheme, 'has-arrow': arrow }), href: href, onClick: onClick }, linkProps), arrow ? (React.createElement(Fragment, null,
|
|
49
|
+
return (React.createElement("a", Object.assign({ className: b('link', { theme: colorTheme, 'has-arrow': arrow }), href: href, onClick: onClick, tabIndex: tabIndex }, linkProps), arrow ? (React.createElement(Fragment, null,
|
|
50
50
|
React.createElement("span", { className: b('content') }, content),
|
|
51
51
|
WORD_JOINER_SYM,
|
|
52
52
|
React.createElement(Icon, { className: b('arrow'), data: Chevron, size: getArrowSize(textSize) }))) : (content)));
|
|
@@ -8,8 +8,7 @@ import Video from './Video/Video';
|
|
|
8
8
|
import './Media.css';
|
|
9
9
|
const b = block('Media');
|
|
10
10
|
export const Media = (props) => {
|
|
11
|
-
const { image, video, youtube, dataLens, color, height, previewImg, parallax = false, metrika, fullscreen, analyticsEvents, } = props;
|
|
12
|
-
const { className, imageClassName, videoClassName, youtubeClassName, playVideo = true, isBackground, playButton, customBarControlsClassName, } = props;
|
|
11
|
+
const { image, video, youtube, dataLens, color, height, previewImg, parallax = false, metrika, fullscreen, analyticsEvents, className, imageClassName, videoClassName, youtubeClassName, playVideo = true, isBackground, playButton, customBarControlsClassName, } = props;
|
|
13
12
|
const [hasVideoFallback, setHasVideoFallback] = useState(false);
|
|
14
13
|
const content = useMemo(() => {
|
|
15
14
|
let result = [];
|
|
@@ -28,8 +28,8 @@ const Video = (props) => {
|
|
|
28
28
|
}
|
|
29
29
|
}, [playVideo, video, setHasVideoFallback]);
|
|
30
30
|
const reactPlayerBlock = useMemo(() => {
|
|
31
|
-
const { src, loop, controls, muted, autoplay = true, elapsedTime, playButton } = video;
|
|
32
|
-
return (React.createElement(ReactPlayerBlock, { className: b('react-player', videoClassName), src: src, previewImgUrl: previewImg, loop: Boolean(loop), controls: controls, muted: muted, autoplay: autoplay && playVideo, elapsedTime: elapsedTime, playButton: playButton || commonPlayButton, customBarControlsClassName: customBarControlsClassName, metrika: metrika, analyticsEvents: analyticsEvents, height: height }));
|
|
31
|
+
const { src, loop, controls, muted, autoplay = true, elapsedTime, playButton, ariaLabel, } = video;
|
|
32
|
+
return (React.createElement(ReactPlayerBlock, { className: b('react-player', videoClassName), src: src, previewImgUrl: previewImg, loop: Boolean(loop), controls: controls, muted: muted, autoplay: autoplay && playVideo, elapsedTime: elapsedTime, playButton: playButton || commonPlayButton, customBarControlsClassName: customBarControlsClassName, metrika: metrika, analyticsEvents: analyticsEvents, height: height, ariaLabel: ariaLabel }));
|
|
33
33
|
}, [
|
|
34
34
|
video,
|
|
35
35
|
height,
|
|
@@ -46,7 +46,7 @@ const Video = (props) => {
|
|
|
46
46
|
React.createElement("video", { disablePictureInPicture: true, playsInline: true,
|
|
47
47
|
// @ts-ignore
|
|
48
48
|
// eslint-disable-next-line react/no-unknown-property
|
|
49
|
-
pip: "false", className: b('item'), ref: ref, preload: "metadata", muted: true }, getVideoTypesWithPriority(video.src).map(({ src, type }, index) => (React.createElement("source", { key: index, src: src, type: type })))))) : null;
|
|
49
|
+
pip: "false", className: b('item'), ref: ref, preload: "metadata", muted: true, "aria-label": video.ariaLabel }, getVideoTypesWithPriority(video.src).map(({ src, type }, index) => (React.createElement("source", { key: index, src: src, type: type })))))) : null;
|
|
50
50
|
}, [video, videoClassName, hasVideoFallback, height]);
|
|
51
51
|
switch (video.type) {
|
|
52
52
|
case MediaVideoType.Player:
|
|
@@ -10,6 +10,7 @@ import { PlayVideo } from '../../icons';
|
|
|
10
10
|
import { DefaultEventNames, MediaVideoControlsType, PlayButtonThemes, PlayButtonType, PredefinedEventTypes, } from '../../models';
|
|
11
11
|
import { block } from '../../utils';
|
|
12
12
|
import CustomBarControls from './CustomBarControls';
|
|
13
|
+
import i18n from './i18n';
|
|
13
14
|
import { checkYoutubeVideos } from './utils';
|
|
14
15
|
import './ReactPlayer.css';
|
|
15
16
|
const b = block('ReactPlayer');
|
|
@@ -18,7 +19,7 @@ const FPS = 60;
|
|
|
18
19
|
export const ReactPlayerBlock = React.forwardRef((props, originRef) => {
|
|
19
20
|
const isMobile = useContext(MobileContext);
|
|
20
21
|
const { metrika } = useContext(MetrikaContext);
|
|
21
|
-
const { src, previewImgUrl, loop = false, controls = MediaVideoControlsType.Default, muted: initiallyMuted = false, elapsedTime, playButton, className, customBarControlsClassName, showPreview, onClickPreview, metrika: videoMetrika, analyticsEvents, height, } = props;
|
|
22
|
+
const { src, previewImgUrl, loop = false, controls = MediaVideoControlsType.Default, muted: initiallyMuted = false, elapsedTime, playButton, className, customBarControlsClassName, showPreview, onClickPreview, metrika: videoMetrika, analyticsEvents, height, ariaLabel, } = props;
|
|
22
23
|
const { type = PlayButtonType.Default, theme = PlayButtonThemes.Blue, text, className: buttonClassName, } = playButton || {};
|
|
23
24
|
const autoPlay = Boolean(!isMobile && !previewImgUrl && props.autoplay);
|
|
24
25
|
const mute = initiallyMuted || autoPlay;
|
|
@@ -102,7 +103,7 @@ export const ReactPlayerBlock = React.forwardRef((props, originRef) => {
|
|
|
102
103
|
playButtonContent = React.createElement(Icon, { className: b('icon'), data: PlayVideo, size: 24 });
|
|
103
104
|
break;
|
|
104
105
|
}
|
|
105
|
-
return (React.createElement("button", { className: b('button', { theme, text: Boolean(text) }, buttonClassName) }, playButtonContent));
|
|
106
|
+
return (React.createElement("button", { className: b('button', { theme, text: Boolean(text) }, buttonClassName), "aria-label": i18n('play') }, playButtonContent));
|
|
106
107
|
}, [type, theme, text, buttonClassName]);
|
|
107
108
|
const changeMute = useCallback((isMuted) => {
|
|
108
109
|
if (isMuted && playerRef) {
|
|
@@ -192,7 +193,7 @@ export const ReactPlayerBlock = React.forwardRef((props, originRef) => {
|
|
|
192
193
|
}, elapsedTimePercent: elapsedTimePercent }));
|
|
193
194
|
}, [controls, isPlaying, customBarControlsClassName, changeMute]);
|
|
194
195
|
return (React.createElement("div", { className: b({ wrapper: !currentHeight }, className), ref: ref, onClick: handleClick },
|
|
195
|
-
React.createElement(ReactPlayer, { className: b('player'), url: videoSrc, muted: muted, controls: controls === MediaVideoControlsType.Default, height: currentHeight || '100%', width: width || '100%', light: previewImgUrl, playing: isPlaying, playIcon: playIcon, progressInterval: FPS, onClickPreview: handleClickPreview, onStart: onStart, onReady: setPlayerRef, onPlay: onPlay, onPause: onPause, onProgress: onProgress, onEnded: onEnded }),
|
|
196
|
+
React.createElement(ReactPlayer, { className: b('player'), url: videoSrc, muted: muted, controls: controls === MediaVideoControlsType.Default, height: currentHeight || '100%', width: width || '100%', light: previewImgUrl, playing: isPlaying, playIcon: playIcon, progressInterval: FPS, onClickPreview: handleClickPreview, onStart: onStart, onReady: setPlayerRef, onPlay: onPlay, onPause: onPause, onProgress: onProgress, onEnded: onEnded, "aria-label": ariaLabel }),
|
|
196
197
|
renderCustomBarControls(muted, playedPercent)));
|
|
197
198
|
});
|
|
198
199
|
function getHeight(width) {
|