@gravity-ui/page-constructor 4.31.1 → 4.34.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.
Files changed (105) hide show
  1. package/build/cjs/blocks/Form/Form.css +136 -0
  2. package/build/cjs/blocks/Form/Form.d.ts +4 -0
  3. package/build/cjs/blocks/Form/Form.js +59 -0
  4. package/build/cjs/blocks/Form/InnerForm/InnerForm.d.ts +9 -0
  5. package/build/cjs/blocks/Form/InnerForm/InnerForm.js +28 -0
  6. package/build/cjs/blocks/Form/schema.d.ts +202 -0
  7. package/build/cjs/blocks/Form/schema.js +44 -0
  8. package/build/cjs/blocks/Header/Header.js +6 -2
  9. package/build/cjs/blocks/Tabs/Tabs.js +8 -1
  10. package/build/cjs/blocks/index.d.ts +1 -0
  11. package/build/cjs/blocks/index.js +3 -1
  12. package/build/cjs/components/BackLink/BackLink.d.ts +3 -2
  13. package/build/cjs/components/BackLink/BackLink.js +2 -2
  14. package/build/cjs/components/Button/Button.d.ts +0 -1
  15. package/build/cjs/components/DefaultVideo/DefaultVideo.css +5 -0
  16. package/build/cjs/components/DefaultVideo/DefaultVideo.d.ts +11 -0
  17. package/build/cjs/components/DefaultVideo/DefaultVideo.js +60 -0
  18. package/build/cjs/components/FileLink/FileLink.js +2 -2
  19. package/build/cjs/components/FullscreenImage/FullscreenImage.d.ts +2 -1
  20. package/build/cjs/components/FullscreenImage/FullscreenImage.js +2 -2
  21. package/build/cjs/components/Image/Image.js +2 -2
  22. package/build/cjs/components/Link/Link.js +4 -4
  23. package/build/cjs/components/Media/Video/Video.css +0 -5
  24. package/build/cjs/components/Media/Video/Video.js +3 -7
  25. package/build/cjs/components/Title/Title.d.ts +2 -1
  26. package/build/cjs/components/Title/Title.js +2 -2
  27. package/build/cjs/components/Title/TitleItem.css +3 -3
  28. package/build/cjs/components/YandexForm/YandexForm.d.ts +2 -17
  29. package/build/cjs/components/YandexForm/YandexForm.js +6 -4
  30. package/build/cjs/components/YandexForm/schema.d.ts +16 -0
  31. package/build/cjs/components/YandexForm/schema.js +13 -0
  32. package/build/cjs/constructor-items.d.ts +1 -0
  33. package/build/cjs/constructor-items.js +1 -0
  34. package/build/cjs/editor/data/templates/form-block.json +20 -0
  35. package/build/cjs/models/constructor-items/blocks.d.ts +33 -4
  36. package/build/cjs/models/constructor-items/blocks.js +13 -1
  37. package/build/cjs/models/constructor-items/common.d.ts +22 -3
  38. package/build/cjs/models/guards.d.ts +3 -1
  39. package/build/cjs/models/guards.js +9 -1
  40. package/build/cjs/schema/constants.js +2 -1
  41. package/build/cjs/schema/validators/blocks.d.ts +1 -0
  42. package/build/cjs/schema/validators/blocks.js +1 -0
  43. package/build/cjs/sub-blocks/BasicCard/BasicCard.js +5 -2
  44. package/build/cjs/sub-blocks/Content/Content.js +12 -5
  45. package/build/cjs/sub-blocks/HubspotForm/HubspotForm.css +10 -10
  46. package/build/cjs/sub-blocks/HubspotForm/schema.d.ts +22 -0
  47. package/build/cjs/sub-blocks/HubspotForm/schema.js +17 -0
  48. package/build/cjs/sub-blocks/LayoutItem/utils.d.ts +1 -0
  49. package/build/cjs/sub-blocks/Quote/Quote.css +0 -2
  50. package/build/esm/blocks/Form/Form.css +136 -0
  51. package/build/esm/blocks/Form/Form.d.ts +5 -0
  52. package/build/esm/blocks/Form/Form.js +57 -0
  53. package/build/esm/blocks/Form/InnerForm/InnerForm.d.ts +9 -0
  54. package/build/esm/blocks/Form/InnerForm/InnerForm.js +26 -0
  55. package/build/esm/blocks/Form/schema.d.ts +202 -0
  56. package/build/esm/blocks/Form/schema.js +40 -0
  57. package/build/esm/blocks/Header/Header.js +6 -2
  58. package/build/esm/blocks/Tabs/Tabs.js +8 -1
  59. package/build/esm/blocks/index.d.ts +1 -0
  60. package/build/esm/blocks/index.js +1 -0
  61. package/build/esm/components/BackLink/BackLink.d.ts +3 -2
  62. package/build/esm/components/BackLink/BackLink.js +2 -2
  63. package/build/esm/components/Button/Button.d.ts +0 -1
  64. package/build/esm/components/DefaultVideo/DefaultVideo.css +5 -0
  65. package/build/esm/components/DefaultVideo/DefaultVideo.d.ts +12 -0
  66. package/build/esm/components/DefaultVideo/DefaultVideo.js +57 -0
  67. package/build/esm/components/FileLink/FileLink.js +2 -2
  68. package/build/esm/components/FullscreenImage/FullscreenImage.d.ts +2 -1
  69. package/build/esm/components/FullscreenImage/FullscreenImage.js +2 -2
  70. package/build/esm/components/Image/Image.js +3 -2
  71. package/build/esm/components/Link/Link.js +4 -4
  72. package/build/esm/components/Media/Video/Video.css +0 -5
  73. package/build/esm/components/Media/Video/Video.js +3 -7
  74. package/build/esm/components/Title/Title.d.ts +2 -1
  75. package/build/esm/components/Title/Title.js +2 -2
  76. package/build/esm/components/Title/TitleItem.css +3 -3
  77. package/build/esm/components/YandexForm/YandexForm.d.ts +2 -17
  78. package/build/esm/components/YandexForm/YandexForm.js +5 -3
  79. package/build/esm/components/YandexForm/schema.d.ts +16 -0
  80. package/build/esm/components/YandexForm/schema.js +10 -0
  81. package/build/esm/constructor-items.d.ts +1 -0
  82. package/build/esm/constructor-items.js +2 -1
  83. package/build/esm/editor/data/templates/form-block.json +20 -0
  84. package/build/esm/models/constructor-items/blocks.d.ts +33 -4
  85. package/build/esm/models/constructor-items/blocks.js +12 -0
  86. package/build/esm/models/constructor-items/common.d.ts +22 -3
  87. package/build/esm/models/guards.d.ts +3 -1
  88. package/build/esm/models/guards.js +7 -1
  89. package/build/esm/schema/constants.js +3 -2
  90. package/build/esm/schema/validators/blocks.d.ts +1 -0
  91. package/build/esm/schema/validators/blocks.js +1 -0
  92. package/build/esm/sub-blocks/BasicCard/BasicCard.js +5 -2
  93. package/build/esm/sub-blocks/Content/Content.js +12 -5
  94. package/build/esm/sub-blocks/HubspotForm/HubspotForm.css +10 -10
  95. package/build/esm/sub-blocks/HubspotForm/schema.d.ts +22 -0
  96. package/build/esm/sub-blocks/HubspotForm/schema.js +14 -0
  97. package/build/esm/sub-blocks/LayoutItem/utils.d.ts +1 -0
  98. package/build/esm/sub-blocks/Quote/Quote.css +0 -2
  99. package/package.json +1 -1
  100. package/server/models/constructor-items/blocks.d.ts +33 -4
  101. package/server/models/constructor-items/blocks.js +13 -1
  102. package/server/models/constructor-items/common.d.ts +22 -3
  103. package/server/models/guards.d.ts +3 -1
  104. package/server/models/guards.js +9 -1
  105. package/widget/index.js +1 -1
@@ -1,4 +1,5 @@
1
1
  import React, { Fragment, useRef, useState } from 'react';
2
+ import { useUniqId } from '@gravity-ui/uikit';
2
3
  import AnimateBlock from '../../components/AnimateBlock/AnimateBlock';
3
4
  import ButtonTabs from '../../components/ButtonTabs/ButtonTabs';
4
5
  import FullscreenImage from '../../components/FullscreenImage/FullscreenImage';
@@ -23,10 +24,16 @@ export const TabsBlock = ({ items, title, description, animated, tabsColSizes, c
23
24
  const ref = useRef(null);
24
25
  const mediaWidth = (_a = ref === null || ref === void 0 ? void 0 : ref.current) === null || _a === void 0 ? void 0 : _a.offsetWidth;
25
26
  const mediaHeight = mediaWidth && getHeight(mediaWidth);
27
+ const captionId = useUniqId();
26
28
  let imageProps;
27
29
  if (activeTabData) {
28
30
  const themedImage = getThemedValue(activeTabData.image, theme);
29
31
  imageProps = themedImage && getMediaImage(themedImage);
32
+ if (activeTabData.caption && imageProps) {
33
+ Object.assign(imageProps, {
34
+ 'aria-describedby': captionId,
35
+ });
36
+ }
30
37
  }
31
38
  const showMedia = Boolean((activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.media) || imageProps);
32
39
  const showText = Boolean(activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.text);
@@ -45,7 +52,7 @@ export const TabsBlock = ({ items, title, description, animated, tabsColSizes, c
45
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 })))),
46
53
  imageProps && (React.createElement(Fragment, null,
47
54
  React.createElement(FullscreenImage, Object.assign({}, imageProps, { imageClassName: b('image') })))),
48
- (activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.caption) && React.createElement("p", { className: b('caption') }, activeTabData.caption)));
55
+ (activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.caption) && (React.createElement("p", { className: b('caption'), id: captionId }, activeTabData.caption))));
49
56
  const onSelectTab = (id, e) => {
50
57
  setActiveTab(id);
51
58
  e.currentTarget.scrollIntoView({ inline: 'center', behavior: 'smooth', block: 'nearest' });
@@ -16,3 +16,4 @@ export { default as CardLayoutBlock } from './CardLayout/CardLayout';
16
16
  export { default as ContentLayoutBlock } from './ContentLayout/ContentLayout';
17
17
  export { default as ShareBlock } from './Share/Share';
18
18
  export { default as FilterBlock } from './FilterBlock/FilterBlock';
19
+ export { default as FormBlock } from './Form/Form';
@@ -16,3 +16,4 @@ export { default as CardLayoutBlock } from './CardLayout/CardLayout';
16
16
  export { default as ContentLayoutBlock } from './ContentLayout/ContentLayout';
17
17
  export { default as ShareBlock } from './Share/Share';
18
18
  export { default as FilterBlock } from './FilterBlock/FilterBlock';
19
+ export { default as FormBlock } from './Form/Form';
@@ -1,8 +1,8 @@
1
- import { ReactNode } from 'react';
1
+ import { HTMLProps, ReactNode } from 'react';
2
2
  import { ButtonSize } from '@gravity-ui/uikit';
3
3
  import { Tabbable } from '../../models';
4
4
  export type Theme = 'default' | 'special';
5
- export interface BackLinkProps extends Tabbable {
5
+ export interface BackLinkProps<T = HTMLElement> extends Tabbable {
6
6
  url: string;
7
7
  title: ReactNode;
8
8
  theme?: Theme;
@@ -10,5 +10,6 @@ export interface BackLinkProps extends Tabbable {
10
10
  className?: string;
11
11
  shouldHandleBackAction?: boolean;
12
12
  onClick?: () => void;
13
+ extraProps?: HTMLProps<T>;
13
14
  }
14
15
  export default function BackLink(props: BackLinkProps): JSX.Element;
@@ -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, tabIndex, } = props;
9
+ const { url, title, theme = 'default', size = 'l', className, shouldHandleBackAction = false, onClick, tabIndex, extraProps, } = 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, tabIndex: tabIndex },
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, extraProps: extraProps },
27
27
  React.createElement(Icon, { data: ArrowSidebar, size: 24 }),
28
28
  React.createElement("span", null, title)));
29
29
  }
@@ -4,7 +4,6 @@ import './Button.css';
4
4
  export interface ButtonProps extends Omit<ButtonParams, 'url'>, QAProps {
5
5
  className?: string;
6
6
  url?: string;
7
- urlTitle?: string;
8
7
  onClick?: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>;
9
8
  }
10
9
  declare const Button: (props: ButtonProps) => JSX.Element;
@@ -0,0 +1,5 @@
1
+ .pc-default-video {
2
+ width: 100%;
3
+ display: flex;
4
+ align-items: center;
5
+ }
@@ -0,0 +1,12 @@
1
+ import React from 'react';
2
+ import { MediaVideoProps } from '../../models';
3
+ import './DefaultVideo.css';
4
+ type DefaultVideoRefType = HTMLVideoElement | undefined;
5
+ interface DefaultVideoProps {
6
+ video: MediaVideoProps;
7
+ qa?: string;
8
+ customBarControlsClassName?: string;
9
+ className?: string;
10
+ }
11
+ export declare const DefaultVideo: React.ForwardRefExoticComponent<DefaultVideoProps & React.RefAttributes<DefaultVideoRefType>>;
12
+ export {};
@@ -0,0 +1,57 @@
1
+ import React, { Fragment, useCallback, useImperativeHandle, useRef, useState } from 'react';
2
+ import { CustomControlsType, MediaVideoControlsType } from '../../models';
3
+ import { block } from '../../utils';
4
+ import { getVideoTypesWithPriority } from '../Media/Video/utils';
5
+ import CustomBarControls from '../ReactPlayer/CustomBarControls';
6
+ import './DefaultVideo.css';
7
+ const b = block('default-video');
8
+ export const DefaultVideo = React.forwardRef((props, ref) => {
9
+ const { video, qa, customBarControlsClassName } = props;
10
+ const { controls, customControlsOptions, muted: initiallyMuted } = video;
11
+ const { muteButtonShown, positioning, type: customControlsType, } = customControlsOptions || {};
12
+ const [isPaused, setIsPaused] = useState(false);
13
+ const [isMuted, setIsMuted] = useState(initiallyMuted);
14
+ const videoRef = useRef(null);
15
+ // one may not use this hook and work with `ref` variable only, but
16
+ // in this case one should support both function type and object type,
17
+ // according to ForwardedRef type.
18
+ // Currently used way with extra ref and useImperativeHandle is more
19
+ // convenient and allows us to work with object typed ref only,
20
+ // avoiding typeof ref === 'function' statements
21
+ useImperativeHandle(ref, () => {
22
+ if (!(videoRef === null || videoRef === void 0 ? void 0 : videoRef.current)) {
23
+ return undefined;
24
+ }
25
+ return videoRef.current;
26
+ }, [videoRef]);
27
+ const onPlayToggle = useCallback(() => {
28
+ setIsPaused((value) => {
29
+ var _a, _b;
30
+ if (value) {
31
+ (_a = videoRef === null || videoRef === void 0 ? void 0 : videoRef.current) === null || _a === void 0 ? void 0 : _a.play();
32
+ }
33
+ else {
34
+ (_b = videoRef === null || videoRef === void 0 ? void 0 : videoRef.current) === null || _b === void 0 ? void 0 : _b.pause();
35
+ }
36
+ return !value;
37
+ });
38
+ }, [videoRef]);
39
+ const onMuteToggle = useCallback(() => {
40
+ setIsMuted((value) => !value);
41
+ }, []);
42
+ const onClick = useCallback(() => {
43
+ if (customControlsType === CustomControlsType.WithPlayPauseButton) {
44
+ onPlayToggle();
45
+ }
46
+ }, [onPlayToggle, customControlsType]);
47
+ return (React.createElement(Fragment, null,
48
+ React.createElement("video", { disablePictureInPicture: true, playsInline: true,
49
+ // @ts-ignore
50
+ // eslint-disable-next-line react/no-unknown-property
51
+ pip: "false", className: b(), ref: videoRef, preload: "metadata", muted: isMuted, "aria-label": video.ariaLabel, onClick: onClick }, getVideoTypesWithPriority(video.src).map(({ src, type }, index) => (React.createElement("source", { key: index, src: src, type: type, "data-qa": qa })))),
52
+ controls === MediaVideoControlsType.Custom && (React.createElement(CustomBarControls, { className: customBarControlsClassName, type: customControlsType, isPaused: isPaused, onPlayClick: onPlayToggle, muteButtonShown: muteButtonShown, shown: true, positioning: positioning, mute: {
53
+ isMuted: Boolean(isMuted),
54
+ changeMute: onMuteToggle,
55
+ } }))));
56
+ });
57
+ DefaultVideo.displayName = 'DefaultVideo';
@@ -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, tabIndex, urlTitle, } = props;
40
+ const { href, text, type = 'vertical', textSize = 'm', className, theme = 'default', onClick, tabIndex, urlTitle, extraProps, } = 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, onClick: onClick, tabIndex: tabIndex, title: urlTitle }, getLinkProps(href, hostname)), text))));
47
+ React.createElement("a", Object.assign({ href: href, onClick: onClick, tabIndex: tabIndex, title: urlTitle }, getLinkProps(href, hostname), extraProps), text))));
48
48
  };
49
49
  export default FileLink;
@@ -1,10 +1,11 @@
1
- import { CSSProperties } from 'react';
1
+ import { CSSProperties, HTMLProps } from 'react';
2
2
  import { ImageProps } from '../Image/Image';
3
3
  import './FullscreenImage.css';
4
4
  export interface FullscreenImageProps extends ImageProps {
5
5
  imageClassName?: string;
6
6
  modalImageClass?: string;
7
7
  imageStyle?: CSSProperties;
8
+ extraProps?: HTMLProps<HTMLDivElement>;
8
9
  }
9
10
  declare const FullscreenImage: (props: FullscreenImageProps) => JSX.Element;
10
11
  export default FullscreenImage;
@@ -9,11 +9,11 @@ const b = block('fullscreen-image');
9
9
  const FULL_SCREEN_ICON_SIZE = 18;
10
10
  const CLOSE_ICON_SIZE = 30;
11
11
  const FullscreenImage = (props) => {
12
- const { imageClassName, modalImageClass, imageStyle, alt = i18n('img-alt') } = props;
12
+ const { imageClassName, modalImageClass, imageStyle, alt = i18n('img-alt'), extraProps } = props;
13
13
  const [isOpened, setIsOpened] = useState(false);
14
14
  const openModal = () => setIsOpened(true);
15
15
  const closeModal = () => setIsOpened(false);
16
- return (React.createElement("div", { className: b() },
16
+ return (React.createElement("div", Object.assign({ className: b() }, extraProps),
17
17
  React.createElement("div", { className: b('image-wrapper') },
18
18
  React.createElement(Image, Object.assign({}, props, { alt: alt, className: b('image', imageClassName), onClick: openModal, style: imageStyle })),
19
19
  React.createElement("button", { className: b('icon-wrapper'), onClick: openModal },
@@ -1,3 +1,4 @@
1
+ import { __rest } from "tslib";
1
2
  import React, { Fragment, useContext, useState } from 'react';
2
3
  import { BREAKPOINTS } from '../../constants';
3
4
  import { ProjectSettingsContext } from '../../context/projectSettingsContext';
@@ -12,7 +13,7 @@ const DeviceSpecificFragment = ({ disableWebp, src, breakpoint, qa, }) => (React
12
13
  React.createElement("source", { srcSet: src, media: `(max-width: ${breakpoint}px)`, "data-qa": qa })));
13
14
  const Image = (props) => {
14
15
  const projectSettings = useContext(ProjectSettingsContext);
15
- const { src: imageSrc, alt, disableCompress, tablet, desktop, mobile, style, className, onClick, containerClassName, qa, } = props;
16
+ const { src: imageSrc, alt, disableCompress, tablet, desktop, mobile, style, className, onClick, containerClassName, qa } = props, rest = __rest(props, ["src", "alt", "disableCompress", "tablet", "desktop", "mobile", "style", "className", "onClick", "containerClassName", "qa"]);
16
17
  const [imgLoadingError, setImgLoadingError] = useState(false);
17
18
  const src = imageSrc || desktop;
18
19
  if (!src) {
@@ -27,6 +28,6 @@ const Image = (props) => {
27
28
  mobile && (React.createElement(DeviceSpecificFragment, { src: mobile, disableWebp: disableWebp, breakpoint: BREAKPOINTS.sm, qa: qaAttributes.mobileSource })),
28
29
  tablet && (React.createElement(DeviceSpecificFragment, { src: tablet, disableWebp: disableWebp, breakpoint: BREAKPOINTS.md, qa: qaAttributes.tabletSource })),
29
30
  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) })));
31
+ React.createElement(ImageBase, Object.assign({ className: className, alt: alt, src: src, style: style, onClick: onClick, onError: () => setImgLoadingError(true) }, rest))));
31
32
  };
32
33
  export default Image;
@@ -26,7 +26,7 @@ function getArrowSize(size) {
26
26
  }
27
27
  }
28
28
  const LinkBlock = (props) => {
29
- const { text, url, arrow, metrikaGoals, pixelEvents, analyticsEvents, theme = 'file-link', colorTheme = 'light', textSize = 'm', className, target, children, tabIndex, qa, urlTitle, } = props;
29
+ const { text, url, arrow, metrikaGoals, pixelEvents, analyticsEvents, theme = 'file-link', colorTheme = 'light', textSize = 'm', className, target, children, tabIndex, qa, urlTitle, extraProps, } = props;
30
30
  const qaAttributes = getQaAttrubutes(qa, ['normal']);
31
31
  const handleMetrika = useMetrika();
32
32
  const handleAnalytics = useAnalytics(DefaultEventNames.Link, url);
@@ -41,14 +41,14 @@ const LinkBlock = (props) => {
41
41
  const getLinkByType = () => {
42
42
  switch (theme) {
43
43
  case 'back':
44
- return (React.createElement(BackLink, { title: children || text, url: href, onClick: onClick, tabIndex: tabIndex }));
44
+ return (React.createElement(BackLink, { title: children || text, url: href, onClick: onClick, tabIndex: tabIndex, extraProps: extraProps }));
45
45
  case 'file-link':
46
46
  case 'underline':
47
- return (React.createElement(FileLink, { text: children || text, href: href, type: "horizontal", textSize: textSize, onClick: onClick, tabIndex: tabIndex }));
47
+ return (React.createElement(FileLink, { text: children || text, href: href, type: "horizontal", textSize: textSize, onClick: onClick, tabIndex: tabIndex, extraProps: extraProps }));
48
48
  case 'normal': {
49
49
  const linkProps = getLinkProps(url, hostname, target);
50
50
  const content = children || text;
51
- return (React.createElement("a", Object.assign({ className: b('link', { theme: colorTheme, 'has-arrow': arrow }), href: href, onClick: onClick, tabIndex: tabIndex, title: urlTitle }, linkProps, { "data-qa": qaAttributes.normal }), arrow ? (React.createElement(Fragment, null,
51
+ return (React.createElement("a", Object.assign({ className: b('link', { theme: colorTheme, 'has-arrow': arrow }), href: href, onClick: onClick, tabIndex: tabIndex, title: urlTitle }, linkProps, { "data-qa": qaAttributes.normal }, extraProps), arrow ? (React.createElement(Fragment, null,
52
52
  React.createElement("span", { className: b('content') }, content),
53
53
  WORD_JOINER_SYM,
54
54
  React.createElement(Icon, { className: b('arrow'), data: Chevron, size: getArrowSize(textSize) }))) : (content)));
@@ -4,11 +4,6 @@ unpredictable css rules order in build */
4
4
  position: relative;
5
5
  overflow: hidden;
6
6
  }
7
- .pc-media-component-video__item {
8
- width: 100%;
9
- display: flex;
10
- align-items: center;
11
- }
12
7
  .pc-media-component-video__react-player {
13
8
  display: flex;
14
9
  position: relative;
@@ -1,8 +1,8 @@
1
1
  import React, { useEffect, useMemo, useRef } from 'react';
2
2
  import { MediaVideoType } from '../../../models';
3
3
  import { block, getQaAttrubutes } from '../../../utils';
4
+ import { DefaultVideo } from '../../DefaultVideo/DefaultVideo';
4
5
  import ReactPlayerBlock from '../../ReactPlayer/ReactPlayer';
5
- import { getVideoTypesWithPriority } from './utils';
6
6
  import './Video.css';
7
7
  const b = block('media-component-video');
8
8
  const Video = (props) => {
@@ -45,13 +45,9 @@ const Video = (props) => {
45
45
  ]);
46
46
  const defaultVideoBlock = useMemo(() => {
47
47
  return video.src.length && !hasVideoFallback ? (React.createElement("div", { className: b('wrap', videoClassName), style: { height }, "data-qa": qaAttributes.default },
48
- React.createElement("video", { disablePictureInPicture: true, playsInline: true,
49
- // @ts-ignore
50
- // eslint-disable-next-line react/no-unknown-property
51
- 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, "data-qa": qaAttributes.source })))))) : null;
48
+ React.createElement(DefaultVideo, { ref: ref, video: video, qa: qaAttributes.source }))) : null;
52
49
  }, [
53
- video.src,
54
- video.ariaLabel,
50
+ video,
55
51
  hasVideoFallback,
56
52
  videoClassName,
57
53
  height,
@@ -3,6 +3,7 @@ import { ClassNameProps, TitleProps as TitleParams } from '../../models';
3
3
  import './Title.css';
4
4
  export interface TitleProps extends TitleParams {
5
5
  colSizes?: GridColumnSizesType;
6
+ id?: string;
6
7
  }
7
- declare const Title: ({ title, subtitle, className, colSizes, }: TitleProps & ClassNameProps) => JSX.Element | null;
8
+ declare const Title: ({ title, subtitle, className, colSizes, id, }: TitleProps & ClassNameProps) => JSX.Element | null;
8
9
  export default Title;
@@ -6,12 +6,12 @@ import YFMWrapper from '../YFMWrapper/YFMWrapper';
6
6
  import TitleItem from './TitleItem';
7
7
  import './Title.css';
8
8
  const b = block('title');
9
- const Title = ({ title, subtitle, className, colSizes = { all: 12, sm: 8 }, }) => {
9
+ const Title = ({ title, subtitle, className, colSizes = { all: 12, sm: 8 }, id, }) => {
10
10
  if (!title && !subtitle) {
11
11
  return null;
12
12
  }
13
13
  const _a = !title || typeof title === 'string' ? { text: title } : title, { text } = _a, titleProps = __rest(_a, ["text"]);
14
- return (React.createElement("div", { className: b(null, className) },
14
+ return (React.createElement("div", { className: b(null, className), id: id },
15
15
  text && (React.createElement(Col, { reset: true, sizes: colSizes },
16
16
  React.createElement(TitleItem, Object.assign({ text: text }, titleProps)))),
17
17
  subtitle && (React.createElement(Col, { reset: true, sizes: colSizes },
@@ -50,13 +50,13 @@ unpredictable css rules order in build */
50
50
  }
51
51
  }
52
52
  .pc-title-item__arrow {
53
- margin-top: 10px;
53
+ margin-top: 9px;
54
54
  }
55
55
  .pc-title-item__arrow_size_xs {
56
- margin-top: 7px;
56
+ margin-top: 6px;
57
57
  }
58
58
  .pc-title-item__arrow_size_s {
59
- margin-top: 5px;
59
+ margin-top: 4px;
60
60
  }
61
61
  .pc-title-item__link {
62
62
  color: inherit;
@@ -1,20 +1,5 @@
1
- import { PixelEvent } from '../../models';
2
- import { AnalyticsEventsBase } from '../../models/common';
1
+ import { YandexFormProps } from '../../models';
3
2
  export declare const YANDEX_FORM_ORIGIN = "https://forms.yandex.ru";
4
- export interface YandexFormProps extends AnalyticsEventsBase {
5
- id: number | string;
6
- containerId?: string;
7
- theme?: string;
8
- className?: string;
9
- headerHeight?: number;
10
- customFormOrigin?: string;
11
- params?: {
12
- [key: string]: string;
13
- };
14
- onSubmit?: () => void;
15
- onLoad?: () => void;
16
- metrikaGoals?: string | string[];
17
- pixelEvents?: string | string[] | PixelEvent | PixelEvent[];
18
- }
3
+ export declare const YANDEX_FORM_SECTION = "surveys";
19
4
  declare const YandexForm: (props: YandexFormProps) => JSX.Element;
20
5
  export default YandexForm;
@@ -7,13 +7,15 @@ import { DefaultEventNames } from '../../models/common';
7
7
  import { block } from '../../utils';
8
8
  import { HEADER_HEIGHT } from '../constants';
9
9
  export const YANDEX_FORM_ORIGIN = 'https://forms.yandex.ru';
10
+ export const YANDEX_FORM_SECTION = 'surveys';
10
11
  const CONTAINER_ID = 'pc-yandex-form-container';
11
12
  const b = block('yandex-form');
12
13
  const YandexForm = (props) => {
13
- const { onLoad, id, params, className, theme, containerId = CONTAINER_ID, headerHeight = HEADER_HEIGHT, onSubmit, metrikaGoals, pixelEvents, analyticsEvents, customFormOrigin, } = props;
14
+ const { onLoad, id, params, className, theme, containerId = CONTAINER_ID, headerHeight = HEADER_HEIGHT, onSubmit, metrikaGoals, pixelEvents, analyticsEvents, customFormOrigin, customFormSection, } = props;
14
15
  const formContainerRef = useRef(null);
15
16
  const iframeRef = useRef();
16
17
  const yaFormOrigin = customFormOrigin || YANDEX_FORM_ORIGIN;
18
+ const yaFormSection = customFormSection || YANDEX_FORM_SECTION;
17
19
  const handleMetrika = useMetrika();
18
20
  const handleAnalytics = useAnalytics(DefaultEventNames.YandexFormSubmit);
19
21
  const isMobile = useContext(MobileContext);
@@ -35,7 +37,7 @@ const YandexForm = (props) => {
35
37
  queryParams.set(param, params[param]);
36
38
  });
37
39
  }
38
- const src = `${yaFormOrigin}/surveys/${id}/?${queryParams}`;
40
+ const src = `${yaFormOrigin}/${yaFormSection}/${id}/?${queryParams}`;
39
41
  if (iframeRef.current) {
40
42
  iframeRef.current.src = src;
41
43
  }
@@ -50,7 +52,7 @@ const YandexForm = (props) => {
50
52
  iframeRef.current.width = '100%';
51
53
  container.appendChild(iframeRef.current);
52
54
  }
53
- }, [locale.lang, theme, isMobile, yaFormOrigin, id, containerId, params]);
55
+ }, [locale.lang, theme, isMobile, yaFormOrigin, yaFormSection, id, containerId, params]);
54
56
  const handleSubmit = useCallback(() => {
55
57
  if (formContainerRef && formContainerRef.current) {
56
58
  const { top } = formContainerRef.current.getBoundingClientRect();
@@ -0,0 +1,16 @@
1
+ export declare const YandexFormProps: {
2
+ type: string;
3
+ required: string[];
4
+ properties: {
5
+ id: {
6
+ type: string;
7
+ };
8
+ containerId: {
9
+ type: string;
10
+ };
11
+ type: {};
12
+ when: {
13
+ type: string;
14
+ };
15
+ };
16
+ };
@@ -0,0 +1,10 @@
1
+ import { BaseProps } from '../../schema/validators/common';
2
+ export const YandexFormProps = {
3
+ type: 'object',
4
+ required: ['id'],
5
+ properties: Object.assign(Object.assign({}, BaseProps), { id: {
6
+ type: 'string',
7
+ }, containerId: {
8
+ type: 'string',
9
+ } }),
10
+ };
@@ -17,6 +17,7 @@ export declare const blockMap: {
17
17
  "share-block": ({ items, title }: import("./models").ShareBlockProps) => JSX.Element;
18
18
  "map-block": ({ map, ...props }: import("./models").MapBlockProps) => JSX.Element;
19
19
  "filter-block": import("react").FC<import("./models").FilterBlockProps>;
20
+ "form-block": import("react").FC<import("./models").FormBlockProps>;
20
21
  };
21
22
  export declare const subBlockMap: {
22
23
  divider: ({ size, border }: import("./models").DividerProps) => JSX.Element;
@@ -1,4 +1,4 @@
1
- import { BannerBlock, CardLayoutBlock, CompaniesBlock, ContentLayoutBlock, ExtendedFeaturesBlock, FilterBlock, HeaderBlock, HeaderSliderBlock, IconsBlock, InfoBlock, MapBlock, MediaBlock, PromoFeaturesBlock, QuestionsBlock, ShareBlock, SliderBlock, TableBlock, TabsBlock, } from './blocks';
1
+ import { BannerBlock, CardLayoutBlock, CompaniesBlock, ContentLayoutBlock, ExtendedFeaturesBlock, FilterBlock, FormBlock, HeaderBlock, HeaderSliderBlock, IconsBlock, InfoBlock, MapBlock, MediaBlock, PromoFeaturesBlock, QuestionsBlock, ShareBlock, SliderBlock, TableBlock, TabsBlock, } from './blocks';
2
2
  import { BlockType, NavigationItemType, SubBlockType } from './models';
3
3
  import { GithubButton, NavigationButton, NavigationDropdown, NavigationLink, } from './navigation/components/NavigationItem';
4
4
  import SocialIcon from './navigation/components/SocialIcon/SocialIcon';
@@ -22,6 +22,7 @@ export const blockMap = {
22
22
  [BlockType.ShareBlock]: ShareBlock,
23
23
  [BlockType.MapBlock]: MapBlock,
24
24
  [BlockType.FilterBlock]: FilterBlock,
25
+ [BlockType.FormBlock]: FormBlock,
25
26
  };
26
27
  export const subBlockMap = {
27
28
  [SubBlockType.Divider]: Divider,
@@ -0,0 +1,20 @@
1
+ {
2
+ "template": {
3
+ "type": "form-block",
4
+ "formData": {
5
+ "yandex": {
6
+ "hash": "hashString",
7
+ "title": ""
8
+ }
9
+ },
10
+ "direction": "center",
11
+ "textContent": {
12
+ "title": "Lorem ipsum dolor sit amet, consectetur adipiscing elit",
13
+ "text": "Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat."
14
+ },
15
+ "image": {
16
+ "src": "https://storage.yandexcloud.net/cloud-www-assets/constructor/storybook/images/img-mini_4-12_light.png"
17
+ },
18
+ "backgroundColor": "#262626"
19
+ }
20
+ }
@@ -3,8 +3,8 @@ import { ButtonSize } from '@gravity-ui/uikit';
3
3
  import { GridColumnSize, GridColumnSizesType } from '../../grid/types';
4
4
  import { ThemeSupporting } from '../../utils';
5
5
  import { AnalyticsEventsBase } from '../common';
6
- import { AnchorProps, Animatable, BackgroundImageProps, ButtonProps, ContentSize, ContentTextSize, ContentTheme, FileLinkProps, HeaderBreadCrumbsProps, HeaderImageSize, HeaderOffset, HeaderWidth, ImageDeviceProps, Justify, LegendTableMarkerType, LinkProps, MapProps, MediaDirection, MediaProps, TextSize, TextTheme, ThemedImage, ThemedMediaProps, ThemedMediaVideoProps, TitleItemBaseProps, TitleItemProps } from './common';
7
- import { BannerCardProps, SubBlock, SubBlockModels } from './sub-blocks';
6
+ import { AnchorProps, Animatable, BackgroundImageProps, ButtonProps, ContentSize, ContentTextSize, ContentTheme, FileLinkProps, HeaderBreadCrumbsProps, HeaderImageSize, HeaderOffset, HeaderWidth, ImageDeviceProps, Justify, LegendTableMarkerType, LinkProps, MapProps, MediaDirection, MediaProps, TextSize, TextTheme, ThemedImage, ThemedMediaProps, ThemedMediaVideoProps, TitleItemBaseProps, TitleItemProps, YandexFormProps } from './common';
7
+ import { BannerCardProps, HubspotFormProps, SubBlock, SubBlockModels } from './sub-blocks';
8
8
  export declare enum BlockType {
9
9
  PromoFeaturesBlock = "promo-features-block",
10
10
  ExtendedFeaturesBlock = "extended-features-block",
@@ -23,7 +23,8 @@ export declare enum BlockType {
23
23
  ContentLayoutBlock = "content-layout-block",
24
24
  ShareBlock = "share-block",
25
25
  MapBlock = "map-block",
26
- FilterBlock = "filter-block"
26
+ FilterBlock = "filter-block",
27
+ FormBlock = "form-block"
27
28
  }
28
29
  export declare const BlockTypes: BlockType[];
29
30
  export declare const HeaderBlockTypes: BlockType[];
@@ -274,7 +275,9 @@ export interface ContentItemProps {
274
275
  }
275
276
  export interface ContentBlockProps {
276
277
  title?: TitleItemBaseProps | string;
278
+ titleId?: string;
277
279
  text?: string;
280
+ textId?: string;
278
281
  additionalInfo?: string;
279
282
  links?: LinkProps[];
280
283
  buttons?: ButtonProps[];
@@ -295,6 +298,29 @@ export interface ShareBlockProps {
295
298
  items: PCShareSocialNetwork[];
296
299
  title?: string;
297
300
  }
301
+ export declare enum FormBlockDataTypes {
302
+ YANDEX = "yandex",
303
+ HUBSPOT = "hubspot"
304
+ }
305
+ export declare enum FormBlockDirection {
306
+ FormContent = "form-content",
307
+ ContentForm = "content-form",
308
+ Center = "center"
309
+ }
310
+ export interface FormBlockYandexData {
311
+ yandex: YandexFormProps;
312
+ }
313
+ export interface FormBlockHubspotData {
314
+ hubspot: HubspotFormProps;
315
+ }
316
+ export type FormBlockData = FormBlockYandexData | FormBlockHubspotData;
317
+ export interface FormBlockProps {
318
+ formData: FormBlockData;
319
+ title?: string;
320
+ textContent?: Omit<ContentBlockProps, 'centered' | 'colSizes' | 'size'>;
321
+ direction?: FormBlockDirection;
322
+ background?: BackgroundImageProps;
323
+ }
298
324
  export type HeaderBlockModel = {
299
325
  type: BlockType.HeaderBlock;
300
326
  } & HeaderBlockProps;
@@ -349,6 +375,9 @@ export type ContentLayoutBlockModel = {
349
375
  export type ShareBLockModel = {
350
376
  type: BlockType.ShareBlock;
351
377
  } & ShareBlockProps;
352
- type BlockModels = SliderBlockModel | ExtendedFeaturesBlockModel | PromoFeaturesBlockModel | QuestionsBlockModel | BannerBlockModel | CompaniesBlockModel | MediaBlockModel | MapBlockModel | InfoBlockModel | TableBlockModel | TabsBlockModel | HeaderBlockModel | IconsBlockModel | HeaderSliderBlockModel | CardLayoutBlockModel | ContentLayoutBlockModel | ShareBLockModel | FilterBlockModel;
378
+ export type FormBlockModel = {
379
+ type: BlockType.FormBlock;
380
+ } & FormBlockProps;
381
+ type BlockModels = SliderBlockModel | ExtendedFeaturesBlockModel | PromoFeaturesBlockModel | QuestionsBlockModel | BannerBlockModel | CompaniesBlockModel | MediaBlockModel | MapBlockModel | InfoBlockModel | TableBlockModel | TabsBlockModel | HeaderBlockModel | IconsBlockModel | HeaderSliderBlockModel | CardLayoutBlockModel | ContentLayoutBlockModel | ShareBLockModel | FilterBlockModel | FormBlockModel;
353
382
  export type Block = BlockModels & BlockBaseProps;
354
383
  export {};
@@ -18,6 +18,7 @@ export var BlockType;
18
18
  BlockType["ShareBlock"] = "share-block";
19
19
  BlockType["MapBlock"] = "map-block";
20
20
  BlockType["FilterBlock"] = "filter-block";
21
+ BlockType["FormBlock"] = "form-block";
21
22
  })(BlockType || (BlockType = {}));
22
23
  export const BlockTypes = Object.values(BlockType);
23
24
  export const HeaderBlockTypes = [BlockType.HeaderBlock, BlockType.HeaderSliderBlock];
@@ -41,3 +42,14 @@ export var PCShareSocialNetwork;
41
42
  PCShareSocialNetwork["Facebook"] = "facebook";
42
43
  PCShareSocialNetwork["LinkedIn"] = "linkedin";
43
44
  })(PCShareSocialNetwork || (PCShareSocialNetwork = {}));
45
+ export var FormBlockDataTypes;
46
+ (function (FormBlockDataTypes) {
47
+ FormBlockDataTypes["YANDEX"] = "yandex";
48
+ FormBlockDataTypes["HUBSPOT"] = "hubspot";
49
+ })(FormBlockDataTypes || (FormBlockDataTypes = {}));
50
+ export var FormBlockDirection;
51
+ (function (FormBlockDirection) {
52
+ FormBlockDirection["FormContent"] = "form-content";
53
+ FormBlockDirection["ContentForm"] = "content-form";
54
+ FormBlockDirection["Center"] = "center";
55
+ })(FormBlockDirection || (FormBlockDirection = {}));