@gravity-ui/blog-constructor 5.0.1 → 5.1.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 (66) hide show
  1. package/build/cjs/blocks/Author/Author.js +2 -2
  2. package/build/cjs/blocks/Banner/Banner.js +7 -5
  3. package/build/cjs/blocks/ColoredText/ColoredText.js +5 -4
  4. package/build/cjs/blocks/YFM/YFM.js +6 -4
  5. package/build/cjs/components/FeedHeader/components/Controls/Controls.css +5 -23
  6. package/build/cjs/components/FeedHeader/components/Controls/Controls.js +1 -1
  7. package/build/cjs/components/FeedHeader/components/Controls/customRenders.js +1 -2
  8. package/build/cjs/components/FeedHeader/components/CustomSwitcher/CustomSwitcher.css +1 -1
  9. package/build/cjs/components/Paginator/types.d.ts +4 -4
  10. package/build/cjs/components/PostCard/PostCard.d.ts +3 -2
  11. package/build/cjs/components/PostCard/PostCard.js +5 -4
  12. package/build/cjs/components/PostInfo/SuggestPostInfo.d.ts +2 -2
  13. package/build/cjs/components/PostInfo/SuggestPostInfo.js +2 -1
  14. package/build/cjs/components/PostInfo/components/Date.d.ts +2 -1
  15. package/build/cjs/components/PostInfo/components/Date.js +2 -1
  16. package/build/cjs/components/Posts/Posts.js +5 -2
  17. package/build/cjs/components/Search/Search.css +13 -15
  18. package/build/cjs/components/Search/Search.d.ts +7 -1
  19. package/build/cjs/components/Search/Search.js +26 -14
  20. package/build/cjs/models/blocks.d.ts +5 -5
  21. package/build/cjs/models/common.d.ts +8 -0
  22. package/build/cjs/models/common.js +12 -2
  23. package/build/cjs/utils/cn.d.ts +2 -3
  24. package/build/cjs/utils/cn.js +4 -7
  25. package/build/cjs/utils/common.d.ts +1 -0
  26. package/build/cjs/utils/common.js +15 -2
  27. package/build/esm/blocks/Author/Author.js +2 -2
  28. package/build/esm/blocks/Banner/Banner.js +8 -6
  29. package/build/esm/blocks/ColoredText/ColoredText.js +6 -5
  30. package/build/esm/blocks/YFM/YFM.js +6 -4
  31. package/build/esm/components/FeedHeader/components/Controls/Controls.css +5 -23
  32. package/build/esm/components/FeedHeader/components/Controls/Controls.js +1 -1
  33. package/build/esm/components/FeedHeader/components/Controls/customRenders.js +1 -2
  34. package/build/esm/components/FeedHeader/components/CustomSwitcher/CustomSwitcher.css +1 -1
  35. package/build/esm/components/Paginator/types.d.ts +4 -4
  36. package/build/esm/components/PostCard/PostCard.d.ts +3 -2
  37. package/build/esm/components/PostCard/PostCard.js +5 -4
  38. package/build/esm/components/PostInfo/SuggestPostInfo.d.ts +2 -2
  39. package/build/esm/components/PostInfo/SuggestPostInfo.js +2 -1
  40. package/build/esm/components/PostInfo/components/Date.d.ts +2 -1
  41. package/build/esm/components/PostInfo/components/Date.js +2 -1
  42. package/build/esm/components/Posts/Posts.js +5 -2
  43. package/build/esm/components/Search/Search.css +13 -15
  44. package/build/esm/components/Search/Search.d.ts +7 -1
  45. package/build/esm/components/Search/Search.js +28 -16
  46. package/build/esm/models/blocks.d.ts +5 -5
  47. package/build/esm/models/common.d.ts +8 -0
  48. package/build/esm/models/common.js +11 -1
  49. package/build/esm/utils/cn.d.ts +2 -3
  50. package/build/esm/utils/cn.js +3 -4
  51. package/build/esm/utils/common.d.ts +1 -0
  52. package/build/esm/utils/common.js +13 -1
  53. package/package.json +5 -6
  54. package/server/models/blocks.d.ts +5 -5
  55. package/server/models/common.d.ts +8 -0
  56. package/server/models/common.js +12 -2
  57. package/build/cjs/components/ButtonWithIcon/ButtonWithIcon.css +0 -76
  58. package/build/cjs/components/ButtonWithIcon/ButtonWithIcon.d.ts +0 -12
  59. package/build/cjs/components/ButtonWithIcon/ButtonWithIcon.js +0 -11
  60. package/build/cjs/demo/DocsDecorator/DocsDecorator.css +0 -14
  61. package/build/cjs/internal-typings/bem-cn-lite.d.ts +0 -17
  62. package/build/esm/components/ButtonWithIcon/ButtonWithIcon.css +0 -76
  63. package/build/esm/components/ButtonWithIcon/ButtonWithIcon.d.ts +0 -13
  64. package/build/esm/components/ButtonWithIcon/ButtonWithIcon.js +0 -7
  65. package/build/esm/demo/DocsDecorator/DocsDecorator.css +0 -14
  66. package/build/esm/internal-typings/bem-cn-lite.d.ts +0 -17
@@ -11,7 +11,7 @@ const cn_1 = require("../../utils/cn");
11
11
  const b = (0, cn_1.block)('author');
12
12
  const Author = (props) => {
13
13
  var _a;
14
- const { image, paddingTop, paddingBottom, authorId } = props;
14
+ const { image, paddingTop, paddingBottom, authorId, qa } = props;
15
15
  const { post } = (0, react_1.useContext)(PostPageContext_1.PostPageContext);
16
16
  const author = (_a = post === null || post === void 0 ? void 0 : post.authors) === null || _a === void 0 ? void 0 : _a.find(({ id }) => id === authorId);
17
17
  const authorItem = (0, react_1.useMemo)(() => {
@@ -31,7 +31,7 @@ const Author = (props) => {
31
31
  return (react_1.default.createElement(Wrapper_1.Wrapper, { paddings: {
32
32
  [paddings_1.PaddingsDirections.top]: paddingTop,
33
33
  [paddings_1.PaddingsDirections.bottom]: paddingBottom,
34
- }, className: b('content') },
34
+ }, className: b('content'), qa: qa },
35
35
  react_1.default.createElement("div", { className: b('layout'), "data-qa": "blog-author-layout" },
36
36
  react_1.default.createElement(page_constructor_1.Author, { type: page_constructor_1.AuthorType.Column, author: authorItem, authorContainerClassName: b('container') }))));
37
37
  };
@@ -10,10 +10,12 @@ const paddings_1 = require("../../models/paddings");
10
10
  const cn_1 = require("../../utils/cn");
11
11
  const common_1 = require("../../utils/common");
12
12
  const b = (0, cn_1.block)('banner');
13
+ const BANNER_CUSTOM_QA_ATTRIBUTES = ['image-container'];
13
14
  const Banner = (_a) => {
14
15
  var _b;
15
- var { color, imageSize = 's', image, paddingTop, paddingBottom } = _a, content = tslib_1.__rest(_a, ["color", "imageSize", "image", "paddingTop", "paddingBottom"]);
16
+ var { color, imageSize = 's', image, paddingTop, paddingBottom, qa } = _a, content = tslib_1.__rest(_a, ["color", "imageSize", "image", "paddingTop", "paddingBottom", "qa"]);
16
17
  const contentStyle = {};
18
+ const qaAttributes = (0, common_1.getQaAttributes)(qa, BANNER_CUSTOM_QA_ATTRIBUTES);
17
19
  if (color) {
18
20
  contentStyle.backgroundColor = color;
19
21
  }
@@ -32,11 +34,11 @@ const Banner = (_a) => {
32
34
  return (react_1.default.createElement(Wrapper_1.Wrapper, { paddings: {
33
35
  [paddings_1.PaddingsDirections.top]: paddingTop,
34
36
  [paddings_1.PaddingsDirections.bottom]: paddingBottom,
35
- }, className: b('container') },
36
- react_1.default.createElement("div", { className: b('content'), style: contentStyle, "data-qa": "blog-banner-content" },
37
+ }, qa: qaAttributes.wrapper, className: b('container') },
38
+ react_1.default.createElement("div", { className: b('content'), style: contentStyle, "data-qa": qaAttributes.content },
37
39
  react_1.default.createElement("div", { className: b('info') },
38
- react_1.default.createElement(page_constructor_1.Content, Object.assign({}, contentData))),
39
- image && (react_1.default.createElement("div", { className: b('image-container', { ['image-size']: imageSize }) },
40
+ react_1.default.createElement(page_constructor_1.Content, Object.assign({}, contentData, { qa: qaAttributes.content }))),
41
+ image && (react_1.default.createElement("div", { className: b('image-container', { ['image-size']: imageSize }), "data-qa": qaAttributes.imageContainer },
40
42
  react_1.default.createElement(page_constructor_1.Image, { className: b('image'), src: image }))))));
41
43
  };
42
44
  exports.Banner = Banner;
@@ -10,15 +10,16 @@ const cn_1 = require("../../utils/cn");
10
10
  const common_1 = require("../../utils/common");
11
11
  const b = (0, cn_1.block)('colored-text');
12
12
  const ColoredText = (_a) => {
13
- var { background, paddingTop, paddingBottom } = _a, content = tslib_1.__rest(_a, ["background", "paddingTop", "paddingBottom"]);
13
+ var { background, paddingTop, paddingBottom, qa } = _a, content = tslib_1.__rest(_a, ["background", "paddingTop", "paddingBottom", "qa"]);
14
14
  const contentData = (0, common_1.updateContentSizes)(content);
15
+ const qaAttributes = (0, common_1.getQaAttributes)(qa);
15
16
  return (react_1.default.createElement(Wrapper_1.Wrapper, { paddings: {
16
17
  [paddings_1.PaddingsDirections.top]: paddingTop,
17
18
  [paddings_1.PaddingsDirections.bottom]: paddingBottom,
18
- } },
19
- react_1.default.createElement("div", { className: b('container'), style: { backgroundColor: (background === null || background === void 0 ? void 0 : background.color) || 'none' }, "data-qa": "blog-colored-text-content" },
19
+ }, qa: qaAttributes.wrapper },
20
+ react_1.default.createElement("div", { className: b('container'), style: { backgroundColor: (background === null || background === void 0 ? void 0 : background.color) || 'none' }, "data-qa": qaAttributes.container },
20
21
  react_1.default.createElement("div", { className: b('picture-container') }, (background === null || background === void 0 ? void 0 : background.image) && (react_1.default.createElement(page_constructor_1.BackgroundImage, { className: b('picture'), alt: background === null || background === void 0 ? void 0 : background.altText, src: background === null || background === void 0 ? void 0 : background.image }))),
21
22
  react_1.default.createElement("div", { className: b('text-content') },
22
- react_1.default.createElement(page_constructor_1.Content, Object.assign({}, contentData))))));
23
+ react_1.default.createElement(page_constructor_1.Content, Object.assign({}, contentData, { qa: qaAttributes.content }))))));
23
24
  };
24
25
  exports.ColoredText = ColoredText;
@@ -4,16 +4,18 @@ exports.YFM = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importDefault(require("react"));
6
6
  const page_constructor_1 = require("@gravity-ui/page-constructor");
7
- const bem_cn_lite_1 = tslib_1.__importDefault(require("bem-cn-lite"));
8
7
  const Wrapper_1 = require("../../components/Wrapper/Wrapper");
9
8
  const paddings_1 = require("../../models/paddings");
10
- const b = (0, bem_cn_lite_1.default)('yfm');
9
+ const cn_1 = require("../../utils/cn");
10
+ const common_1 = require("../../utils/common");
11
+ const b = (0, cn_1.cn)('yfm');
11
12
  const YFM = (props) => {
12
- const { text, paddingTop, paddingBottom } = props;
13
+ const { text, paddingTop, paddingBottom, qa } = props;
14
+ const qaAttributes = (0, common_1.getQaAttributes)(qa);
13
15
  return (react_1.default.createElement(Wrapper_1.Wrapper, { paddings: {
14
16
  [paddings_1.PaddingsDirections.top]: paddingTop,
15
17
  [paddings_1.PaddingsDirections.bottom]: paddingBottom,
16
- } },
18
+ }, qa: qaAttributes.wrapper },
17
19
  react_1.default.createElement(page_constructor_1.YFMWrapper, { content: text, modifiers: {
18
20
  blog: true,
19
21
  resetPaddings: true,
@@ -23,9 +23,6 @@ unpredictable css rules order in build */
23
23
  width: 100%;
24
24
  max-width: 100%;
25
25
  }
26
- .bc-feed-controls__search .yc-text-input_view_normal .yc-text-input__control {
27
- border-color: var(--g-color-base-background);
28
- }
29
26
  .bc-feed-controls__select {
30
27
  width: 100%;
31
28
  }
@@ -33,9 +30,6 @@ unpredictable css rules order in build */
33
30
  max-height: 500px;
34
31
  border-radius: 12px;
35
32
  }
36
- .bc-feed-controls__popup.bc-feed-controls__popup .g-select-filter + .g-select-list {
37
- margin-top: 0;
38
- }
39
33
  .bc-feed-controls__popup.bc-feed-controls__popup .g-select-list {
40
34
  overflow: scroll;
41
35
  }
@@ -49,27 +43,15 @@ unpredictable css rules order in build */
49
43
  margin: 4px;
50
44
  border-radius: 8px;
51
45
  }
52
- .bc-feed-controls__popup.bc-feed-controls__popup .yc-text-input__content {
53
- padding: 4px;
54
- border: none;
55
- border-bottom: 1px solid var(--yc-color-line-generic);
56
- border-bottom-right-radius: 0;
57
- border-bottom-left-radius: 0;
58
- }
59
- .bc-feed-controls__popup.bc-feed-controls__popup .yc-text-input__content .yc-text-input__control.yc-text-input__control_type_input {
60
- border: none;
61
- }
62
- .bc-feed-controls__popup.bc-feed-controls__popup .g-select-list_size_xl .g-select-list__option {
63
- padding: 0 16px;
64
- }
65
46
 
66
- .bc-feed-controls__popup-filter .yc-text-input__control {
47
+ .bc-feed-controls__popup-filter {
67
48
  font-size: var(--g-text-body-2-font-size);
68
49
  line-height: var(--g-text-body-2-line-height);
50
+ padding: 4px 12px;
69
51
  border: none;
70
- }
71
- .bc-feed-controls__popup-filter .yc-text-input__control:hover, .bc-feed-controls__popup-filter .yc-text-input__control:focus {
72
- border: none;
52
+ border-bottom: 1px solid var(--yc-color-line-generic);
53
+ border-bottom-right-radius: 0;
54
+ border-bottom-left-radius: 0;
73
55
  }
74
56
  .bc-feed-controls__select:hover {
75
57
  width: 100%;
@@ -104,7 +104,7 @@ const Controls = ({ handleLoadData, tags = [], services = [], queryParams, }) =>
104
104
  defaultLabel: (0, i18n_1.i18)(i18n_1.Keyset.AllTags),
105
105
  }), disablePortal: true, virtualizationThreshold: VIRTUALIZATION_THRESHOLD, renderOption: customRenders_1.renderOption })),
106
106
  services.length > 0 ? (react_1.default.createElement("div", { className: b('filter-item') },
107
- react_1.default.createElement(uikit_1.Select, { className: b('select'), size: "xl", multiple: true, filterable: true, disablePortal: true, options: services, defaultValue: servicesItems, popupClassName: b('popup'), onUpdate: handleServicesSelect, placeholder: (0, i18n_1.i18)(i18n_1.Keyset.AllServices), renderControl: (0, customRenders_1.renderSwitcher)({
107
+ react_1.default.createElement(uikit_1.Select, { className: b('select'), size: "xl", multiple: true, filterable: true, hasClear: true, disablePortal: true, options: services, defaultValue: servicesItems, popupClassName: b('popup'), onUpdate: handleServicesSelect, placeholder: (0, i18n_1.i18)(i18n_1.Keyset.AllServices), renderControl: (0, customRenders_1.renderSwitcher)({
108
108
  initial: servicesItems,
109
109
  list: services,
110
110
  defaultLabel: (0, i18n_1.i18)(i18n_1.Keyset.AllServices),
@@ -13,8 +13,7 @@ const renderSwitcher = ({ initial, list, defaultLabel }) =>
13
13
  // eslint-disable-next-line react/display-name
14
14
  ({ onClick, ref }) => (react_1.default.createElement(CustomSwitcher_1.CustomSwitcher, { initial: initial, defaultLabel: defaultLabel, list: list, controlRef: ref, onClick: onClick }));
15
15
  exports.renderSwitcher = renderSwitcher;
16
- const renderFilter = ({ value, ref, onChange, onKeyDown }) => (react_1.default.createElement("div", { className: b('popup-filter') },
17
- react_1.default.createElement(uikit_1.TextInput, { controlRef: ref, controlProps: { size: 1 }, value: value, placeholder: (0, i18n_1.i18)(i18n_1.Keyset.Search), onUpdate: onChange, onKeyDown: onKeyDown })));
16
+ const renderFilter = ({ value, ref, onChange, onKeyDown }) => (react_1.default.createElement(uikit_1.TextInput, { controlRef: ref, controlProps: { size: 1 }, value: value, view: "clear", placeholder: (0, i18n_1.i18)(i18n_1.Keyset.Search), onUpdate: onChange, onKeyDown: onKeyDown, className: b('popup-filter') }));
18
17
  exports.renderFilter = renderFilter;
19
18
  const renderOption = (option) => (react_1.default.createElement(CustomSelectOption_1.CustomSelectOption, { data: option }));
20
19
  exports.renderOption = renderOption;
@@ -9,7 +9,7 @@ unpredictable css rules order in build */
9
9
  align-items: center;
10
10
  background-color: var(--g-color-base-background);
11
11
  border: 1px solid var(--g-color-base-background);
12
- border-radius: 10px;
12
+ border-radius: var(--g-border-radius-xl);
13
13
  width: 100%;
14
14
  line-height: 42px;
15
15
  }
@@ -1,10 +1,10 @@
1
- import { ReactNode } from 'react';
2
- import { Modifications } from 'bem-cn-lite';
3
- import { ClassNameProps } from '../../models/common';
1
+ import type { ReactNode } from 'react';
2
+ import type { NoStrictEntityMods } from '@bem-react/classname';
3
+ import type { ClassNameProps } from '../../models/common';
4
4
  export interface PaginatorItemProps {
5
5
  key: string | ArrowType;
6
6
  dataKey: string | ArrowType;
7
- mods: Modifications;
7
+ mods: NoStrictEntityMods;
8
8
  content: ReactNode;
9
9
  onClick?: (key: number | ArrowType) => void;
10
10
  loading?: boolean;
@@ -1,11 +1,12 @@
1
1
  import React from 'react';
2
2
  import { MetrikaGoal } from '@gravity-ui/page-constructor';
3
- import { PostData } from '../../models/common';
3
+ import { PostCardSize, PostCardTitleHeadingLevel, PostData } from '../../models/common';
4
4
  type PostCardProps = {
5
5
  post: PostData;
6
6
  fullWidth?: boolean;
7
7
  showTag?: boolean;
8
- size?: 's' | 'm';
8
+ size?: PostCardSize;
9
+ titleHeadingLevel?: PostCardTitleHeadingLevel;
9
10
  /**
10
11
  * @deprecated Metrika will be deleted after launch of analyticsEvents
11
12
  */
@@ -5,10 +5,11 @@ const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importStar(require("react"));
6
6
  const page_constructor_1 = require("@gravity-ui/page-constructor");
7
7
  const LikesContext_1 = require("../../contexts/LikesContext");
8
+ const common_1 = require("../../models/common");
8
9
  const cn_1 = require("../../utils/cn");
9
10
  const SuggestPostInfo_1 = require("../PostInfo/SuggestPostInfo");
10
11
  const b = (0, cn_1.block)('post-card');
11
- const PostCard = ({ post, metrikaGoals, fullWidth = false, size = 's', showTag = false, }) => {
12
+ const PostCard = ({ post, metrikaGoals, fullWidth = false, size = common_1.PostCardSize.SMALL, showTag = false, titleHeadingLevel = common_1.PostCardTitleHeadingLevel.H3, }) => {
12
13
  var _a;
13
14
  const { title: postTitle, htmlTitle, textTitle, blogPostId, id, date, readingTime, hasUserLike, likes, image, description, tags, url, } = post;
14
15
  const title = postTitle || textTitle || htmlTitle;
@@ -25,9 +26,9 @@ const PostCard = ({ post, metrikaGoals, fullWidth = false, size = 's', showTag =
25
26
  react_1.default.createElement("div", { className: b('image-container'), "data-qa": "blog-suggest-header" })),
26
27
  react_1.default.createElement(page_constructor_1.CardBase.Content, null,
27
28
  showTag && ((_a = tags === null || tags === void 0 ? void 0 : tags[0]) === null || _a === void 0 ? void 0 : _a.name) && (react_1.default.createElement("div", { className: b('tag', { size }) }, tags[0].name)),
28
- title && (react_1.default.createElement("h4", { className: b('title', { size }) },
29
- react_1.default.createElement("span", null,
30
- react_1.default.createElement(page_constructor_1.HTML, null, title)))),
29
+ title &&
30
+ react_1.default.createElement(titleHeadingLevel, { className: b('title', { size }) }, react_1.default.createElement("span", null,
31
+ react_1.default.createElement(page_constructor_1.HTML, null, title))),
31
32
  description && (react_1.default.createElement(page_constructor_1.YFMWrapper, { className: b('description'), content: description, modifiers: {
32
33
  blog: size === 'm',
33
34
  blogCard: true,
@@ -1,8 +1,8 @@
1
1
  import React from 'react';
2
- import { PostData, QAProps, ToggleLikeCallbackType } from '../../models/common';
2
+ import { PostCardSize, PostData, QAProps, ToggleLikeCallbackType } from '../../models/common';
3
3
  export interface SuggestPostInfoProps extends Pick<PostData, 'date' | 'readingTime' | 'hasUserLike'>, QAProps {
4
4
  postId: PostData['blogPostId'];
5
- size?: 's' | 'm';
5
+ size?: PostCardSize;
6
6
  likes?: {
7
7
  likesCount?: number;
8
8
  hasUserLike?: boolean;
@@ -4,6 +4,7 @@ exports.SuggestPostInfo = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importDefault(require("react"));
6
6
  const useLikes_1 = require("../../hooks/useLikes");
7
+ const common_1 = require("../../models/common");
7
8
  const cn_1 = require("../../utils/cn");
8
9
  const Date_1 = require("./components/Date");
9
10
  const ReadingTime_1 = require("./components/ReadingTime");
@@ -23,7 +24,7 @@ const b = (0, cn_1.block)('post-info');
23
24
  *
24
25
  * @returns jsx
25
26
  */
26
- const SuggestPostInfo = ({ postId, date, readingTime, likes, size = 's', qa, }) => {
27
+ const SuggestPostInfo = ({ postId, date, readingTime, likes, size = common_1.PostCardSize.SMALL, qa, }) => {
27
28
  const { hasUserLike, likesCount, handleLike } = (0, useLikes_1.useLikes)({
28
29
  hasLike: likes === null || likes === void 0 ? void 0 : likes.hasUserLike,
29
30
  count: likes === null || likes === void 0 ? void 0 : likes.likesCount,
@@ -1,7 +1,8 @@
1
1
  import React from 'react';
2
+ import { PostCardSize } from '../../../models/common';
2
3
  type DateProps = {
3
4
  date: string | number;
4
- size?: 's' | 'm';
5
+ size?: PostCardSize;
5
6
  };
6
7
  export declare const Date: React.FC<DateProps>;
7
8
  export {};
@@ -4,10 +4,11 @@ exports.Date = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const react_1 = tslib_1.__importStar(require("react"));
6
6
  const LocaleContext_1 = require("../../../contexts/LocaleContext");
7
+ const common_1 = require("../../../models/common");
7
8
  const cn_1 = require("../../../utils/cn");
8
9
  const date_1 = require("../../../utils/date");
9
10
  const b = (0, cn_1.block)('post-info');
10
- const Date = ({ date, size = 's' }) => {
11
+ const Date = ({ date, size = common_1.PostCardSize.SMALL }) => {
11
12
  const { locale } = (0, react_1.useContext)(LocaleContext_1.LocaleContext);
12
13
  return react_1.default.createElement("div", { className: b('item', { size }) }, (0, date_1.format)(date, 'longDate', locale === null || locale === void 0 ? void 0 : locale.code));
13
14
  };
@@ -6,6 +6,7 @@ const react_1 = tslib_1.__importDefault(require("react"));
6
6
  const page_constructor_1 = require("@gravity-ui/page-constructor");
7
7
  const uikit_1 = require("@gravity-ui/uikit");
8
8
  const i18n_1 = require("../../i18n");
9
+ const common_1 = require("../../models/common");
9
10
  const cn_1 = require("../../utils/cn");
10
11
  const Paginator_1 = require("../Paginator/Paginator");
11
12
  const PostCard_1 = require("../PostCard/PostCard");
@@ -15,12 +16,14 @@ const Posts = ({ containerId, pinnedPostOnPage, currentPage, postsOnPage, isShow
15
16
  isFetching && react_1.default.createElement("div", { className: b('loaderContainer') }),
16
17
  react_1.default.createElement("div", { id: containerId, className: b('cards-container', { isLoading: isFetching }) },
17
18
  pinnedPostOnPage && currentPage === 1 && (react_1.default.createElement("div", { className: b('pinned-container') },
18
- react_1.default.createElement(PostCard_1.PostCard, { post: pinnedPostOnPage, size: "m", fullWidth: true, showTag: true }))),
19
+ react_1.default.createElement(PostCard_1.PostCard, { post: pinnedPostOnPage, size: common_1.PostCardSize.MEDIUM, fullWidth: true, showTag: true, titleHeadingLevel: common_1.PostCardTitleHeadingLevel.H2 }))),
19
20
  (postsOnPage === null || postsOnPage === void 0 ? void 0 : postsOnPage.length) ? (react_1.default.createElement(page_constructor_1.CardLayoutBlock, { title: '', colSizes: {
20
21
  all: 12,
21
22
  lg: 4,
22
23
  md: 6,
23
- } }, postsOnPage === null || postsOnPage === void 0 ? void 0 : postsOnPage.map((post) => (react_1.default.createElement(PostCard_1.PostCard, { key: post.id, post: post, showTag: true }))))) : (react_1.default.createElement(PostsEmpty_1.PostsEmpty, null))),
24
+ } }, postsOnPage === null || postsOnPage === void 0 ? void 0 : postsOnPage.map((post) => (react_1.default.createElement(PostCard_1.PostCard, { key: post.id, post: post, showTag: true, titleHeadingLevel: pinnedPostOnPage
25
+ ? common_1.PostCardTitleHeadingLevel.H3
26
+ : common_1.PostCardTitleHeadingLevel.H2 }))))) : (react_1.default.createElement(PostsEmpty_1.PostsEmpty, null))),
24
27
  react_1.default.createElement("div", { className: b('pagination') },
25
28
  Boolean(isShowMoreVisible && (postsOnPage === null || postsOnPage === void 0 ? void 0 : postsOnPage.length)) && (react_1.default.createElement(uikit_1.Button, { view: "outlined", size: "xl", className: b('more-button'), onClick: handleShowMore }, (0, i18n_1.i18)(i18n_1.Keyset.ActionLoadMore))),
26
29
  errorShowMore && (react_1.default.createElement("div", { className: b('error-show-more') },
@@ -7,30 +7,28 @@ unpredictable css rules order in build */
7
7
  display: flex;
8
8
  align-items: center;
9
9
  justify-content: flex-end;
10
- height: 44px;
11
10
  transition: width 0.3s;
12
11
  }
13
- .bc-search__close-button, .bc-search__search-button {
14
- position: absolute;
15
- z-index: 2;
16
- right: 10px;
12
+ .bc-search__input-icon {
13
+ display: flex;
14
+ padding-right: 7px;
17
15
  color: var(--g-color-text-hint);
16
+ cursor: pointer;
18
17
  }
19
- .bc-search__search-button:hover {
20
- color: var(--g-color-text-secondary);
18
+ .bc-search__search-suggest {
19
+ display: flex;
20
+ align-items: center;
21
+ height: 44px;
22
+ background-color: var(--g-color-base-background);
23
+ border-radius: var(--bc-text-input-border-radius);
24
+ border: 1px solid var(--g-color-base-background);
21
25
  }
22
- .bc-search__search-suggest-container {
23
- width: 100%;
26
+ .bc-search__search-suggest:hover, .bc-search__search-suggest:focus {
27
+ border: 1px solid var(--g-color-base-generic-hover);
24
28
  }
25
29
  .bc-search .bc-search__search-suggest-control {
26
- background-color: var(--g-color-base-background);
27
30
  padding-left: 12px;
28
31
  padding-right: 32px;
29
- border-radius: var(--bc-text-input-border-radius);
30
- border: 1px solid transparent;
31
- }
32
- .bc-search .bc-search__search-suggest-control:hover, .bc-search .bc-search__search-suggest-control:focus {
33
- border: 1px solid var(--g-color-base-generic-hover);
34
32
  }
35
33
  .bc-search_size_s {
36
34
  --bc-text-input-border-radius: var(--g-border-radius-l);
@@ -11,5 +11,11 @@ interface SearchProps extends ClassNameProps {
11
11
  autoFocus?: boolean;
12
12
  className?: string;
13
13
  }
14
- export declare const Search: React.FC<SearchProps>;
14
+ /**
15
+ * Search component, placed on blog main page,
16
+ * based on TextInput from uikit
17
+ *
18
+ * @returns {JSX|null}
19
+ */
20
+ export declare const Search: ({ className, initialValue, onSubmit, debounce, placeholder, size, autoFocus, value: externalValue, }: SearchProps) => React.JSX.Element;
15
21
  export {};
@@ -10,12 +10,17 @@ const i18n_1 = require("../../i18n");
10
10
  const Close_1 = require("../../icons/Close");
11
11
  const SearchIcon_1 = require("../../icons/SearchIcon");
12
12
  const cn_1 = require("../../utils/cn");
13
- const ButtonWithIcon_1 = require("../ButtonWithIcon/ButtonWithIcon");
14
13
  const b = (0, cn_1.block)('search');
15
14
  const SEARCH_ICON_SIZE = 16;
16
15
  const CLOSE_ICON_SIZE = 12;
17
- const Search = (props) => {
18
- const { className, initialValue, onSubmit, debounce = 300, placeholder = (0, i18n_1.i18)(i18n_1.Keyset.Search), size = 'm', autoFocus = false, value: externalValue, } = props;
16
+ const AUTOFOCUS_TIMEOUT = 0;
17
+ /**
18
+ * Search component, placed on blog main page,
19
+ * based on TextInput from uikit
20
+ *
21
+ * @returns {JSX|null}
22
+ */
23
+ const Search = ({ className, initialValue, onSubmit, debounce = 300, placeholder = (0, i18n_1.i18)(i18n_1.Keyset.Search), size = 'm', autoFocus = false, value: externalValue, }) => {
19
24
  const handleChange = (0, lodash_1.debounce)(onSubmit, debounce);
20
25
  const [value, setValue] = (0, react_1.useState)(initialValue);
21
26
  const inputRef = (0, react_1.useRef)(null);
@@ -27,21 +32,28 @@ const Search = (props) => {
27
32
  }, [externalValue]);
28
33
  (0, react_1.useEffect)(() => {
29
34
  if (autoFocus && !isIPhone) {
30
- setTimeout(() => { var _a; return (_a = inputRef === null || inputRef === void 0 ? void 0 : inputRef.current) === null || _a === void 0 ? void 0 : _a.focus({ preventScroll: true }); }, 0);
35
+ setTimeout(() => { var _a; return (_a = inputRef === null || inputRef === void 0 ? void 0 : inputRef.current) === null || _a === void 0 ? void 0 : _a.focus({ preventScroll: true }); }, AUTOFOCUS_TIMEOUT);
31
36
  }
32
37
  }, [autoFocus, inputRef, isIPhone]);
33
- return (react_1.default.createElement("div", { className: b({ size }, className) },
34
- react_1.default.createElement("div", { className: b('search-suggest-container') },
35
- react_1.default.createElement(uikit_1.TextInput, { className: b('search-suggest'), value: value, onUpdate: (query) => {
36
- setValue(query);
37
- handleChange(query);
38
- }, placeholder: placeholder, size: size === 'm' ? 'xl' : 'l', controlRef: inputRef, view: "clear", controlProps: {
39
- className: b('search-suggest-control'),
40
- } })),
41
- value ? (react_1.default.createElement(ButtonWithIcon_1.ButtonWithIcon, { className: b('close-button'), icon: Close_1.Close, iconSize: CLOSE_ICON_SIZE, size: "xs", onClick: () => {
38
+ const rightContent = (0, react_1.useMemo)(() => {
39
+ const iconData = value ? Close_1.Close : SearchIcon_1.SearchIcon;
40
+ const iconSize = value ? CLOSE_ICON_SIZE : SEARCH_ICON_SIZE;
41
+ const handleClick = () => {
42
+ if (value) {
42
43
  handleChange.cancel();
43
44
  setValue('');
44
45
  onSubmit('');
45
- } })) : (react_1.default.createElement(ButtonWithIcon_1.ButtonWithIcon, { className: b('search-button'), icon: SearchIcon_1.SearchIcon, iconSize: SEARCH_ICON_SIZE, size: "xs", disabled: true }))));
46
+ }
47
+ };
48
+ return (react_1.default.createElement("div", { className: b('input-icon'), onClick: handleClick },
49
+ react_1.default.createElement(uikit_1.Icon, { size: iconSize, data: iconData })));
50
+ }, [handleChange, onSubmit, value]);
51
+ return (react_1.default.createElement("div", { className: b({ size }, className) },
52
+ react_1.default.createElement(uikit_1.TextInput, { className: b('search-suggest'), value: value, onUpdate: (query) => {
53
+ setValue(query);
54
+ handleChange(query);
55
+ }, placeholder: placeholder, size: size === 'm' ? 'xl' : 'l', controlRef: inputRef, view: "clear", controlProps: {
56
+ className: b('search-suggest-control'),
57
+ }, rightContent: rightContent })));
46
58
  };
47
59
  exports.Search = Search;
@@ -1,17 +1,17 @@
1
1
  import { ReactElement } from 'react';
2
2
  import { ContentBlockProps, HeaderBlockProps, MediaProps as PCMediaProps, TextTheme } from '@gravity-ui/page-constructor';
3
- import { BlockType, ClassNameProps, PostData } from './common';
3
+ import { BlockType, ClassNameProps, PostData, QAProps } from './common';
4
4
  import { PaddingsYFMProps } from './paddings';
5
5
  export type AuthorProps = ClassNameProps & {
6
6
  authorId: number;
7
7
  image: string;
8
- } & PaddingsYFMProps;
9
- export type BannerProps = ContentBlockProps & {
8
+ } & PaddingsYFMProps & QAProps;
9
+ export type BannerProps = ContentBlockProps & QAProps & {
10
10
  color?: string;
11
11
  image?: string;
12
12
  imageSize?: 's' | 'm';
13
13
  } & PaddingsYFMProps;
14
- export type ColoredTextProps = ContentBlockProps & {
14
+ export type ColoredTextProps = ContentBlockProps & QAProps & {
15
15
  background?: {
16
16
  color?: string;
17
17
  image?: string;
@@ -40,7 +40,7 @@ export type SuggestProps = ClassNameProps & {
40
40
  } & PaddingsYFMProps;
41
41
  export type YFMProps = {
42
42
  text: string;
43
- } & PaddingsYFMProps;
43
+ } & PaddingsYFMProps & QAProps;
44
44
  export type FeedProps = {
45
45
  image: string;
46
46
  };
@@ -168,3 +168,11 @@ export type FetchArgs = {
168
168
  export interface QAProps {
169
169
  qa?: string;
170
170
  }
171
+ export declare enum PostCardSize {
172
+ SMALL = "s",
173
+ MEDIUM = "m"
174
+ }
175
+ export declare enum PostCardTitleHeadingLevel {
176
+ H2 = "h2",
177
+ H3 = "h3"
178
+ }
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.DefaultEventNames = exports.BlockType = exports.Theme = void 0;
3
+ exports.PostCardTitleHeadingLevel = exports.PostCardSize = exports.DefaultEventNames = exports.BlockType = exports.Theme = void 0;
4
4
  var Theme;
5
5
  (function (Theme) {
6
6
  Theme["Light"] = "light";
@@ -31,4 +31,14 @@ var DefaultEventNames;
31
31
  DefaultEventNames["Tag"] = "selector-tag-click";
32
32
  DefaultEventNames["Service"] = "selector-service-click";
33
33
  DefaultEventNames["SaveOnly"] = "save-only-button-click";
34
- })(DefaultEventNames = exports.DefaultEventNames || (exports.DefaultEventNames = {}));
34
+ })(DefaultEventNames = exports.DefaultEventNames || (exports.DefaultEventNames = {}));
35
+ var PostCardSize;
36
+ (function (PostCardSize) {
37
+ PostCardSize["SMALL"] = "s";
38
+ PostCardSize["MEDIUM"] = "m";
39
+ })(PostCardSize = exports.PostCardSize || (exports.PostCardSize = {}));
40
+ var PostCardTitleHeadingLevel;
41
+ (function (PostCardTitleHeadingLevel) {
42
+ PostCardTitleHeadingLevel["H2"] = "h2";
43
+ PostCardTitleHeadingLevel["H3"] = "h3";
44
+ })(PostCardTitleHeadingLevel = exports.PostCardTitleHeadingLevel || (exports.PostCardTitleHeadingLevel = {}));
@@ -1,4 +1,3 @@
1
- import blockOrigin from 'bem-cn-lite';
2
1
  export declare const NAMESPACE = "bc-";
3
- export type CnBlock = ReturnType<typeof blockOrigin>;
4
- export declare function block(name: string): CnBlock;
2
+ export declare const cn: import("@bem-react/classname").ClassNameInitilizer;
3
+ export declare const block: import("@bem-react/classname").ClassNameInitilizer;
@@ -1,10 +1,7 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.block = exports.NAMESPACE = void 0;
4
- const tslib_1 = require("tslib");
5
- const bem_cn_lite_1 = tslib_1.__importDefault(require("bem-cn-lite"));
3
+ exports.block = exports.cn = exports.NAMESPACE = void 0;
4
+ const classname_1 = require("@bem-react/classname");
6
5
  exports.NAMESPACE = 'bc-';
7
- function block(name) {
8
- return (0, bem_cn_lite_1.default)(`${exports.NAMESPACE}${name}`);
9
- }
10
- exports.block = block;
6
+ exports.cn = (0, classname_1.withNaming)({ e: '__', m: '_' });
7
+ exports.block = (0, classname_1.withNaming)({ n: exports.NAMESPACE, e: '__', m: '_' });
@@ -41,4 +41,5 @@ export declare const isMetrikaExist: (goal: NewMetrikaGoal, existGoals: NewMetri
41
41
  export declare const getBlogElementMetrika: (blogCustomGoal: NewMetrikaGoal, existingGoals?: MetrikaGoal) => string | string[] | NewMetrikaGoal[];
42
42
  export declare const getFeedQueryParams: (queryString: Query, pageNumber?: number) => GetPostsRequest;
43
43
  export declare const scrollOnPageChange: (containerId: string) => void;
44
+ export declare const getQaAttributes: (qa?: string, ...customKeys: (string | Array<string>)[]) => Record<string, string>;
44
45
  export {};
@@ -1,12 +1,13 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.scrollOnPageChange = exports.getFeedQueryParams = exports.getBlogElementMetrika = exports.isMetrikaExist = exports.getBreadcrumbs = exports.getBlogPath = exports.updateContentSizes = exports.getTagFilterUrl = exports.postLikeStatus = exports.getTags = exports.scrollToHash = exports.getPageSearchParams = exports.getAbsolutePath = void 0;
3
+ exports.getQaAttributes = exports.scrollOnPageChange = exports.getFeedQueryParams = exports.getBlogElementMetrika = exports.isMetrikaExist = exports.getBreadcrumbs = exports.getBlogPath = exports.updateContentSizes = exports.getTagFilterUrl = exports.postLikeStatus = exports.getTags = exports.scrollToHash = exports.getPageSearchParams = exports.getAbsolutePath = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  const url_1 = require("url");
6
6
  const page_constructor_1 = require("@gravity-ui/page-constructor");
7
7
  const lodash_1 = require("lodash");
8
8
  const constants_1 = require("../blocks/constants");
9
9
  const i18n_1 = require("../i18n");
10
+ const QA_ATTRIBUTES_KEYS = ['container', 'content', 'wrapper', 'image', 'button'];
10
11
  function getAbsolutePath(router, url) {
11
12
  if (!router || !router.pathname) {
12
13
  return url !== null && url !== void 0 ? url : '';
@@ -112,4 +113,16 @@ const scrollOnPageChange = (containerId) => {
112
113
  (0, exports.scrollToHash)(containerId);
113
114
  }
114
115
  };
115
- exports.scrollOnPageChange = scrollOnPageChange;
116
+ exports.scrollOnPageChange = scrollOnPageChange;
117
+ const getQaAttributes = (qa, ...customKeys) => {
118
+ const attributes = {};
119
+ if (qa) {
120
+ const keys = QA_ATTRIBUTES_KEYS.concat((0, lodash_1.flatten)(customKeys));
121
+ keys.forEach((key) => {
122
+ attributes[(0, lodash_1.camelCase)(key)] = `${qa}-${key}`;
123
+ });
124
+ attributes.default = qa;
125
+ }
126
+ return attributes;
127
+ };
128
+ exports.getQaAttributes = getQaAttributes;
@@ -8,7 +8,7 @@ import './Author.css';
8
8
  const b = block('author');
9
9
  export const Author = (props) => {
10
10
  var _a;
11
- const { image, paddingTop, paddingBottom, authorId } = props;
11
+ const { image, paddingTop, paddingBottom, authorId, qa } = props;
12
12
  const { post } = useContext(PostPageContext);
13
13
  const author = (_a = post === null || post === void 0 ? void 0 : post.authors) === null || _a === void 0 ? void 0 : _a.find(({ id }) => id === authorId);
14
14
  const authorItem = useMemo(() => {
@@ -28,7 +28,7 @@ export const Author = (props) => {
28
28
  return (React.createElement(Wrapper, { paddings: {
29
29
  [PaddingsDirections.top]: paddingTop,
30
30
  [PaddingsDirections.bottom]: paddingBottom,
31
- }, className: b('content') },
31
+ }, className: b('content'), qa: qa },
32
32
  React.createElement("div", { className: b('layout'), "data-qa": "blog-author-layout" },
33
33
  React.createElement(PCAuthor, { type: AuthorType.Column, author: authorItem, authorContainerClassName: b('container') }))));
34
34
  };