@gravity-ui/page-constructor 4.37.1 → 4.37.3

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.
Files changed (32) hide show
  1. package/build/cjs/blocks/Tabs/Tabs.css +3 -37
  2. package/build/cjs/blocks/Tabs/Tabs.js +21 -18
  3. package/build/cjs/blocks/Tabs/TabsTextContent/TabsTextContent.css +27 -0
  4. package/build/cjs/blocks/Tabs/TabsTextContent/TabsTextContent.d.ts +10 -0
  5. package/build/cjs/blocks/Tabs/TabsTextContent/TabsTextContent.js +20 -0
  6. package/build/cjs/components/Image/Image.d.ts +2 -1
  7. package/build/cjs/components/Image/Image.js +2 -2
  8. package/build/cjs/components/ImageBase/ImageBase.d.ts +2 -1
  9. package/build/cjs/components/Media/Image/Image.d.ts +1 -0
  10. package/build/cjs/components/Media/Image/Image.js +2 -2
  11. package/build/cjs/components/Media/Media.d.ts +1 -0
  12. package/build/cjs/components/Media/Media.js +4 -3
  13. package/build/cjs/components/VideoBlock/VideoBlock.d.ts +1 -0
  14. package/build/cjs/components/VideoBlock/VideoBlock.js +2 -2
  15. package/build/cjs/sub-blocks/Content/Content.css +7 -7
  16. package/build/esm/blocks/Tabs/Tabs.css +3 -37
  17. package/build/esm/blocks/Tabs/Tabs.js +22 -19
  18. package/build/esm/blocks/Tabs/TabsTextContent/TabsTextContent.css +27 -0
  19. package/build/esm/blocks/Tabs/TabsTextContent/TabsTextContent.d.ts +11 -0
  20. package/build/esm/blocks/Tabs/TabsTextContent/TabsTextContent.js +16 -0
  21. package/build/esm/components/Image/Image.d.ts +2 -1
  22. package/build/esm/components/Image/Image.js +3 -3
  23. package/build/esm/components/ImageBase/ImageBase.d.ts +2 -1
  24. package/build/esm/components/Media/Image/Image.d.ts +1 -0
  25. package/build/esm/components/Media/Image/Image.js +2 -2
  26. package/build/esm/components/Media/Media.d.ts +1 -0
  27. package/build/esm/components/Media/Media.js +4 -3
  28. package/build/esm/components/VideoBlock/VideoBlock.d.ts +1 -0
  29. package/build/esm/components/VideoBlock/VideoBlock.js +2 -2
  30. package/build/esm/sub-blocks/Content/Content.css +7 -7
  31. package/package.json +1 -1
  32. package/widget/index.js +1 -1
@@ -1,16 +1,12 @@
1
- .pc-tabs-block__content-title.pc-tabs-block__content-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
- .pc-tabs-block__block-title {
3
+ .pc-tabs-block__title {
8
4
  margin-bottom: 24px;
9
5
  }
10
- .pc-tabs-block__block-title_centered {
6
+ .pc-tabs-block__title_centered {
11
7
  text-align: center;
12
8
  }
13
- .pc-tabs-block__block-title_centered > * {
9
+ .pc-tabs-block__title_centered > * {
14
10
  margin: 0 auto;
15
11
  }
16
12
  .pc-tabs-block__tabs {
@@ -44,9 +40,6 @@ unpredictable css rules order in build */
44
40
  .pc-tabs-block__row_reverse {
45
41
  flex-direction: row-reverse;
46
42
  }
47
- .pc-tabs-block__row_reverse .pc-tabs-block__content-wrapper {
48
- margin: 24px 32px 0 0;
49
- }
50
43
  .pc-tabs-block__image {
51
44
  width: 100%;
52
45
  height: auto;
@@ -64,40 +57,13 @@ unpredictable css rules order in build */
64
57
  margin: 12px 0 0;
65
58
  color: var(--g-color-text-secondary);
66
59
  }
67
- .pc-tabs-block__content {
68
- display: flex;
69
- flex-direction: column;
70
- }
71
- .pc-tabs-block__content_centered {
72
- margin: 0 auto;
73
- }
74
60
  .pc-tabs-block__col_centered {
75
61
  margin: 0 auto;
76
62
  }
77
- .pc-tabs-block__content-wrapper_margin {
78
- margin: 24px 0 0 32px;
79
- }
80
- .pc-tabs-block__content-title {
81
- margin: 0 auto 12px;
82
- }
83
- .pc-tabs-block__content-title.pc-tabs-block__content-title > * {
84
- font-size: var(--g-text-header-1-font-size);
85
- line-height: var(--g-text-header-1-line-height);
86
- color: var(--pc-text-header-color);
87
- font-weight: var(--g-text-accent-font-weight);
88
- }
89
-
90
63
  @media (max-width: 769px) {
91
- .pc-tabs-block__content-wrapper_margin {
92
- margin: 0 0 32px 0;
93
- }
94
64
  .pc-tabs-block__row_reverse {
95
65
  flex-direction: column-reverse;
96
66
  }
97
- .pc-tabs-block__row_reverse .pc-tabs-block__content > * {
98
- margin-top: 32px;
99
- padding-bottom: 0;
100
- }
101
67
  }
102
68
  @media (min-width: 769px) {
103
69
  .pc-tabs-block.pc-AnimateBlock .pc-tabs-block__media, .pc-AnimateBlock .pc-tabs-block .pc-tabs-block__media {
@@ -13,11 +13,11 @@ const Title_1 = tslib_1.__importDefault(require("../../components/Title/Title"))
13
13
  const VideoBlock_1 = require("../../components/VideoBlock/VideoBlock");
14
14
  const theme_1 = require("../../context/theme");
15
15
  const grid_1 = require("../../grid");
16
- const sub_blocks_1 = require("../../sub-blocks");
17
16
  const utils_2 = require("../../utils");
17
+ const TabsTextContent_1 = tslib_1.__importDefault(require("./TabsTextContent/TabsTextContent"));
18
18
  const b = (0, utils_2.block)('tabs-block');
19
19
  const TabsBlock = ({ items, title, description, animated, tabsColSizes, centered, direction = 'media-content', contentSize = 's', }) => {
20
- var _a;
20
+ var _a, _b;
21
21
  const [activeTab, setActiveTab] = (0, react_1.useState)(items[0].tabName);
22
22
  const [play, setPlay] = (0, react_1.useState)(false);
23
23
  const theme = (0, theme_1.useTheme)();
@@ -26,11 +26,24 @@ const TabsBlock = ({ items, title, description, animated, tabsColSizes, centered
26
26
  const isReverse = direction === 'content-media';
27
27
  const ref = (0, react_1.useRef)(null);
28
28
  const mediaWidth = (_a = ref === null || ref === void 0 ? void 0 : ref.current) === null || _a === void 0 ? void 0 : _a.offsetWidth;
29
- const mediaHeight = mediaWidth && (0, VideoBlock_1.getHeight)(mediaWidth);
30
29
  const captionId = (0, uikit_1.useUniqId)();
30
+ const themedMedia = (0, utils_2.getThemedValue)(activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.media, theme);
31
+ const hasNoImage = !(themedMedia === null || themedMedia === void 0 ? void 0 : themedMedia.image) || !(activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.image);
32
+ const mediaVideoHeight = hasNoImage && mediaWidth && (0, VideoBlock_1.getHeight)(mediaWidth);
33
+ const [minImageHeight, setMinImageHeight] = (0, react_1.useState)((_b = ref === null || ref === void 0 ? void 0 : ref.current) === null || _b === void 0 ? void 0 : _b.offsetHeight);
34
+ // TODO remove property support activeTabData?.image. Use only activeTabData?.media?.image
31
35
  let imageProps;
36
+ const handleImageHeight = (0, react_1.useCallback)(() => {
37
+ var _a;
38
+ setMinImageHeight((_a = ref === null || ref === void 0 ? void 0 : ref.current) === null || _a === void 0 ? void 0 : _a.offsetHeight);
39
+ }, []);
40
+ const onSelectTab = (id, e) => {
41
+ setActiveTab(id);
42
+ handleImageHeight();
43
+ e.currentTarget.scrollIntoView({ inline: 'center', behavior: 'smooth', block: 'nearest' });
44
+ };
32
45
  if (activeTabData) {
33
- const themedImage = (0, utils_2.getThemedValue)(activeTabData.image, theme);
46
+ const themedImage = (0, utils_2.getThemedValue)(activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.image, theme);
34
47
  imageProps = themedImage && (0, utils_1.getMediaImage)(themedImage);
35
48
  if (activeTabData.caption && imageProps) {
36
49
  Object.assign(imageProps, {
@@ -40,28 +53,18 @@ const TabsBlock = ({ items, title, description, animated, tabsColSizes, centered
40
53
  }
41
54
  const showMedia = Boolean((activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.media) || imageProps);
42
55
  const showText = Boolean(activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.text);
43
- const textContent = activeTabData && showText && (react_1.default.createElement(grid_1.Col, { sizes: { all: 12, md: showMedia ? 4 : 8 }, className: b('content', { centered: centered }) },
44
- react_1.default.createElement("div", { className: b('content-wrapper', {
45
- margin: Boolean(((activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.media) || imageProps) && !isReverse),
46
- }) },
47
- react_1.default.createElement(sub_blocks_1.Content, { title: activeTabData.title, text: activeTabData.text, additionalInfo: activeTabData.additionalInfo, size: contentSize, links: [
48
- ...(activeTabData.link ? [activeTabData.link] : []),
49
- ...(activeTabData.links || []),
50
- ], buttons: activeTabData.buttons, colSizes: { all: 12 } }))));
56
+ const textContent = activeTabData && showText && (react_1.default.createElement(TabsTextContent_1.default, { showMedia: showMedia, data: activeTabData, imageProps: imageProps ? imageProps : undefined, isReverse: isReverse, contentSize: contentSize, centered: centered }));
51
57
  const mediaContent = showMedia && (react_1.default.createElement(grid_1.Col, { sizes: { all: 12, md: 8 }, orders: {
52
58
  all: grid_1.GridColumnOrderClasses.Last,
53
59
  md: grid_1.GridColumnOrderClasses.First,
54
60
  }, className: b('col', { centered: centered }) },
55
- react_1.default.createElement("div", { ref: ref }, (activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.media) && (react_1.default.createElement(Media_1.default, Object.assign({}, (0, utils_2.getThemedValue)(activeTabData.media, theme), { key: activeTab, className: b('media'), playVideo: play, height: mediaHeight })))),
61
+ react_1.default.createElement("div", { style: { minHeight: mediaVideoHeight || minImageHeight } }, (activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.media) && (react_1.default.createElement("div", { ref: ref },
62
+ react_1.default.createElement(Media_1.default, Object.assign({}, (0, utils_2.getThemedValue)(activeTabData.media, theme), { key: activeTab, className: b('media'), playVideo: play, height: mediaVideoHeight || undefined, onImageLoad: handleImageHeight }))))),
56
63
  imageProps && (react_1.default.createElement(react_1.Fragment, null,
57
64
  react_1.default.createElement(FullscreenImage_1.default, Object.assign({}, imageProps, { imageClassName: b('image') })))),
58
65
  (activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.caption) && (react_1.default.createElement("p", { className: b('caption'), id: captionId }, activeTabData.caption))));
59
- const onSelectTab = (id, e) => {
60
- setActiveTab(id);
61
- e.currentTarget.scrollIntoView({ inline: 'center', behavior: 'smooth', block: 'nearest' });
62
- };
63
66
  return (react_1.default.createElement(AnimateBlock_1.default, { className: b(), onScroll: () => setPlay(true), animate: animated },
64
- react_1.default.createElement(Title_1.default, { title: title, subtitle: description, className: b('block-title', { centered: centered }) }),
67
+ react_1.default.createElement(Title_1.default, { title: title, subtitle: description, className: b('title', { centered: centered }) }),
65
68
  react_1.default.createElement(grid_1.Row, null,
66
69
  react_1.default.createElement(grid_1.Col, { sizes: tabsColSizes },
67
70
  react_1.default.createElement(ButtonTabs_1.default, { items: tabs, onSelectTab: onSelectTab, activeTab: activeTab, className: b('tabs', { centered: centered }) }))),
@@ -0,0 +1,27 @@
1
+ /* use this for style redefinitions to awoid problems with
2
+ unpredictable css rules order in build */
3
+ .pc-tabs-block-text-content {
4
+ display: flex;
5
+ flex-direction: column;
6
+ }
7
+ .pc-tabs-block-text-content_centered {
8
+ margin: 0 auto;
9
+ }
10
+ .pc-tabs-block-text-content__wrapper {
11
+ margin: 24px 0 0 32px;
12
+ }
13
+ .pc-tabs-block-text-content__wrapper_reverse {
14
+ margin: 24px 32px 0 0;
15
+ }
16
+ .pc-tabs-block-text-content__wrapper_no-image {
17
+ margin: 0;
18
+ }
19
+ @media (max-width: 769px) {
20
+ .pc-tabs-block-text-content__wrapper {
21
+ margin: 0 0 32px 0;
22
+ }
23
+ .pc-tabs-block-text-content__wrapper_reverse {
24
+ margin-top: 32px;
25
+ padding-bottom: 0;
26
+ }
27
+ }
@@ -0,0 +1,10 @@
1
+ import { ImageDeviceProps, ImageObjectProps, TabsBlockItem, TabsBlockProps } from '../../../models';
2
+ interface TextContentProps extends Pick<TabsBlockProps, 'centered' | 'contentSize'> {
3
+ showMedia: boolean;
4
+ isReverse: boolean;
5
+ data: TabsBlockItem;
6
+ centered?: boolean;
7
+ imageProps?: ImageObjectProps | ImageDeviceProps;
8
+ }
9
+ export declare const TabsTextContent: ({ centered, contentSize, showMedia, data, imageProps, isReverse, }: TextContentProps) => JSX.Element;
10
+ export default TabsTextContent;
@@ -0,0 +1,20 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.TabsTextContent = void 0;
4
+ const tslib_1 = require("tslib");
5
+ const react_1 = tslib_1.__importDefault(require("react"));
6
+ const grid_1 = require("../../../grid");
7
+ const sub_blocks_1 = require("../../../sub-blocks");
8
+ const utils_1 = require("../../../utils");
9
+ const b = (0, utils_1.block)('tabs-block-text-content');
10
+ const TabsTextContent = ({ centered, contentSize = 's', showMedia, data, imageProps, isReverse, }) => {
11
+ const isImage = (data === null || data === void 0 ? void 0 : data.media) || imageProps;
12
+ return (react_1.default.createElement(grid_1.Col, { sizes: { all: 12, md: showMedia ? 4 : 8 }, className: b({ centered: centered }) },
13
+ react_1.default.createElement("div", { className: b('wrapper', {
14
+ reverse: isReverse,
15
+ 'no-image': !isImage,
16
+ }) },
17
+ react_1.default.createElement(sub_blocks_1.Content, { title: data.title, text: data.text, additionalInfo: data.additionalInfo, size: contentSize, links: [...(data.link ? [data.link] : []), ...(data.links || [])], buttons: data.buttons, colSizes: { all: 12 } }))));
18
+ };
19
+ exports.TabsTextContent = TabsTextContent;
20
+ exports.default = exports.TabsTextContent;
@@ -1,9 +1,10 @@
1
- import { CSSProperties, MouseEventHandler } from 'react';
1
+ import { CSSProperties, MouseEventHandler, ReactEventHandler } from 'react';
2
2
  import { ImageDeviceProps, ImageObjectProps, QAProps } from '../../models';
3
3
  export interface ImageProps extends Partial<ImageObjectProps>, Partial<ImageDeviceProps>, QAProps {
4
4
  style?: CSSProperties;
5
5
  className?: string;
6
6
  onClick?: MouseEventHandler;
7
+ onLoad?: ReactEventHandler<HTMLDivElement>;
7
8
  containerClassName?: string;
8
9
  }
9
10
  export interface DeviceSpecificFragmentProps extends QAProps {
@@ -15,7 +15,7 @@ const DeviceSpecificFragment = ({ disableWebp, src, breakpoint, qa, }) => (react
15
15
  react_1.default.createElement("source", { srcSet: src, media: `(max-width: ${breakpoint}px)`, "data-qa": qa })));
16
16
  const Image = (props) => {
17
17
  const projectSettings = (0, react_1.useContext)(projectSettingsContext_1.ProjectSettingsContext);
18
- const { src: imageSrc, alt, disableCompress, tablet, desktop, mobile, style, className, onClick, containerClassName, qa, } = props;
18
+ const { src: imageSrc, alt, disableCompress, tablet, desktop, mobile, style, className, onClick, onLoad, containerClassName, qa, } = props;
19
19
  const [imgLoadingError, setImgLoadingError] = (0, react_1.useState)(false);
20
20
  const src = imageSrc || desktop;
21
21
  if (!src) {
@@ -30,6 +30,6 @@ const Image = (props) => {
30
30
  mobile && (react_1.default.createElement(DeviceSpecificFragment, { src: mobile, disableWebp: disableWebp, breakpoint: constants_1.BREAKPOINTS.sm, qa: qaAttributes.mobileSource })),
31
31
  tablet && (react_1.default.createElement(DeviceSpecificFragment, { src: tablet, disableWebp: disableWebp, breakpoint: constants_1.BREAKPOINTS.md, qa: qaAttributes.tabletSource })),
32
32
  src && !disableWebp && (react_1.default.createElement("source", { srcSet: checkWebP(src), type: "image/webp", "data-qa": qaAttributes.desktopSourceCompressed })),
33
- react_1.default.createElement(ImageBase_1.default, { className: className, alt: alt, src: src, style: style, onClick: onClick, onError: () => setImgLoadingError(true) })));
33
+ react_1.default.createElement(ImageBase_1.default, { className: className, alt: alt, src: src, style: style, onClick: onClick, onError: () => setImgLoadingError(true), onLoad: onLoad })));
34
34
  };
35
35
  exports.default = Image;
@@ -1,9 +1,10 @@
1
- import { CSSProperties, MouseEventHandler } from 'react';
1
+ import { CSSProperties, MouseEventHandler, ReactEventHandler } from 'react';
2
2
  import { ImageObjectProps } from '../../models';
3
3
  export interface ImageBaseProps extends Partial<ImageObjectProps> {
4
4
  style?: CSSProperties;
5
5
  className?: string;
6
6
  onClick?: MouseEventHandler;
7
+ onLoad?: ReactEventHandler<HTMLDivElement>;
7
8
  onError?: () => void;
8
9
  }
9
10
  export declare const ImageBase: (props: ImageBaseProps) => JSX.Element;
@@ -3,6 +3,7 @@ export interface ImageAdditionProps {
3
3
  imageClassName?: string;
4
4
  isBackground?: boolean;
5
5
  fullscreen?: boolean;
6
+ onLoad?: () => void;
6
7
  }
7
8
  interface InnerImageProps {
8
9
  hasVideoFallback: boolean;
@@ -15,7 +15,7 @@ const utils_2 = require("./utils");
15
15
  const b = (0, utils_1.block)('media-component-image');
16
16
  exports.defaultAnimatedDivQa = 'animated-div';
17
17
  const Image = (props) => {
18
- const { parallax, image, height, imageClassName, isBackground, hasVideoFallback, video, fullscreen, qa, } = props;
18
+ const { parallax, image, height, imageClassName, isBackground, hasVideoFallback, video, fullscreen, qa, onLoad, } = props;
19
19
  const qaAttributes = (0, utils_1.getQaAttrubutes)(qa, 'fullscreen-image', 'animate', 'background-image', 'image-view', 'slider-block');
20
20
  const [scrollY, setScrollY] = (0, react_1.useState)(0);
21
21
  const [{ springScrollY }, springSetScrollY] = (0, web_1.useSpring)(() => ({
@@ -49,7 +49,7 @@ const Image = (props) => {
49
49
  };
50
50
  const imageOnly = (oneImage) => {
51
51
  const imageData = (0, utils_2.getMediaImage)(oneImage);
52
- return (react_1.default.createElement(Image_1.default, Object.assign({}, imageData, { className: imageClass, style: { height }, qa: qaAttributes.imageView })));
52
+ return (react_1.default.createElement(Image_1.default, Object.assign({}, imageData, { className: imageClass, style: { height }, qa: qaAttributes.imageView, onLoad: onLoad })));
53
53
  };
54
54
  const imageSlider = (imageArray) => {
55
55
  const fullscreenItem = fullscreen === undefined || fullscreen;
@@ -5,6 +5,7 @@ export interface MediaAllProps extends MediaProps, VideoAdditionProps, ImageAddi
5
5
  className?: string;
6
6
  youtubeClassName?: string;
7
7
  autoplay?: boolean;
8
+ onImageLoad?: () => void;
8
9
  }
9
10
  export declare const Media: (props: MediaAllProps) => JSX.Element;
10
11
  export default Media;
@@ -11,13 +11,13 @@ const Image_1 = tslib_1.__importDefault(require("./Image/Image"));
11
11
  const Video_1 = tslib_1.__importDefault(require("./Video/Video"));
12
12
  const b = (0, utils_1.block)('Media');
13
13
  const Media = (props) => {
14
- const { image, video, youtube, dataLens, color, height, previewImg, parallax = false, metrika, fullscreen, analyticsEvents, className, imageClassName, videoClassName, youtubeClassName, playVideo = true, isBackground, playButton, customBarControlsClassName, qa, ratio, autoplay, } = props;
14
+ const { image, video, youtube, dataLens, color, height, previewImg, parallax = false, metrika, fullscreen, analyticsEvents, className, imageClassName, videoClassName, youtubeClassName, playVideo = true, isBackground, playButton, customBarControlsClassName, qa, ratio, autoplay, onImageLoad, } = props;
15
15
  const [hasVideoFallback, setHasVideoFallback] = (0, react_1.useState)(false);
16
16
  const qaAttributes = (0, utils_1.getQaAttrubutes)(qa, 'video');
17
17
  const content = (0, react_1.useMemo)(() => {
18
18
  let result = [];
19
19
  if (image) {
20
- result.push(react_1.default.createElement(Image_1.default, { key: "image", parallax: parallax, image: image, height: height, imageClassName: imageClassName, isBackground: isBackground, video: video, hasVideoFallback: hasVideoFallback, fullscreen: fullscreen, qa: qaAttributes.image }));
20
+ result.push(react_1.default.createElement(Image_1.default, { key: "image", parallax: parallax, image: image, height: height, imageClassName: imageClassName, isBackground: isBackground, video: video, hasVideoFallback: hasVideoFallback, fullscreen: fullscreen, qa: qaAttributes.image, onLoad: onImageLoad }));
21
21
  }
22
22
  if (video) {
23
23
  const videoProps = {
@@ -43,7 +43,7 @@ const Media = (props) => {
43
43
  }
44
44
  }
45
45
  if (youtube) {
46
- result = (react_1.default.createElement(VideoBlock_1.default, { className: b('youtube', youtubeClassName), record: youtube, attributes: { color: 'white', rel: '0' }, previewImg: previewImg, height: height, fullscreen: fullscreen, analyticsEvents: analyticsEvents, autoplay: autoplay }));
46
+ result = (react_1.default.createElement(VideoBlock_1.default, { className: b('youtube', youtubeClassName), record: youtube, attributes: { color: 'white', rel: '0' }, previewImg: previewImg, height: height, fullscreen: fullscreen, analyticsEvents: analyticsEvents, autoplay: autoplay, onImageLoad: onImageLoad }));
47
47
  }
48
48
  if (dataLens) {
49
49
  result = react_1.default.createElement(DataLens_1.default, { dataLens: dataLens });
@@ -62,6 +62,7 @@ const Media = (props) => {
62
62
  fullscreen,
63
63
  qaAttributes.image,
64
64
  qaAttributes.video,
65
+ onImageLoad,
65
66
  videoClassName,
66
67
  metrika,
67
68
  analyticsEvents,
@@ -16,6 +16,7 @@ export interface VideoBlockProps extends AnalyticsEventsBase {
16
16
  height?: number;
17
17
  fullscreen?: boolean;
18
18
  autoplay?: boolean;
19
+ onImageLoad?: () => void;
19
20
  }
20
21
  declare const VideoBlock: (props: VideoBlockProps) => JSX.Element | null;
21
22
  export default VideoBlock;
@@ -41,7 +41,7 @@ function getHeight(width) {
41
41
  }
42
42
  exports.getHeight = getHeight;
43
43
  const VideoBlock = (props) => {
44
- const { stream, record, attributes, className, id, previewImg, playButton, height, fullscreen, analyticsEvents, autoplay, } = props;
44
+ const { stream, record, attributes, className, id, previewImg, playButton, height, fullscreen, analyticsEvents, autoplay, onImageLoad, } = props;
45
45
  const handleAnalytics = (0, useAnalytics_1.useAnalytics)(common_1.DefaultEventNames.VideoPreview);
46
46
  const src = getVideoSrc(stream, record);
47
47
  const ref = (0, react_1.useRef)(null);
@@ -95,7 +95,7 @@ const VideoBlock = (props) => {
95
95
  return null;
96
96
  }
97
97
  return (react_1.default.createElement("div", { className: b(null, className), ref: ref, style: { height: currentHeight } }, previewImg && !hidePreview && !fullscreen && (react_1.default.createElement("div", { className: b('preview'), onClick: onPreviewClick },
98
- react_1.default.createElement(Image_1.default, { src: previewImg, className: b('image'), containerClassName: b('image-wrapper') }),
98
+ react_1.default.createElement(Image_1.default, { src: previewImg, className: b('image'), containerClassName: b('image-wrapper'), onLoad: onImageLoad }),
99
99
  playButton || (react_1.default.createElement("button", { title: "Play", className: b('button') },
100
100
  react_1.default.createElement(uikit_1.Icon, { className: b('icon'), data: icons_1.PlayVideo, size: 24 })))))));
101
101
  };
@@ -27,14 +27,11 @@ unpredictable css rules order in build */
27
27
  color: var(--g-color-text-primary);
28
28
  }
29
29
 
30
- .pc-content__button.pc-content__button {
31
- margin-top: 0;
32
- margin-right: 12px;
33
- }
34
- .pc-content__button.pc-content__button:last-child {
35
- margin-right: 0;
30
+ .pc-content__buttons {
31
+ display: flex;
32
+ flex-wrap: wrap;
33
+ column-gap: 12px;
36
34
  }
37
-
38
35
  .pc-content__links {
39
36
  display: flex;
40
37
  flex-direction: column;
@@ -48,6 +45,9 @@ unpredictable css rules order in build */
48
45
  text-align: center;
49
46
  }
50
47
 
48
+ .pc-content_centered .pc-content__buttons {
49
+ justify-content: center;
50
+ }
51
51
  .pc-content_centered .pc-content__links {
52
52
  align-items: center;
53
53
  }
@@ -1,16 +1,12 @@
1
- .pc-tabs-block__content-title.pc-tabs-block__content-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
- .pc-tabs-block__block-title {
3
+ .pc-tabs-block__title {
8
4
  margin-bottom: 24px;
9
5
  }
10
- .pc-tabs-block__block-title_centered {
6
+ .pc-tabs-block__title_centered {
11
7
  text-align: center;
12
8
  }
13
- .pc-tabs-block__block-title_centered > * {
9
+ .pc-tabs-block__title_centered > * {
14
10
  margin: 0 auto;
15
11
  }
16
12
  .pc-tabs-block__tabs {
@@ -44,9 +40,6 @@ unpredictable css rules order in build */
44
40
  .pc-tabs-block__row_reverse {
45
41
  flex-direction: row-reverse;
46
42
  }
47
- .pc-tabs-block__row_reverse .pc-tabs-block__content-wrapper {
48
- margin: 24px 32px 0 0;
49
- }
50
43
  .pc-tabs-block__image {
51
44
  width: 100%;
52
45
  height: auto;
@@ -64,40 +57,13 @@ unpredictable css rules order in build */
64
57
  margin: 12px 0 0;
65
58
  color: var(--g-color-text-secondary);
66
59
  }
67
- .pc-tabs-block__content {
68
- display: flex;
69
- flex-direction: column;
70
- }
71
- .pc-tabs-block__content_centered {
72
- margin: 0 auto;
73
- }
74
60
  .pc-tabs-block__col_centered {
75
61
  margin: 0 auto;
76
62
  }
77
- .pc-tabs-block__content-wrapper_margin {
78
- margin: 24px 0 0 32px;
79
- }
80
- .pc-tabs-block__content-title {
81
- margin: 0 auto 12px;
82
- }
83
- .pc-tabs-block__content-title.pc-tabs-block__content-title > * {
84
- font-size: var(--g-text-header-1-font-size);
85
- line-height: var(--g-text-header-1-line-height);
86
- color: var(--pc-text-header-color);
87
- font-weight: var(--g-text-accent-font-weight);
88
- }
89
-
90
63
  @media (max-width: 769px) {
91
- .pc-tabs-block__content-wrapper_margin {
92
- margin: 0 0 32px 0;
93
- }
94
64
  .pc-tabs-block__row_reverse {
95
65
  flex-direction: column-reverse;
96
66
  }
97
- .pc-tabs-block__row_reverse .pc-tabs-block__content > * {
98
- margin-top: 32px;
99
- padding-bottom: 0;
100
- }
101
67
  }
102
68
  @media (min-width: 769px) {
103
69
  .pc-tabs-block.pc-AnimateBlock .pc-tabs-block__media, .pc-AnimateBlock .pc-tabs-block .pc-tabs-block__media {
@@ -1,4 +1,4 @@
1
- import React, { Fragment, useRef, useState } from 'react';
1
+ import React, { Fragment, useCallback, useRef, useState } from 'react';
2
2
  import { useUniqId } from '@gravity-ui/uikit';
3
3
  import AnimateBlock from '../../components/AnimateBlock/AnimateBlock';
4
4
  import ButtonTabs from '../../components/ButtonTabs/ButtonTabs';
@@ -9,12 +9,12 @@ import Title from '../../components/Title/Title';
9
9
  import { getHeight } from '../../components/VideoBlock/VideoBlock';
10
10
  import { useTheme } from '../../context/theme';
11
11
  import { Col, GridColumnOrderClasses, Row } from '../../grid';
12
- import { Content } from '../../sub-blocks';
13
12
  import { block, getThemedValue } from '../../utils';
13
+ import TabsTextContent from './TabsTextContent/TabsTextContent';
14
14
  import './Tabs.css';
15
15
  const b = block('tabs-block');
16
16
  export const TabsBlock = ({ items, title, description, animated, tabsColSizes, centered, direction = 'media-content', contentSize = 's', }) => {
17
- var _a;
17
+ var _a, _b;
18
18
  const [activeTab, setActiveTab] = useState(items[0].tabName);
19
19
  const [play, setPlay] = useState(false);
20
20
  const theme = useTheme();
@@ -23,11 +23,24 @@ export const TabsBlock = ({ items, title, description, animated, tabsColSizes, c
23
23
  const isReverse = direction === 'content-media';
24
24
  const ref = useRef(null);
25
25
  const mediaWidth = (_a = ref === null || ref === void 0 ? void 0 : ref.current) === null || _a === void 0 ? void 0 : _a.offsetWidth;
26
- const mediaHeight = mediaWidth && getHeight(mediaWidth);
27
26
  const captionId = useUniqId();
27
+ const themedMedia = getThemedValue(activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.media, theme);
28
+ const hasNoImage = !(themedMedia === null || themedMedia === void 0 ? void 0 : themedMedia.image) || !(activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.image);
29
+ const mediaVideoHeight = hasNoImage && mediaWidth && getHeight(mediaWidth);
30
+ const [minImageHeight, setMinImageHeight] = useState((_b = ref === null || ref === void 0 ? void 0 : ref.current) === null || _b === void 0 ? void 0 : _b.offsetHeight);
31
+ // TODO remove property support activeTabData?.image. Use only activeTabData?.media?.image
28
32
  let imageProps;
33
+ const handleImageHeight = useCallback(() => {
34
+ var _a;
35
+ setMinImageHeight((_a = ref === null || ref === void 0 ? void 0 : ref.current) === null || _a === void 0 ? void 0 : _a.offsetHeight);
36
+ }, []);
37
+ const onSelectTab = (id, e) => {
38
+ setActiveTab(id);
39
+ handleImageHeight();
40
+ e.currentTarget.scrollIntoView({ inline: 'center', behavior: 'smooth', block: 'nearest' });
41
+ };
29
42
  if (activeTabData) {
30
- const themedImage = getThemedValue(activeTabData.image, theme);
43
+ const themedImage = getThemedValue(activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.image, theme);
31
44
  imageProps = themedImage && getMediaImage(themedImage);
32
45
  if (activeTabData.caption && imageProps) {
33
46
  Object.assign(imageProps, {
@@ -37,28 +50,18 @@ export const TabsBlock = ({ items, title, description, animated, tabsColSizes, c
37
50
  }
38
51
  const showMedia = Boolean((activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.media) || imageProps);
39
52
  const showText = Boolean(activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.text);
40
- const textContent = activeTabData && showText && (React.createElement(Col, { sizes: { all: 12, md: showMedia ? 4 : 8 }, className: b('content', { centered: centered }) },
41
- React.createElement("div", { className: b('content-wrapper', {
42
- margin: Boolean(((activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.media) || imageProps) && !isReverse),
43
- }) },
44
- React.createElement(Content, { title: activeTabData.title, text: activeTabData.text, additionalInfo: activeTabData.additionalInfo, size: contentSize, links: [
45
- ...(activeTabData.link ? [activeTabData.link] : []),
46
- ...(activeTabData.links || []),
47
- ], buttons: activeTabData.buttons, colSizes: { all: 12 } }))));
53
+ const textContent = activeTabData && showText && (React.createElement(TabsTextContent, { showMedia: showMedia, data: activeTabData, imageProps: imageProps ? imageProps : undefined, isReverse: isReverse, contentSize: contentSize, centered: centered }));
48
54
  const mediaContent = showMedia && (React.createElement(Col, { sizes: { all: 12, md: 8 }, orders: {
49
55
  all: GridColumnOrderClasses.Last,
50
56
  md: GridColumnOrderClasses.First,
51
57
  }, className: b('col', { centered: centered }) },
52
- React.createElement("div", { ref: ref }, (activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.media) && (React.createElement(Media, Object.assign({}, getThemedValue(activeTabData.media, theme), { key: activeTab, className: b('media'), playVideo: play, height: mediaHeight })))),
58
+ React.createElement("div", { style: { minHeight: mediaVideoHeight || minImageHeight } }, (activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.media) && (React.createElement("div", { ref: ref },
59
+ React.createElement(Media, Object.assign({}, getThemedValue(activeTabData.media, theme), { key: activeTab, className: b('media'), playVideo: play, height: mediaVideoHeight || undefined, onImageLoad: handleImageHeight }))))),
53
60
  imageProps && (React.createElement(Fragment, null,
54
61
  React.createElement(FullscreenImage, Object.assign({}, imageProps, { imageClassName: b('image') })))),
55
62
  (activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.caption) && (React.createElement("p", { className: b('caption'), id: captionId }, activeTabData.caption))));
56
- const onSelectTab = (id, e) => {
57
- setActiveTab(id);
58
- e.currentTarget.scrollIntoView({ inline: 'center', behavior: 'smooth', block: 'nearest' });
59
- };
60
63
  return (React.createElement(AnimateBlock, { className: b(), onScroll: () => setPlay(true), animate: animated },
61
- React.createElement(Title, { title: title, subtitle: description, className: b('block-title', { centered: centered }) }),
64
+ React.createElement(Title, { title: title, subtitle: description, className: b('title', { centered: centered }) }),
62
65
  React.createElement(Row, null,
63
66
  React.createElement(Col, { sizes: tabsColSizes },
64
67
  React.createElement(ButtonTabs, { items: tabs, onSelectTab: onSelectTab, activeTab: activeTab, className: b('tabs', { centered: centered }) }))),
@@ -0,0 +1,27 @@
1
+ /* use this for style redefinitions to awoid problems with
2
+ unpredictable css rules order in build */
3
+ .pc-tabs-block-text-content {
4
+ display: flex;
5
+ flex-direction: column;
6
+ }
7
+ .pc-tabs-block-text-content_centered {
8
+ margin: 0 auto;
9
+ }
10
+ .pc-tabs-block-text-content__wrapper {
11
+ margin: 24px 0 0 32px;
12
+ }
13
+ .pc-tabs-block-text-content__wrapper_reverse {
14
+ margin: 24px 32px 0 0;
15
+ }
16
+ .pc-tabs-block-text-content__wrapper_no-image {
17
+ margin: 0;
18
+ }
19
+ @media (max-width: 769px) {
20
+ .pc-tabs-block-text-content__wrapper {
21
+ margin: 0 0 32px 0;
22
+ }
23
+ .pc-tabs-block-text-content__wrapper_reverse {
24
+ margin-top: 32px;
25
+ padding-bottom: 0;
26
+ }
27
+ }
@@ -0,0 +1,11 @@
1
+ import { ImageDeviceProps, ImageObjectProps, TabsBlockItem, TabsBlockProps } from '../../../models';
2
+ import './TabsTextContent.css';
3
+ interface TextContentProps extends Pick<TabsBlockProps, 'centered' | 'contentSize'> {
4
+ showMedia: boolean;
5
+ isReverse: boolean;
6
+ data: TabsBlockItem;
7
+ centered?: boolean;
8
+ imageProps?: ImageObjectProps | ImageDeviceProps;
9
+ }
10
+ export declare const TabsTextContent: ({ centered, contentSize, showMedia, data, imageProps, isReverse, }: TextContentProps) => JSX.Element;
11
+ export default TabsTextContent;
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+ import { Col } from '../../../grid';
3
+ import { Content } from '../../../sub-blocks';
4
+ import { block } from '../../../utils';
5
+ import './TabsTextContent.css';
6
+ const b = block('tabs-block-text-content');
7
+ export const TabsTextContent = ({ centered, contentSize = 's', showMedia, data, imageProps, isReverse, }) => {
8
+ const isImage = (data === null || data === void 0 ? void 0 : data.media) || imageProps;
9
+ return (React.createElement(Col, { sizes: { all: 12, md: showMedia ? 4 : 8 }, className: b({ centered: centered }) },
10
+ React.createElement("div", { className: b('wrapper', {
11
+ reverse: isReverse,
12
+ 'no-image': !isImage,
13
+ }) },
14
+ React.createElement(Content, { title: data.title, text: data.text, additionalInfo: data.additionalInfo, size: contentSize, links: [...(data.link ? [data.link] : []), ...(data.links || [])], buttons: data.buttons, colSizes: { all: 12 } }))));
15
+ };
16
+ export default TabsTextContent;
@@ -1,9 +1,10 @@
1
- import { CSSProperties, MouseEventHandler } from 'react';
1
+ import { CSSProperties, MouseEventHandler, ReactEventHandler } from 'react';
2
2
  import { ImageDeviceProps, ImageObjectProps, QAProps } from '../../models';
3
3
  export interface ImageProps extends Partial<ImageObjectProps>, Partial<ImageDeviceProps>, QAProps {
4
4
  style?: CSSProperties;
5
5
  className?: string;
6
6
  onClick?: MouseEventHandler;
7
+ onLoad?: ReactEventHandler<HTMLDivElement>;
7
8
  containerClassName?: string;
8
9
  }
9
10
  export interface DeviceSpecificFragmentProps extends QAProps {
@@ -1,4 +1,4 @@
1
- import React, { Fragment, useContext, useState } from 'react';
1
+ import React, { Fragment, useContext, useState, } from 'react';
2
2
  import { BREAKPOINTS } from '../../constants';
3
3
  import { ProjectSettingsContext } from '../../context/projectSettingsContext';
4
4
  import { getQaAttrubutes } from '../../utils';
@@ -12,7 +12,7 @@ const DeviceSpecificFragment = ({ disableWebp, src, breakpoint, qa, }) => (React
12
12
  React.createElement("source", { srcSet: src, media: `(max-width: ${breakpoint}px)`, "data-qa": qa })));
13
13
  const Image = (props) => {
14
14
  const projectSettings = useContext(ProjectSettingsContext);
15
- const { src: imageSrc, alt, disableCompress, tablet, desktop, mobile, style, className, onClick, containerClassName, qa, } = props;
15
+ const { src: imageSrc, alt, disableCompress, tablet, desktop, mobile, style, className, onClick, onLoad, containerClassName, qa, } = props;
16
16
  const [imgLoadingError, setImgLoadingError] = useState(false);
17
17
  const src = imageSrc || desktop;
18
18
  if (!src) {
@@ -27,6 +27,6 @@ const Image = (props) => {
27
27
  mobile && (React.createElement(DeviceSpecificFragment, { src: mobile, disableWebp: disableWebp, breakpoint: BREAKPOINTS.sm, qa: qaAttributes.mobileSource })),
28
28
  tablet && (React.createElement(DeviceSpecificFragment, { src: tablet, disableWebp: disableWebp, breakpoint: BREAKPOINTS.md, qa: qaAttributes.tabletSource })),
29
29
  src && !disableWebp && (React.createElement("source", { srcSet: checkWebP(src), type: "image/webp", "data-qa": qaAttributes.desktopSourceCompressed })),
30
- React.createElement(ImageBase, { className: className, alt: alt, src: src, style: style, onClick: onClick, onError: () => setImgLoadingError(true) })));
30
+ React.createElement(ImageBase, { className: className, alt: alt, src: src, style: style, onClick: onClick, onError: () => setImgLoadingError(true), onLoad: onLoad })));
31
31
  };
32
32
  export default Image;