@gravity-ui/page-constructor 2.8.4 → 2.10.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 (30) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/build/cjs/blocks/Questions/Questions.js +14 -5
  3. package/build/cjs/blocks/Tabs/Tabs.js +5 -1
  4. package/build/cjs/components/AnimateBlock/AnimateBlock.d.ts +1 -0
  5. package/build/cjs/components/AnimateBlock/AnimateBlock.js +2 -2
  6. package/build/cjs/components/AnimateBlock/__tests__/AnimateBlock.test.d.ts +1 -0
  7. package/build/cjs/components/AnimateBlock/__tests__/AnimateBlock.test.js +36 -0
  8. package/build/cjs/components/Button/Button.d.ts +2 -1
  9. package/build/cjs/components/Button/Button.js +2 -2
  10. package/build/cjs/components/ButtonTabs/ButtonTabs.d.ts +1 -1
  11. package/build/cjs/components/ButtonTabs/ButtonTabs.js +3 -3
  12. package/build/cjs/components/HTML/HTML.d.ts +3 -1
  13. package/build/cjs/components/HTML/HTML.js +2 -1
  14. package/build/cjs/components/YFMWrapper/YFMWrapper.d.ts +2 -1
  15. package/build/cjs/components/YFMWrapper/YFMWrapper.js +1 -1
  16. package/build/esm/blocks/Questions/Questions.js +14 -5
  17. package/build/esm/blocks/Tabs/Tabs.js +5 -1
  18. package/build/esm/components/AnimateBlock/AnimateBlock.d.ts +1 -0
  19. package/build/esm/components/AnimateBlock/AnimateBlock.js +2 -2
  20. package/build/esm/components/AnimateBlock/__tests__/AnimateBlock.test.d.ts +1 -0
  21. package/build/esm/components/AnimateBlock/__tests__/AnimateBlock.test.js +33 -0
  22. package/build/esm/components/Button/Button.d.ts +2 -1
  23. package/build/esm/components/Button/Button.js +2 -2
  24. package/build/esm/components/ButtonTabs/ButtonTabs.d.ts +1 -1
  25. package/build/esm/components/ButtonTabs/ButtonTabs.js +3 -3
  26. package/build/esm/components/HTML/HTML.d.ts +3 -1
  27. package/build/esm/components/HTML/HTML.js +2 -1
  28. package/build/esm/components/YFMWrapper/YFMWrapper.d.ts +2 -1
  29. package/build/esm/components/YFMWrapper/YFMWrapper.js +1 -1
  30. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -1,5 +1,19 @@
1
1
  # Changelog
2
2
 
3
+ ## [2.10.0](https://github.com/gravity-ui/page-constructor/compare/v2.9.0...v2.10.0) (2023-04-24)
4
+
5
+
6
+ ### Features
7
+
8
+ * add scroll to the active tab ([#311](https://github.com/gravity-ui/page-constructor/issues/311)) ([a5f8576](https://github.com/gravity-ui/page-constructor/commit/a5f857640c9aa5d81859321a933fcef4913b5b76))
9
+
10
+ ## [2.9.0](https://github.com/gravity-ui/page-constructor/compare/v2.8.4...v2.9.0) (2023-04-19)
11
+
12
+
13
+ ### Features
14
+
15
+ * **QuestionBlock:** add schema.org FAQ microdata ([#308](https://github.com/gravity-ui/page-constructor/issues/308)) ([cfca14a](https://github.com/gravity-ui/page-constructor/commit/cfca14a76b458bfa21daa452cb46cb966fae9e88))
16
+
3
17
  ## [2.8.4](https://github.com/gravity-ui/page-constructor/compare/v2.8.3...v2.8.4) (2023-04-17)
4
18
 
5
19
 
@@ -8,6 +8,15 @@ const grid_1 = require("../../grid");
8
8
  const sub_blocks_1 = require("../../sub-blocks");
9
9
  const utils_1 = require("../../utils");
10
10
  const b = (0, utils_1.block)('QuestionsBlock');
11
+ const FaqMicrodataValues = {
12
+ PageType: 'https://schema.org/FAQPage',
13
+ QuestionType: 'https://schema.org/Question',
14
+ QuestionProp: 'mainEntity',
15
+ QuestionTextProp: 'name',
16
+ AnswerType: 'https://schema.org/Answer',
17
+ AnswerProp: 'acceptedAnswer',
18
+ AnswerTextProp: 'text',
19
+ };
11
20
  const QuestionsBlock = (props) => {
12
21
  const { title, text, additionalInfo, links, buttons, items } = props;
13
22
  const [opened, setOpened] = (0, react_1.useState)([0]);
@@ -21,24 +30,24 @@ const QuestionsBlock = (props) => {
21
30
  }
22
31
  setOpened(newState);
23
32
  };
24
- return (react_1.default.createElement("div", { className: b() },
33
+ return (react_1.default.createElement("div", { className: b(), itemScope: true, itemType: FaqMicrodataValues.PageType },
25
34
  react_1.default.createElement(grid_1.Row, null,
26
35
  react_1.default.createElement(grid_1.Col, { sizes: { all: 12, md: 4 } },
27
36
  react_1.default.createElement("div", { className: b('title') },
28
37
  react_1.default.createElement(sub_blocks_1.Content, { title: title, text: text, additionalInfo: additionalInfo, links: links, buttons: buttons, colSizes: { all: 12, md: 12 } }))),
29
38
  react_1.default.createElement(grid_1.Col, { sizes: { all: 12, md: 8 } }, items.map(({ title: itemTitle, text: itemText, link, listStyle = 'dash' }, index) => {
30
39
  const isOpened = opened.includes(index);
31
- return (react_1.default.createElement("div", { key: itemTitle, className: b('item') },
40
+ return (react_1.default.createElement("div", { key: itemTitle, className: b('item'), itemScope: true, itemProp: FaqMicrodataValues.QuestionProp, itemType: FaqMicrodataValues.QuestionType },
32
41
  react_1.default.createElement("h4", { className: b('item-title'), onClick: () => toggleItem(index) },
33
- react_1.default.createElement(components_1.HTML, null, itemTitle),
42
+ react_1.default.createElement(components_1.HTML, { itemProp: FaqMicrodataValues.QuestionTextProp }, itemTitle),
34
43
  react_1.default.createElement(components_1.ToggleArrow, { open: isOpened, size: 16, type: 'vertical', iconType: "navigation", className: b('arrow') })),
35
44
  react_1.default.createElement(components_1.Foldable, { isOpened: isOpened },
36
- react_1.default.createElement("div", { className: b('text') },
45
+ react_1.default.createElement("div", { className: b('text'), itemScope: true, itemProp: FaqMicrodataValues.AnswerProp, itemType: FaqMicrodataValues.AnswerType },
37
46
  react_1.default.createElement(components_1.YFMWrapper, { content: itemText, modifiers: {
38
47
  constructor: true,
39
48
  constructorListStyle: true,
40
49
  constructorListStyleDash: listStyle === 'dash',
41
- } }),
50
+ }, itemProp: FaqMicrodataValues.QuestionTextProp }),
42
51
  link && react_1.default.createElement(Link_1.default, Object.assign({}, link, { className: b('link') }))))));
43
52
  })))));
44
53
  };
@@ -49,11 +49,15 @@ const TabsBlock = ({ items, title, description, animated, tabsColSizes, centered
49
49
  imageProps && (react_1.default.createElement(react_1.Fragment, null,
50
50
  react_1.default.createElement(FullscreenImage_1.default, Object.assign({}, imageProps, { imageClassName: b('image') })))),
51
51
  (activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.caption) && react_1.default.createElement("p", { className: b('caption') }, activeTabData.caption)));
52
+ const onSelectTab = (id, e) => {
53
+ setActiveTab(id);
54
+ e.currentTarget.scrollIntoView({ inline: 'center', behavior: 'smooth', block: 'nearest' });
55
+ };
52
56
  return (react_1.default.createElement(AnimateBlock_1.default, { className: b(), onScroll: () => setPlay(true), animate: animated },
53
57
  react_1.default.createElement(BlockHeader_1.default, { title: title, description: description, className: b('block-title', { centered: centered }) }),
54
58
  react_1.default.createElement(grid_1.Row, null,
55
59
  react_1.default.createElement(grid_1.Col, { sizes: tabsColSizes },
56
- react_1.default.createElement(ButtonTabs_1.default, { items: tabs, onSelectTab: setActiveTab, activeTab: activeTab, className: b('tabs', { centered: centered }) }))),
60
+ react_1.default.createElement(ButtonTabs_1.default, { items: tabs, onSelectTab: onSelectTab, activeTab: activeTab, className: b('tabs', { centered: centered }) }))),
57
61
  activeTabData && (react_1.default.createElement(grid_1.Row, { className: b('row', { reverse: isReverse }) },
58
62
  mediaContent,
59
63
  textContent))));
@@ -7,6 +7,7 @@ export interface AnimateBlockProps extends AnimateContextProps {
7
7
  className?: string;
8
8
  style?: CSSProperties;
9
9
  onScroll?: () => void;
10
+ qa?: string;
10
11
  }
11
12
  declare const AnimateBlock: (props: WithChildren<AnimateBlockProps>) => JSX.Element;
12
13
  export default AnimateBlock;
@@ -8,12 +8,12 @@ const utils_1 = require("../../utils");
8
8
  const b = (0, utils_1.block)('AnimateBlock');
9
9
  const AnimateBlock = (props) => {
10
10
  const { animated } = (0, react_1.useContext)(AnimateContext_1.AnimateContext);
11
- const { children, className, offset = 100, onScroll, style, animate = animated } = props;
11
+ const { children, className, offset = 100, onScroll, style, animate = animated, qa } = props;
12
12
  const [playAnimation, setPlayAnimation] = (0, react_1.useState)(false);
13
13
  const divClassName = animate
14
14
  ? b(null, `${playAnimation && 'animate'} ${className}`)
15
15
  : className;
16
- return (react_1.default.createElement("div", { className: divClassName, style: style },
16
+ return (react_1.default.createElement("div", { className: divClassName, style: style, "data-qa": qa },
17
17
  react_1.default.createElement(react_waypoint_1.Waypoint
18
18
  // trigger animation if element is above screen
19
19
  , {
@@ -0,0 +1,36 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const tslib_1 = require("tslib");
4
+ const react_1 = tslib_1.__importDefault(require("react"));
5
+ const react_2 = require("@testing-library/react");
6
+ const user_event_1 = tslib_1.__importDefault(require("@testing-library/user-event"));
7
+ const AnimateBlock_1 = tslib_1.__importDefault(require("../AnimateBlock"));
8
+ const qaId = 'animate-block';
9
+ describe('AnimateBlock', () => {
10
+ test('render AnimateBlock by default', async () => {
11
+ (0, react_2.render)(react_1.default.createElement(AnimateBlock_1.default, { qa: qaId }));
12
+ const component = react_2.screen.getByTestId(qaId);
13
+ expect(component).toBeInTheDocument();
14
+ });
15
+ test('add className', () => {
16
+ const className = 'my-class';
17
+ (0, react_2.render)(react_1.default.createElement(AnimateBlock_1.default, { qa: qaId, className: className }));
18
+ const component = react_2.screen.getByTestId(qaId);
19
+ expect(component).toHaveClass(className);
20
+ });
21
+ test('use passed style', () => {
22
+ const style = { color: 'red' };
23
+ (0, react_2.render)(react_1.default.createElement(AnimateBlock_1.default, { style: style, qa: qaId }));
24
+ const component = react_2.screen.getByTestId(qaId);
25
+ expect(component).toHaveStyle(style);
26
+ });
27
+ test('call onScroll', async () => {
28
+ const onScroll = jest.fn();
29
+ const user = user_event_1.default.setup();
30
+ (0, react_2.render)(react_1.default.createElement("div", { style: { paddingTop: 100000 } },
31
+ react_1.default.createElement(AnimateBlock_1.default, { onScroll: onScroll, qa: qaId })));
32
+ const component = react_2.screen.getByTestId(qaId);
33
+ await user.hover(component);
34
+ expect(onScroll).toHaveBeenCalledTimes(1);
35
+ });
36
+ });
@@ -1,8 +1,9 @@
1
+ import React from 'react';
1
2
  import { ButtonProps as ButtonParams } from '../../models';
2
3
  export interface ButtonProps extends Omit<ButtonParams, 'url'> {
3
4
  className?: string;
4
5
  url?: string;
5
- onClick?: () => void;
6
+ onClick?: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>;
6
7
  qa?: string;
7
8
  }
8
9
  declare const Button: (props: ButtonProps) => JSX.Element;
@@ -17,11 +17,11 @@ const Button = (props) => {
17
17
  const { className, metrikaGoals, pixelEvents, analyticsEvents, size = 'l', theme = 'normal', url, img, onClick: onClickOrigin, text } = props, rest = tslib_1.__rest(props, ["className", "metrikaGoals", "pixelEvents", "analyticsEvents", "size", "theme", "url", "img", "onClick", "text"]);
18
18
  const defaultImgPosition = 'left';
19
19
  const handleAnalytics = (0, hooks_1.useAnalytics)(models_1.DefaultEventNames.Button, url);
20
- const onClick = (0, react_1.useCallback)(() => {
20
+ const onClick = (0, react_1.useCallback)((e) => {
21
21
  handleMetrika({ metrikaGoals, pixelEvents });
22
22
  handleAnalytics(analyticsEvents);
23
23
  if (onClickOrigin) {
24
- onClickOrigin();
24
+ onClickOrigin(e);
25
25
  }
26
26
  }, [handleMetrika, metrikaGoals, pixelEvents, handleAnalytics, analyticsEvents, onClickOrigin]);
27
27
  const buttonImg = img instanceof Object
@@ -9,7 +9,7 @@ export interface ButtonTabsProps {
9
9
  className?: string;
10
10
  items: ButtonTabsItemProps[];
11
11
  activeTab?: string | null;
12
- onSelectTab?: (tabId: string | null) => void;
12
+ onSelectTab?: (tabId: string | null, e: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => void;
13
13
  tabSize?: ButtonSize;
14
14
  qa?: string;
15
15
  }
@@ -12,11 +12,11 @@ const ButtonTabs = ({ className, items, activeTab, onSelectTab, tabSize = 'l', q
12
12
  }
13
13
  return items[0].id;
14
14
  }, [activeTab, items]);
15
- const handleClick = (0, react_1.useCallback)((tabId) => {
15
+ const handleClick = (0, react_1.useCallback)((tabId) => (e) => {
16
16
  if (onSelectTab) {
17
- onSelectTab(tabId);
17
+ onSelectTab(tabId, e);
18
18
  }
19
19
  }, [onSelectTab]);
20
- return (react_1.default.createElement("div", { className: b(null, className), "data-qa": qa }, items.map(({ id, title }) => (react_1.default.createElement(index_1.Button, { text: title, className: b('item', { active: id === activeTabId }), key: title, size: tabSize, onClick: () => handleClick(id) })))));
20
+ return (react_1.default.createElement("div", { className: b(null, className), "data-qa": qa }, items.map(({ id, title }) => (react_1.default.createElement(index_1.Button, { text: title, className: b('item', { active: id === activeTabId }), key: title, size: tabSize, onClick: handleClick(id) })))));
21
21
  };
22
22
  exports.default = ButtonTabs;
@@ -4,11 +4,13 @@ export interface HTMLProps {
4
4
  children?: string;
5
5
  block?: boolean;
6
6
  className?: string;
7
+ itemProp?: string;
7
8
  }
8
- declare const HTML: ({ children, block, className }: WithChildren<HTMLProps>) => React.DetailedReactHTMLElement<{
9
+ declare const HTML: ({ children, block, className, itemProp }: WithChildren<HTMLProps>) => React.DetailedReactHTMLElement<{
9
10
  dangerouslySetInnerHTML: {
10
11
  __html: string | (string & React.ReactElement<any, string | React.JSXElementConstructor<any>>) | (string & React.ReactFragment) | (string & React.ReactPortal);
11
12
  };
12
13
  className: string | undefined;
14
+ itemProp: string | undefined;
13
15
  }, HTMLElement> | null;
14
16
  export default HTML;
@@ -2,13 +2,14 @@
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  const tslib_1 = require("tslib");
4
4
  const react_1 = tslib_1.__importDefault(require("react"));
5
- const HTML = ({ children, block = false, className }) => {
5
+ const HTML = ({ children, block = false, className, itemProp }) => {
6
6
  if (!children) {
7
7
  return null;
8
8
  }
9
9
  return react_1.default.createElement(block ? 'div' : 'span', {
10
10
  dangerouslySetInnerHTML: { __html: children },
11
11
  className,
12
+ itemProp,
12
13
  });
13
14
  };
14
15
  exports.default = HTML;
@@ -3,6 +3,7 @@ export interface YFMWrapperProps {
3
3
  className?: string;
4
4
  content: string;
5
5
  modifiers?: Modifiers;
6
+ itemProp?: string;
6
7
  }
7
- declare const YFMWrapper: ({ content, modifiers, className }: YFMWrapperProps & ClassNameProps) => JSX.Element;
8
+ declare const YFMWrapper: ({ content, modifiers, className, itemProp, }: YFMWrapperProps & ClassNameProps) => JSX.Element;
8
9
  export default YFMWrapper;
@@ -8,5 +8,5 @@ const bem_cn_lite_1 = tslib_1.__importDefault(require("bem-cn-lite"));
8
8
  const snakecase_keys_1 = tslib_1.__importDefault(require("snakecase-keys"));
9
9
  const components_1 = require("../../components");
10
10
  const yfm = (0, bem_cn_lite_1.default)('yfm');
11
- const YFMWrapper = ({ content, modifiers, className }) => (react_1.default.createElement(components_1.HTML, { className: yfm(modifiers ? (0, snakecase_keys_1.default)(modifiers) : {}, className) }, content));
11
+ const YFMWrapper = ({ content, modifiers, className, itemProp, }) => (react_1.default.createElement(components_1.HTML, { className: yfm(modifiers ? (0, snakecase_keys_1.default)(modifiers) : {}, className), itemProp: itemProp }, content));
12
12
  exports.default = YFMWrapper;
@@ -6,6 +6,15 @@ import { Content } from '../../sub-blocks';
6
6
  import { block } from '../../utils';
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
+ QuestionTextProp: 'name',
14
+ AnswerType: 'https://schema.org/Answer',
15
+ AnswerProp: 'acceptedAnswer',
16
+ AnswerTextProp: 'text',
17
+ };
9
18
  const QuestionsBlock = (props) => {
10
19
  const { title, text, additionalInfo, links, buttons, items } = props;
11
20
  const [opened, setOpened] = useState([0]);
@@ -19,24 +28,24 @@ const QuestionsBlock = (props) => {
19
28
  }
20
29
  setOpened(newState);
21
30
  };
22
- return (React.createElement("div", { className: b() },
31
+ return (React.createElement("div", { className: b(), itemScope: true, itemType: FaqMicrodataValues.PageType },
23
32
  React.createElement(Row, null,
24
33
  React.createElement(Col, { sizes: { all: 12, md: 4 } },
25
34
  React.createElement("div", { className: b('title') },
26
35
  React.createElement(Content, { title: title, text: text, additionalInfo: additionalInfo, links: links, buttons: buttons, colSizes: { all: 12, md: 12 } }))),
27
36
  React.createElement(Col, { sizes: { all: 12, md: 8 } }, items.map(({ title: itemTitle, text: itemText, link, listStyle = 'dash' }, index) => {
28
37
  const isOpened = opened.includes(index);
29
- return (React.createElement("div", { key: itemTitle, className: b('item') },
38
+ return (React.createElement("div", { key: itemTitle, className: b('item'), itemScope: true, itemProp: FaqMicrodataValues.QuestionProp, itemType: FaqMicrodataValues.QuestionType },
30
39
  React.createElement("h4", { className: b('item-title'), onClick: () => toggleItem(index) },
31
- React.createElement(HTML, null, itemTitle),
40
+ React.createElement(HTML, { itemProp: FaqMicrodataValues.QuestionTextProp }, itemTitle),
32
41
  React.createElement(ToggleArrow, { open: isOpened, size: 16, type: 'vertical', iconType: "navigation", className: b('arrow') })),
33
42
  React.createElement(Foldable, { isOpened: isOpened },
34
- React.createElement("div", { className: b('text') },
43
+ React.createElement("div", { className: b('text'), itemScope: true, itemProp: FaqMicrodataValues.AnswerProp, itemType: FaqMicrodataValues.AnswerType },
35
44
  React.createElement(YFMWrapper, { content: itemText, modifiers: {
36
45
  constructor: true,
37
46
  constructorListStyle: true,
38
47
  constructorListStyleDash: listStyle === 'dash',
39
- } }),
48
+ }, itemProp: FaqMicrodataValues.QuestionTextProp }),
40
49
  link && React.createElement(Link, Object.assign({}, link, { className: b('link') }))))));
41
50
  })))));
42
51
  };
@@ -46,11 +46,15 @@ export const TabsBlock = ({ items, title, description, animated, tabsColSizes, c
46
46
  imageProps && (React.createElement(Fragment, null,
47
47
  React.createElement(FullScreenImage, Object.assign({}, imageProps, { imageClassName: b('image') })))),
48
48
  (activeTabData === null || activeTabData === void 0 ? void 0 : activeTabData.caption) && React.createElement("p", { className: b('caption') }, activeTabData.caption)));
49
+ const onSelectTab = (id, e) => {
50
+ setActiveTab(id);
51
+ e.currentTarget.scrollIntoView({ inline: 'center', behavior: 'smooth', block: 'nearest' });
52
+ };
49
53
  return (React.createElement(AnimateBlock, { className: b(), onScroll: () => setPlay(true), animate: animated },
50
54
  React.createElement(BlockHeader, { title: title, description: description, className: b('block-title', { centered: centered }) }),
51
55
  React.createElement(Row, null,
52
56
  React.createElement(Col, { sizes: tabsColSizes },
53
- React.createElement(ButtonTabs, { items: tabs, onSelectTab: setActiveTab, activeTab: activeTab, className: b('tabs', { centered: centered }) }))),
57
+ React.createElement(ButtonTabs, { items: tabs, onSelectTab: onSelectTab, activeTab: activeTab, className: b('tabs', { centered: centered }) }))),
54
58
  activeTabData && (React.createElement(Row, { className: b('row', { reverse: isReverse }) },
55
59
  mediaContent,
56
60
  textContent))));
@@ -7,6 +7,7 @@ export interface AnimateBlockProps extends AnimateContextProps {
7
7
  className?: string;
8
8
  style?: CSSProperties;
9
9
  onScroll?: () => void;
10
+ qa?: string;
10
11
  }
11
12
  declare const AnimateBlock: (props: WithChildren<AnimateBlockProps>) => JSX.Element;
12
13
  export default AnimateBlock;
@@ -5,12 +5,12 @@ import { block } from '../../utils';
5
5
  const b = block('AnimateBlock');
6
6
  const AnimateBlock = (props) => {
7
7
  const { animated } = useContext(AnimateContext);
8
- const { children, className, offset = 100, onScroll, style, animate = animated } = props;
8
+ const { children, className, offset = 100, onScroll, style, animate = animated, qa } = props;
9
9
  const [playAnimation, setPlayAnimation] = useState(false);
10
10
  const divClassName = animate
11
11
  ? b(null, `${playAnimation && 'animate'} ${className}`)
12
12
  : className;
13
- return (React.createElement("div", { className: divClassName, style: style },
13
+ return (React.createElement("div", { className: divClassName, style: style, "data-qa": qa },
14
14
  React.createElement(Waypoint
15
15
  // trigger animation if element is above screen
16
16
  , {
@@ -0,0 +1,33 @@
1
+ import React from 'react';
2
+ import { render, screen } from '@testing-library/react';
3
+ import userEvent from '@testing-library/user-event';
4
+ import AnimateBlock from '../AnimateBlock';
5
+ const qaId = 'animate-block';
6
+ describe('AnimateBlock', () => {
7
+ test('render AnimateBlock by default', async () => {
8
+ render(React.createElement(AnimateBlock, { qa: qaId }));
9
+ const component = screen.getByTestId(qaId);
10
+ expect(component).toBeInTheDocument();
11
+ });
12
+ test('add className', () => {
13
+ const className = 'my-class';
14
+ render(React.createElement(AnimateBlock, { qa: qaId, className: className }));
15
+ const component = screen.getByTestId(qaId);
16
+ expect(component).toHaveClass(className);
17
+ });
18
+ test('use passed style', () => {
19
+ const style = { color: 'red' };
20
+ render(React.createElement(AnimateBlock, { style: style, qa: qaId }));
21
+ const component = screen.getByTestId(qaId);
22
+ expect(component).toHaveStyle(style);
23
+ });
24
+ test('call onScroll', async () => {
25
+ const onScroll = jest.fn();
26
+ const user = userEvent.setup();
27
+ render(React.createElement("div", { style: { paddingTop: 100000 } },
28
+ React.createElement(AnimateBlock, { onScroll: onScroll, qa: qaId })));
29
+ const component = screen.getByTestId(qaId);
30
+ await user.hover(component);
31
+ expect(onScroll).toHaveBeenCalledTimes(1);
32
+ });
33
+ });
@@ -1,9 +1,10 @@
1
+ import React from 'react';
1
2
  import { ButtonProps as ButtonParams } from '../../models';
2
3
  import './Button.css';
3
4
  export interface ButtonProps extends Omit<ButtonParams, 'url'> {
4
5
  className?: string;
5
6
  url?: string;
6
- onClick?: () => void;
7
+ onClick?: React.MouseEventHandler<HTMLButtonElement | HTMLAnchorElement>;
7
8
  qa?: string;
8
9
  }
9
10
  declare const Button: (props: ButtonProps) => JSX.Element;
@@ -16,11 +16,11 @@ const Button = (props) => {
16
16
  const { className, metrikaGoals, pixelEvents, analyticsEvents, size = 'l', theme = 'normal', url, img, onClick: onClickOrigin, text } = props, rest = __rest(props, ["className", "metrikaGoals", "pixelEvents", "analyticsEvents", "size", "theme", "url", "img", "onClick", "text"]);
17
17
  const defaultImgPosition = 'left';
18
18
  const handleAnalytics = useAnalytics(DefaultEventNames.Button, url);
19
- const onClick = useCallback(() => {
19
+ const onClick = useCallback((e) => {
20
20
  handleMetrika({ metrikaGoals, pixelEvents });
21
21
  handleAnalytics(analyticsEvents);
22
22
  if (onClickOrigin) {
23
- onClickOrigin();
23
+ onClickOrigin(e);
24
24
  }
25
25
  }, [handleMetrika, metrikaGoals, pixelEvents, handleAnalytics, analyticsEvents, onClickOrigin]);
26
26
  const buttonImg = img instanceof Object
@@ -10,7 +10,7 @@ export interface ButtonTabsProps {
10
10
  className?: string;
11
11
  items: ButtonTabsItemProps[];
12
12
  activeTab?: string | null;
13
- onSelectTab?: (tabId: string | null) => void;
13
+ onSelectTab?: (tabId: string | null, e: React.MouseEvent<HTMLButtonElement | HTMLAnchorElement>) => void;
14
14
  tabSize?: ButtonSize;
15
15
  qa?: string;
16
16
  }
@@ -10,11 +10,11 @@ const ButtonTabs = ({ className, items, activeTab, onSelectTab, tabSize = 'l', q
10
10
  }
11
11
  return items[0].id;
12
12
  }, [activeTab, items]);
13
- const handleClick = useCallback((tabId) => {
13
+ const handleClick = useCallback((tabId) => (e) => {
14
14
  if (onSelectTab) {
15
- onSelectTab(tabId);
15
+ onSelectTab(tabId, e);
16
16
  }
17
17
  }, [onSelectTab]);
18
- return (React.createElement("div", { className: b(null, className), "data-qa": qa }, items.map(({ id, title }) => (React.createElement(Button, { text: title, className: b('item', { active: id === activeTabId }), key: title, size: tabSize, onClick: () => handleClick(id) })))));
18
+ return (React.createElement("div", { className: b(null, className), "data-qa": qa }, items.map(({ id, title }) => (React.createElement(Button, { text: title, className: b('item', { active: id === activeTabId }), key: title, size: tabSize, onClick: handleClick(id) })))));
19
19
  };
20
20
  export default ButtonTabs;
@@ -4,11 +4,13 @@ export interface HTMLProps {
4
4
  children?: string;
5
5
  block?: boolean;
6
6
  className?: string;
7
+ itemProp?: string;
7
8
  }
8
- declare const HTML: ({ children, block, className }: WithChildren<HTMLProps>) => React.DetailedReactHTMLElement<{
9
+ declare const HTML: ({ children, block, className, itemProp }: WithChildren<HTMLProps>) => React.DetailedReactHTMLElement<{
9
10
  dangerouslySetInnerHTML: {
10
11
  __html: string | (string & React.ReactElement<any, string | React.JSXElementConstructor<any>>) | (string & React.ReactFragment) | (string & React.ReactPortal);
11
12
  };
12
13
  className: string | undefined;
14
+ itemProp: string | undefined;
13
15
  }, HTMLElement> | null;
14
16
  export default HTML;
@@ -1,11 +1,12 @@
1
1
  import React from 'react';
2
- const HTML = ({ children, block = false, className }) => {
2
+ const HTML = ({ children, block = false, className, itemProp }) => {
3
3
  if (!children) {
4
4
  return null;
5
5
  }
6
6
  return React.createElement(block ? 'div' : 'span', {
7
7
  dangerouslySetInnerHTML: { __html: children },
8
8
  className,
9
+ itemProp,
9
10
  });
10
11
  };
11
12
  export default HTML;
@@ -3,6 +3,7 @@ export interface YFMWrapperProps {
3
3
  className?: string;
4
4
  content: string;
5
5
  modifiers?: Modifiers;
6
+ itemProp?: string;
6
7
  }
7
- declare const YFMWrapper: ({ content, modifiers, className }: YFMWrapperProps & ClassNameProps) => JSX.Element;
8
+ declare const YFMWrapper: ({ content, modifiers, className, itemProp, }: YFMWrapperProps & ClassNameProps) => JSX.Element;
8
9
  export default YFMWrapper;
@@ -5,5 +5,5 @@ import block from 'bem-cn-lite';
5
5
  import toSnakeCase from 'snakecase-keys';
6
6
  import { HTML } from '../../components';
7
7
  const yfm = block('yfm');
8
- const YFMWrapper = ({ content, modifiers, className }) => (React.createElement(HTML, { className: yfm(modifiers ? toSnakeCase(modifiers) : {}, className) }, content));
8
+ const YFMWrapper = ({ content, modifiers, className, itemProp, }) => (React.createElement(HTML, { className: yfm(modifiers ? toSnakeCase(modifiers) : {}, className), itemProp: itemProp }, content));
9
9
  export default YFMWrapper;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gravity-ui/page-constructor",
3
- "version": "2.8.4",
3
+ "version": "2.10.0",
4
4
  "description": "Gravity UI Page Constructor",
5
5
  "license": "MIT",
6
6
  "repository": {