@gravity-ui/page-constructor 3.0.0-alpha.4 → 3.0.0-alpha.6

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 (130) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/build/cjs/components/BackgroundImage/BackgroundImage.js +2 -2
  3. package/build/cjs/components/BlockBase/BlockBase.d.ts +3 -2
  4. package/build/cjs/components/BlockBase/BlockBase.js +4 -2
  5. package/build/cjs/components/Button/Button.css +3 -0
  6. package/build/cjs/components/Button/Button.js +5 -4
  7. package/build/cjs/components/Image/Image.d.ts +1 -0
  8. package/build/cjs/components/Image/Image.js +2 -2
  9. package/build/cjs/containers/Loadable/Loadable.d.ts +2 -2
  10. package/build/cjs/containers/PageConstructor/PageConstructor.js +5 -3
  11. package/build/cjs/containers/PageConstructor/components/ConstructorBlocks/ConstructorBlocks.js +3 -2
  12. package/build/cjs/containers/PageConstructor/components/ConstructorItem/ConstructorItem.d.ts +1 -1
  13. package/build/cjs/containers/PageConstructor/components/ConstructorItem/ConstructorItem.js +5 -5
  14. package/build/cjs/context/innerContext/InnerContext.d.ts +2 -1
  15. package/build/cjs/customization/BlockDecoration.d.ts +3 -0
  16. package/build/cjs/customization/BlockDecoration.js +22 -0
  17. package/build/cjs/editor/Components/AddBlock/AddBlock.css +82 -0
  18. package/build/cjs/editor/Components/AddBlock/AddBlock.d.ts +7 -0
  19. package/build/cjs/editor/Components/AddBlock/AddBlock.js +43 -0
  20. package/build/cjs/editor/Components/EditBlock/EditBlock.css +47 -0
  21. package/build/cjs/editor/Components/EditBlock/EditBlock.d.ts +4 -0
  22. package/build/cjs/editor/Components/EditBlock/EditBlock.js +32 -0
  23. package/build/cjs/editor/Containers/Editor.d.ts +2 -0
  24. package/build/cjs/editor/Containers/Editor.js +24 -0
  25. package/build/cjs/editor/data/index.d.ts +13 -0
  26. package/build/cjs/editor/data/index.js +27 -0
  27. package/build/cjs/editor/data/previews/default-preview.d.ts +3 -0
  28. package/build/cjs/editor/data/previews/default-preview.js +18 -0
  29. package/build/cjs/editor/data/previews/header-block.d.ts +3 -0
  30. package/build/cjs/editor/data/previews/header-block.js +19 -0
  31. package/build/cjs/editor/index.d.ts +2 -0
  32. package/build/cjs/editor/index.js +7 -0
  33. package/build/cjs/editor/store/index.d.ts +15 -0
  34. package/build/cjs/editor/store/index.js +32 -0
  35. package/build/cjs/editor/store/reducer.d.ts +41 -0
  36. package/build/cjs/editor/store/reducer.js +59 -0
  37. package/build/cjs/editor/store/utils.d.ts +12 -0
  38. package/build/cjs/editor/store/utils.js +34 -0
  39. package/build/cjs/editor/styles/mixins.css +0 -0
  40. package/build/cjs/editor/styles/variables.css +0 -0
  41. package/build/cjs/editor/types/index.d.ts +17 -0
  42. package/build/cjs/editor/types/index.js +2 -0
  43. package/build/cjs/editor/utils/index.d.ts +11 -0
  44. package/build/cjs/editor/utils/index.js +12 -0
  45. package/build/cjs/hooks/useMetrika.js +0 -7
  46. package/build/cjs/models/constructor-items/blocks.d.ts +1 -11
  47. package/build/cjs/models/constructor-items/blocks.js +0 -2
  48. package/build/cjs/models/constructor-items/common.d.ts +3 -3
  49. package/build/cjs/models/constructor.d.ts +4 -1
  50. package/build/cjs/models/customization.d.ts +9 -0
  51. package/build/cjs/models/customization.js +2 -0
  52. package/build/cjs/models/index.d.ts +1 -0
  53. package/build/cjs/models/index.js +1 -0
  54. package/build/cjs/schema/index.js +0 -1
  55. package/build/cjs/sub-blocks/Content/Content.js +2 -2
  56. package/build/cjs/text-transform/transformers.js +2 -4
  57. package/build/cjs/utils/blocks.d.ts +4 -1
  58. package/build/cjs/utils/blocks.js +11 -1
  59. package/build/esm/components/BackgroundImage/BackgroundImage.js +2 -2
  60. package/build/esm/components/BlockBase/BlockBase.d.ts +3 -2
  61. package/build/esm/components/BlockBase/BlockBase.js +4 -2
  62. package/build/esm/components/Button/Button.css +3 -0
  63. package/build/esm/components/Button/Button.js +5 -4
  64. package/build/esm/components/Image/Image.d.ts +1 -0
  65. package/build/esm/components/Image/Image.js +2 -2
  66. package/build/esm/containers/Loadable/Loadable.d.ts +2 -2
  67. package/build/esm/containers/PageConstructor/PageConstructor.js +6 -4
  68. package/build/esm/containers/PageConstructor/components/ConstructorBlocks/ConstructorBlocks.js +3 -2
  69. package/build/esm/containers/PageConstructor/components/ConstructorItem/ConstructorItem.d.ts +1 -1
  70. package/build/esm/containers/PageConstructor/components/ConstructorItem/ConstructorItem.js +5 -5
  71. package/build/esm/context/innerContext/InnerContext.d.ts +2 -1
  72. package/build/esm/customization/BlockDecoration.d.ts +3 -0
  73. package/build/esm/customization/BlockDecoration.js +17 -0
  74. package/build/esm/editor/Components/AddBlock/AddBlock.css +82 -0
  75. package/build/esm/editor/Components/AddBlock/AddBlock.d.ts +8 -0
  76. package/build/esm/editor/Components/AddBlock/AddBlock.js +41 -0
  77. package/build/esm/editor/Components/EditBlock/EditBlock.css +47 -0
  78. package/build/esm/editor/Components/EditBlock/EditBlock.d.ts +5 -0
  79. package/build/esm/editor/Components/EditBlock/EditBlock.js +30 -0
  80. package/build/esm/editor/Containers/Editor.d.ts +2 -0
  81. package/build/esm/editor/Containers/Editor.js +20 -0
  82. package/build/esm/editor/data/index.d.ts +13 -0
  83. package/build/esm/editor/data/index.js +24 -0
  84. package/build/esm/editor/data/previews/default-preview.d.ts +3 -0
  85. package/build/esm/editor/data/previews/default-preview.js +15 -0
  86. package/build/esm/editor/data/previews/header-block.d.ts +3 -0
  87. package/build/esm/editor/data/previews/header-block.js +16 -0
  88. package/build/esm/editor/index.d.ts +2 -0
  89. package/build/esm/editor/index.js +2 -0
  90. package/build/esm/editor/store/index.d.ts +15 -0
  91. package/build/esm/editor/store/index.js +28 -0
  92. package/build/esm/editor/store/reducer.d.ts +41 -0
  93. package/build/esm/editor/store/reducer.js +55 -0
  94. package/build/esm/editor/store/utils.d.ts +12 -0
  95. package/build/esm/editor/store/utils.js +26 -0
  96. package/build/esm/editor/styles/mixins.css +0 -0
  97. package/build/esm/editor/styles/variables.css +0 -0
  98. package/build/esm/editor/types/index.d.ts +17 -0
  99. package/build/esm/editor/types/index.js +1 -0
  100. package/build/esm/editor/utils/index.d.ts +11 -0
  101. package/build/esm/editor/utils/index.js +6 -0
  102. package/build/esm/hooks/useMetrika.js +0 -7
  103. package/build/esm/models/constructor-items/blocks.d.ts +1 -11
  104. package/build/esm/models/constructor-items/blocks.js +0 -2
  105. package/build/esm/models/constructor-items/common.d.ts +3 -3
  106. package/build/esm/models/constructor.d.ts +4 -1
  107. package/build/esm/models/customization.d.ts +9 -0
  108. package/build/esm/models/customization.js +1 -0
  109. package/build/esm/models/index.d.ts +1 -0
  110. package/build/esm/models/index.js +1 -0
  111. package/build/esm/schema/index.js +0 -1
  112. package/build/esm/sub-blocks/Content/Content.js +2 -3
  113. package/build/esm/text-transform/transformers.js +2 -4
  114. package/build/esm/utils/blocks.d.ts +4 -1
  115. package/build/esm/utils/blocks.js +7 -0
  116. package/package.json +4 -3
  117. package/server/models/constructor-items/blocks.d.ts +1 -11
  118. package/server/models/constructor-items/blocks.js +0 -2
  119. package/server/models/constructor-items/common.d.ts +3 -3
  120. package/server/models/constructor.d.ts +4 -1
  121. package/server/models/customization.d.ts +9 -0
  122. package/server/models/customization.js +2 -0
  123. package/server/models/index.d.ts +1 -0
  124. package/server/models/index.js +1 -0
  125. package/server/text-transform/transformers.js +2 -4
  126. package/server/utils/blocks.d.ts +4 -1
  127. package/server/utils/blocks.js +11 -1
  128. package/styles/styles.css +0 -196
  129. package/styles/styles.scss +0 -1
  130. package/styles/fonts.scss +0 -223
@@ -5,6 +5,7 @@ export interface ImageProps extends Partial<ImageObjectProps>, Partial<ImageDevi
5
5
  className?: string;
6
6
  onClick?: MouseEventHandler;
7
7
  containerClassName?: string;
8
+ qa?: string;
8
9
  }
9
10
  declare const Image: (props: ImageProps) => JSX.Element | null;
10
11
  export default Image;
@@ -9,7 +9,7 @@ const checkWebP = (src) => {
9
9
  };
10
10
  const Image = (props) => {
11
11
  const projectSettings = useContext(ProjectSettingsContext);
12
- const { src: imageSrc, alt = i18n('img-alt'), disableCompress, tablet, desktop, mobile, style, className, onClick, containerClassName, } = props;
12
+ const { src: imageSrc, alt = i18n('img-alt'), disableCompress, tablet, desktop, mobile, style, className, onClick, containerClassName, qa, } = props;
13
13
  const [imgLoadingError, setImgLoadingError] = useState(false);
14
14
  const src = imageSrc || desktop;
15
15
  if (!src) {
@@ -19,7 +19,7 @@ const Image = (props) => {
19
19
  disableCompress ||
20
20
  !isCompressible(src) ||
21
21
  imgLoadingError;
22
- return (React.createElement("picture", { className: containerClassName },
22
+ return (React.createElement("picture", { className: containerClassName, "data-qa": qa },
23
23
  mobile && (React.createElement(Fragment, null,
24
24
  !disableWebp && (React.createElement("source", { srcSet: checkWebP(mobile), type: "image/webp", media: `(max-width: ${BREAKPOINTS.sm}px)` })),
25
25
  React.createElement("source", { srcSet: mobile, media: `(max-width: ${BREAKPOINTS.sm}px)` }))),
@@ -1,5 +1,5 @@
1
1
  import { PropsWithChildren } from 'react';
2
- import { Block, CustomItem, FetchLoadableData, LoadableData, LoadableProps } from '../../models';
2
+ import { ConstructorItem, CustomItem, FetchLoadableData, LoadableData, LoadableProps } from '../../models';
3
3
  import './Loadable.css';
4
4
  export interface LoadableState {
5
5
  loading: boolean;
@@ -9,7 +9,7 @@ export interface LoadableState {
9
9
  export interface LoadableComponentsProps extends Omit<PropsWithChildren<LoadableProps>, 'source'> {
10
10
  Component: CustomItem;
11
11
  ChildComponent: CustomItem;
12
- block: Block;
12
+ block: ConstructorItem;
13
13
  blockKey: string;
14
14
  fetch: FetchLoadableData;
15
15
  }
@@ -9,7 +9,7 @@ import { ThemeValueContext } from '../../context/theme/ThemeValueContext';
9
9
  import { Grid } from '../../grid';
10
10
  import { BlockType, BlockTypes, HeaderBlockTypes, SubBlockTypes, } from '../../models';
11
11
  import Layout from '../../navigation/containers/Layout/Layout';
12
- import { block as cnBlock, getCustomBlockTypes, getCustomHeaderTypes, getCustomItems, getCustomSubBlockTypes, getThemedValue, } from '../../utils';
12
+ import { block as cnBlock, getCustomBlockTypes, getCustomHeaderTypes, getCustomItems, getCustomSubBlockTypes, getHeaderBlock, getOrderedBlocks, getThemedValue, } from '../../utils';
13
13
  import { ConstructorBlocks } from './components/ConstructorBlocks';
14
14
  import { ConstructorHeader } from './components/ConstructorItem';
15
15
  import { ConstructorRow } from './components/ConstructorRow';
@@ -25,12 +25,14 @@ export const Constructor = (props) => {
25
25
  itemMap: Object.assign(Object.assign(Object.assign({}, blockMap), subBlockMap), getCustomItems(custom)),
26
26
  loadables: custom === null || custom === void 0 ? void 0 : custom.loadable,
27
27
  shouldRenderBlock,
28
+ customization: {
29
+ decorators: custom === null || custom === void 0 ? void 0 : custom.decorators,
30
+ },
28
31
  },
29
32
  }), [custom, shouldRenderBlock]);
30
33
  const { themeValue: theme } = useContext(ThemeValueContext);
31
- const isHeaderBlock = (block) => context.headerBlockTypes.includes(block.type);
32
- const header = blocks === null || blocks === void 0 ? void 0 : blocks.find(isHeaderBlock);
33
- const restBlocks = blocks === null || blocks === void 0 ? void 0 : blocks.filter((block) => !isHeaderBlock(block));
34
+ const header = getHeaderBlock(blocks, context.headerBlockTypes);
35
+ const restBlocks = getOrderedBlocks(blocks, context.headerBlockTypes);
34
36
  const themedBackground = getThemedValue(background, theme);
35
37
  return (React.createElement(InnerContext.Provider, { value: context },
36
38
  React.createElement("div", { className: b() },
@@ -1,5 +1,6 @@
1
1
  import React, { Fragment, useContext } from 'react';
2
2
  import _ from 'lodash';
3
+ import { BlockIdContext } from '../../../../context/blockIdContext';
3
4
  import { InnerContext } from '../../../../context/innerContext';
4
5
  import { getBlockKey } from '../../../../utils';
5
6
  import { ConstructorBlock } from '../ConstructorBlock/ConstructorBlock';
@@ -30,9 +31,9 @@ export const ConstructorBlocks = ({ items }) => {
30
31
  if ('children' in item && item.children) {
31
32
  children = item.children.map(renderer.bind(null, blockId));
32
33
  }
33
- itemElement = (React.createElement(ConstructorItem, { data: item, key: blockId, blockKey: blockId }, children));
34
+ itemElement = (React.createElement(ConstructorItem, { data: item, blockKey: blockId }, children));
34
35
  }
35
- return blockTypes.includes(item.type) ? (React.createElement(ConstructorBlock, { data: item, key: blockId }, itemElement)) : (itemElement);
36
+ return (React.createElement(BlockIdContext.Provider, { value: blockId, key: blockId }, blockTypes.includes(item.type) ? (React.createElement(ConstructorBlock, { data: item }, itemElement)) : (itemElement)));
36
37
  };
37
38
  return React.createElement(Fragment, null, items.map(renderer.bind(null, '')));
38
39
  };
@@ -3,5 +3,5 @@ export interface ConstructorItemProps {
3
3
  data: ConstructorItemType;
4
4
  blockKey: string;
5
5
  }
6
- export declare const ConstructorItem: ({ data, blockKey, children }: WithChildren<ConstructorItemProps>) => JSX.Element;
6
+ export declare const ConstructorItem: ({ data, children }: WithChildren<ConstructorItemProps>) => JSX.Element;
7
7
  export declare const ConstructorHeader: ({ data, blockKey, }: Pick<ConstructorItemProps, 'data' | 'blockKey'>) => JSX.Element;
@@ -1,12 +1,12 @@
1
1
  import { __rest } from "tslib";
2
2
  import React, { useContext } from 'react';
3
- import { BlockIdContext } from '../../../../context/blockIdContext';
4
3
  import { InnerContext } from '../../../../context/innerContext';
5
- export const ConstructorItem = ({ data, blockKey, children }) => {
4
+ import { BlockDecoration } from '../../../../customization/BlockDecoration';
5
+ export const ConstructorItem = ({ data, children }) => {
6
6
  const { itemMap } = useContext(InnerContext);
7
7
  const { type } = data, rest = __rest(data, ["type"]);
8
8
  const Component = itemMap[type];
9
- return (React.createElement(BlockIdContext.Provider, { value: blockKey },
10
- React.createElement(Component, Object.assign({}, rest), children)));
9
+ return React.createElement(Component, Object.assign({}, rest), children);
11
10
  };
12
- export const ConstructorHeader = ({ data, blockKey, }) => (React.createElement(ConstructorItem, { data: data, key: data.type, blockKey: blockKey }));
11
+ export const ConstructorHeader = ({ data, blockKey, }) => (React.createElement(BlockDecoration, { id: data.type },
12
+ React.createElement(ConstructorItem, { data: data, key: data.type, blockKey: blockKey })));
@@ -1,6 +1,6 @@
1
1
  import React from 'react';
2
2
  import { ItemMap } from '../../containers/PageConstructor/PageConstructor';
3
- import { LoadableConfig, ShouldRenderBlock } from '../../models';
3
+ import { CustomConfig, LoadableConfig, ShouldRenderBlock } from '../../models';
4
4
  export interface InnerContextType {
5
5
  blockTypes: string[];
6
6
  subBlockTypes: string[];
@@ -8,5 +8,6 @@ export interface InnerContextType {
8
8
  itemMap: ItemMap;
9
9
  loadables?: LoadableConfig;
10
10
  shouldRenderBlock?: ShouldRenderBlock;
11
+ customization?: Pick<CustomConfig, 'decorators'>;
11
12
  }
12
13
  export declare const InnerContext: React.Context<InnerContextType>;
@@ -0,0 +1,3 @@
1
+ import { PropsWithChildren } from 'react';
2
+ import { BlockDecorationProps } from '../models';
3
+ export declare const BlockDecoration: (props: PropsWithChildren<BlockDecorationProps>) => JSX.Element;
@@ -0,0 +1,17 @@
1
+ import React, { Fragment, useContext } from 'react';
2
+ import { BlockIdContext } from '../context/blockIdContext';
3
+ import { InnerContext } from '../context/innerContext';
4
+ import { getBlockIndexFromId } from '../utils';
5
+ export const BlockDecoration = (props) => {
6
+ var _a, _b;
7
+ const blockContenxtId = getBlockIndexFromId(useContext(BlockIdContext));
8
+ const { headerBlockTypes } = useContext(InnerContext);
9
+ const blockId = props.id || blockContenxtId;
10
+ const isHeader = Boolean(props.id && headerBlockTypes.includes(props.id));
11
+ const block = React.createElement(Fragment, null, props.children);
12
+ const blockDecorators = (_b = (_a = useContext(InnerContext).customization) === null || _a === void 0 ? void 0 : _a.decorators) === null || _b === void 0 ? void 0 : _b.block;
13
+ if (!blockDecorators) {
14
+ return block;
15
+ }
16
+ return blockDecorators.reduce((children, decorator) => (React.createElement(Fragment, null, decorator({ children, id: blockId, isHeader }))), block);
17
+ };
@@ -0,0 +1,82 @@
1
+ /* use this for style redefinitions to awoid problems with
2
+ unpredictable css rules order in build */
3
+ .pc-add-block {
4
+ position: fixed;
5
+ bottom: 32px;
6
+ left: 50%;
7
+ transform: translateX(-50%);
8
+ z-index: 110;
9
+ }
10
+ .pc-add-block__button {
11
+ display: inline-block;
12
+ margin: 0;
13
+ padding: 0;
14
+ font: inherit;
15
+ border: none;
16
+ outline: none;
17
+ color: inherit;
18
+ background: none;
19
+ cursor: pointer;
20
+ display: flex;
21
+ justify-content: center;
22
+ align-items: center;
23
+ transition: transform 0.2s;
24
+ width: 76px;
25
+ height: 40px;
26
+ color: var(--yc-color-text-inverted-primary);
27
+ background-color: var(--yc-color-promo-base-neon);
28
+ border-radius: 8px;
29
+ }
30
+ .pc-add-block__button:hover {
31
+ transform: scale(1.05);
32
+ }
33
+ .pc-add-block__icon {
34
+ width: 16px;
35
+ height: 16px;
36
+ }
37
+
38
+ .pc-add-block__popup {
39
+ min-width: 420px;
40
+ border-radius: var(--pc-border-radius);
41
+ box-shadow: 0px 2px 8px rgba(0, 0, 0, 0.06), 0px 4px 24px rgba(0, 0, 0, 0.06);
42
+ }
43
+ .pc-add-block__popup .pc-add-block__search {
44
+ padding: 20px 20px 0;
45
+ }
46
+ .pc-add-block__popup .pc-add-block__blocks {
47
+ display: flex;
48
+ flex-direction: column;
49
+ padding: 20px;
50
+ height: 296px;
51
+ max-height: 296px;
52
+ overflow-y: auto;
53
+ }
54
+ .pc-add-block__popup .pc-add-block__block {
55
+ display: flex;
56
+ justify-content: center;
57
+ align-items: center;
58
+ transition: transform 0.2s;
59
+ margin-top: 20px;
60
+ justify-content: flex-start;
61
+ cursor: pointer;
62
+ }
63
+ .pc-add-block__popup .pc-add-block__block:hover {
64
+ transform: scale(1.05);
65
+ }
66
+ .pc-add-block__popup .pc-add-block__block:first-child {
67
+ margin-top: 0;
68
+ }
69
+ .pc-add-block__popup .pc-add-block__preview {
70
+ width: 148px;
71
+ height: 74px;
72
+ border-radius: var(--pc-border-radius);
73
+ margin-right: 16px;
74
+ }
75
+ .pc-add-block__popup .pc-add-block__title {
76
+ font-size: var(--yc-text-body-2-font-size);
77
+ line-height: var(--yc-text-body-2-line-height);
78
+ }
79
+ .pc-add-block__popup .pc-add-block__title,
80
+ .pc-add-block__popup .pc-add-block__description {
81
+ margin: 0;
82
+ }
@@ -0,0 +1,8 @@
1
+ import { PropsWithChildren } from 'react';
2
+ import { Block } from '../../../models';
3
+ import './AddBlock.css';
4
+ export interface AddBlockProps {
5
+ onAdd: (data: Block) => void;
6
+ }
7
+ declare const AddBlock: ({ onAdd }: PropsWithChildren<AddBlockProps>) => JSX.Element;
8
+ export default AddBlock;
@@ -0,0 +1,41 @@
1
+ import React, { useMemo, useRef, useState } from 'react';
2
+ import { Plus } from '@gravity-ui/icons';
3
+ import { Popup, TextInput } from '@gravity-ui/uikit';
4
+ import { blockMap } from '../../../constructor-items';
5
+ import { block } from '../../../utils';
6
+ import EditorBlocksData from '../../data';
7
+ import './AddBlock.css';
8
+ const b = block('add-block');
9
+ const sortedBlockNames = Object.keys(blockMap).sort();
10
+ const AddBlock = ({ onAdd }) => {
11
+ const [isOpened, setIsOpened] = useState(false);
12
+ const [search, setSearch] = useState('');
13
+ const ref = useRef(null);
14
+ const blocks = useMemo(() => sortedBlockNames.filter((blockName) => EditorBlocksData[blockName].meta.title
15
+ .toLocaleLowerCase()
16
+ .startsWith(search.toLocaleLowerCase())), [search]);
17
+ return (React.createElement("div", { className: b(), ref: ref },
18
+ React.createElement("button", { className: b('button'), onClick: () => {
19
+ setIsOpened(!isOpened);
20
+ setSearch('');
21
+ } },
22
+ React.createElement(Plus, { className: b('icon') })),
23
+ isOpened && (React.createElement(Popup, { anchorRef: ref, open: isOpened, className: b('popup'), placement: "top", offset: [0, 24], onOutsideClick: () => setIsOpened(false) },
24
+ React.createElement("div", { className: b('search') },
25
+ React.createElement(TextInput, { placeholder: "search", type: "text", value: search, size: "l", onUpdate: (value) => setSearch(value) })),
26
+ React.createElement("div", { className: b('blocks') }, blocks.map((blockName) => {
27
+ var _a;
28
+ const blockData = EditorBlocksData[blockName];
29
+ const Preview = blockData === null || blockData === void 0 ? void 0 : blockData.preview;
30
+ return (React.createElement("div", { key: blockName, className: b('block'), onClick: () => {
31
+ onAdd(blockData === null || blockData === void 0 ? void 0 : blockData.template);
32
+ setIsOpened(false);
33
+ } },
34
+ React.createElement("div", { className: b('preview') },
35
+ React.createElement(Preview, null)),
36
+ React.createElement("div", { className: b('info') },
37
+ React.createElement("h4", { className: b('title') }, blockData.meta.title),
38
+ ((_a = blockData === null || blockData === void 0 ? void 0 : blockData.meta) === null || _a === void 0 ? void 0 : _a.description) && (React.createElement("p", { className: b('description') }, blockData.meta.description)))));
39
+ }))))));
40
+ };
41
+ export default AddBlock;
@@ -0,0 +1,47 @@
1
+ /* use this for style redefinitions to awoid problems with
2
+ unpredictable css rules order in build */
3
+ .pc-edit-block {
4
+ cursor: pointer;
5
+ position: relative;
6
+ }
7
+ .pc-edit-block__controls {
8
+ position: absolute;
9
+ width: calc(100% + 40px);
10
+ height: calc(100% + 40px);
11
+ top: -20px;
12
+ left: -20px;
13
+ border-radius: 8px;
14
+ z-index: 100;
15
+ }
16
+ .pc-edit-block__controls_isHeader {
17
+ width: 100%;
18
+ height: 100%;
19
+ top: 0;
20
+ left: 0;
21
+ }
22
+ .pc-edit-block__controls_active {
23
+ border: 4px solid var(--yc-color-promo-base-neon);
24
+ }
25
+ .pc-edit-block__controls-content {
26
+ display: flex;
27
+ position: absolute;
28
+ bottom: -44px;
29
+ left: 50%;
30
+ transform: translateX(-50%);
31
+ }
32
+ .pc-edit-block__control {
33
+ display: flex;
34
+ justify-content: center;
35
+ align-items: center;
36
+ transition: transform 0.2s;
37
+ width: 24px;
38
+ height: 24px;
39
+ border-radius: calc(8px / 2);
40
+ background-color: var(--yc-color-promo-highlight-neon);
41
+ }
42
+ .pc-edit-block__control:hover {
43
+ transform: scale(1.1);
44
+ }
45
+ .pc-edit-block__control:not(:first-child) {
46
+ margin-left: 12px;
47
+ }
@@ -0,0 +1,5 @@
1
+ import React from 'react';
2
+ import { EditBlockProps } from '../../../editor/types';
3
+ import './EditBlock.css';
4
+ declare const _default: React.MemoExoticComponent<({ id, isHeader, activeBlockId, onDelete, onSelect, onCopy, onOrderChange, children, orderedBlocksCount, }: EditBlockProps) => JSX.Element>;
5
+ export default _default;
@@ -0,0 +1,30 @@
1
+ import React, { Fragment, useEffect, useRef } from 'react';
2
+ import { ChevronDown, ChevronUp, Copy, TrashBin } from '@gravity-ui/icons';
3
+ import { block } from '../../../utils';
4
+ import './EditBlock.css';
5
+ const b = block('edit-block');
6
+ const EditBlock = ({ id, isHeader, activeBlockId, onDelete, onSelect, onCopy, onOrderChange, children, orderedBlocksCount, }) => {
7
+ const ref = useRef(null);
8
+ const controlsActive = activeBlockId === id;
9
+ useEffect(() => {
10
+ var _a;
11
+ if (controlsActive && ref.current) {
12
+ (_a = ref.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ behavior: 'smooth', block: 'center' });
13
+ }
14
+ }, [controlsActive]);
15
+ return (React.createElement("div", { className: b(), onClick: () => {
16
+ onSelect(id);
17
+ }, ref: ref },
18
+ React.createElement("div", { className: b('controls', { active: controlsActive, isHeader }) }, controlsActive && (React.createElement("div", { className: b('controls-content'), onClick: (e) => e.stopPropagation() },
19
+ typeof id === 'number' && (React.createElement(Fragment, null,
20
+ id > 0 && (React.createElement("div", { className: b('control'), onClick: () => onOrderChange(id, id - 1) },
21
+ React.createElement(ChevronUp, null))),
22
+ id < orderedBlocksCount - 1 && (React.createElement("div", { className: b('control'), onClick: () => onOrderChange(id, id + 1) },
23
+ React.createElement(ChevronDown, null))),
24
+ React.createElement("div", { className: b('control'), onClick: () => onCopy(id) },
25
+ React.createElement(Copy, null)))),
26
+ React.createElement("div", { className: b('control'), onClick: () => onDelete(id) },
27
+ React.createElement(TrashBin, null))))),
28
+ children));
29
+ };
30
+ export default React.memo(EditBlock);
@@ -0,0 +1,2 @@
1
+ import { EditorProps } from '../types';
2
+ export declare const Editor: ({ children, ...rest }: EditorProps) => JSX.Element;
@@ -0,0 +1,20 @@
1
+ import { __rest } from "tslib";
2
+ import React, { useMemo } from 'react';
3
+ import AddBlock from '../Components/AddBlock/AddBlock';
4
+ import EditBlock from '../Components/EditBlock/EditBlock';
5
+ import { useEditorState } from '../store';
6
+ import { addCustomDecorator } from '../utils';
7
+ export const Editor = (_a) => {
8
+ var { children } = _a, rest = __rest(_a, ["children"]);
9
+ const { content, onAdd, editControlsProps } = useEditorState(rest);
10
+ const constructorProps = useMemo(() => {
11
+ const editControlsDecorator = (props) => (React.createElement(EditBlock, Object.assign({}, props, editControlsProps)));
12
+ return {
13
+ content,
14
+ custom: addCustomDecorator(editControlsDecorator, rest.custom),
15
+ };
16
+ }, [editControlsProps, content, rest.custom]);
17
+ return (React.createElement("div", null,
18
+ children(constructorProps),
19
+ React.createElement(AddBlock, { onAdd: onAdd })));
20
+ };
@@ -0,0 +1,13 @@
1
+ /// <reference types="react" />
2
+ import { Block, BlockType } from '../../models';
3
+ export type PreviewComponent = React.FunctionComponent<React.SVGProps<SVGSVGElement>>;
4
+ export interface EdiorBlockData {
5
+ template: Block;
6
+ preview: PreviewComponent;
7
+ meta: {
8
+ title: string;
9
+ description?: string;
10
+ };
11
+ }
12
+ declare const EditorBlocksData: Record<BlockType, EdiorBlockData>;
13
+ export default EditorBlocksData;
@@ -0,0 +1,24 @@
1
+ import { BlockType } from '../../models';
2
+ import { formatBlockName } from '../utils';
3
+ import DefaultPreview from './previews/default-preview';
4
+ const getBlockTemplate = (blockType) => require(`./templates/${blockType}.json`);
5
+ const getBlockPreview = (blockType) => {
6
+ try {
7
+ return require(`./previews/${blockType}.tsx`).default;
8
+ }
9
+ catch (err) {
10
+ /*eslint-disable no-console */
11
+ console.warn(`Preview image for ${blockType} not found`);
12
+ return DefaultPreview;
13
+ }
14
+ };
15
+ const EditorBlocksData = Object.values(BlockType).reduce((previewData, blockType) => {
16
+ const template = getBlockTemplate(blockType);
17
+ const preview = getBlockPreview(blockType);
18
+ template.meta = template.meta || {};
19
+ template.meta.title = template.meta.title || formatBlockName(blockType);
20
+ /* eslint-disable no-param-reassign */
21
+ previewData[blockType] = Object.assign(Object.assign({}, template), { preview });
22
+ return previewData;
23
+ }, {});
24
+ export default EditorBlocksData;
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ declare const DefaultPreview: React.FC<React.SVGProps<SVGSVGElement>>;
3
+ export default DefaultPreview;
@@ -0,0 +1,15 @@
1
+ import React from 'react';
2
+ import { a11yHiddenSvgProps } from '../../../utils/svg';
3
+ const DefaultPreview = (props) => (React.createElement("svg", Object.assign({ width: "150", height: "76", viewBox: "0 0 150 76", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, a11yHiddenSvgProps, props),
4
+ React.createElement("rect", { x: "1", y: "1", width: "148", height: "74", rx: "8", fill: "white" }),
5
+ React.createElement("rect", { x: "14.7674", y: "21.6512", width: "28.3953", height: "6.88372", rx: "0.860465", fill: "#E7E7E7" }),
6
+ React.createElement("rect", { x: "43.1628", y: "21.6512", width: "28.3953", height: "6.88372", rx: "0.860465", fill: "white" }),
7
+ React.createElement("rect", { x: "14.7674", y: "31.9767", width: "56.7907", height: "3.44186", rx: "0.860465", fill: "#E7E7E7" }),
8
+ React.createElement("rect", { x: "14.7675", y: "37.1395", width: "56.7907", height: "3.44186", rx: "0.860465", fill: "#E7E7E7" }),
9
+ React.createElement("rect", { x: "14.7675", y: "42.3023", width: "56.7907", height: "3.44186", rx: "0.860465", fill: "#E7E7E7" }),
10
+ React.createElement("rect", { x: "14.7674", y: "49.186", width: "18.9302", height: "5.16279", rx: "0.860465", fill: "#E7E7E7" }),
11
+ React.createElement("rect", { x: "33.6977", y: "49.186", width: "18.9302", height: "5.16279", rx: "0.860465", fill: "white" }),
12
+ React.createElement("rect", { x: "52.6279", y: "49.186", width: "18.9302", height: "5.16279", rx: "0.860465", fill: "white" }),
13
+ React.createElement("rect", { x: "78.4418", y: "9.60464", width: "56.7907", height: "56.7907", rx: "5.16279", fill: "#A967FF" }),
14
+ React.createElement("rect", { x: "0.5", y: "0.5", width: "149", height: "75", rx: "8.5", stroke: "black", strokeOpacity: "0.1" })));
15
+ export default DefaultPreview;
@@ -0,0 +1,3 @@
1
+ import React from 'react';
2
+ declare const Header: React.FC<React.SVGProps<SVGSVGElement>>;
3
+ export default Header;
@@ -0,0 +1,16 @@
1
+ import React from 'react';
2
+ import { a11yHiddenSvgProps } from '../../../utils/svg';
3
+ const Header = (props) => (React.createElement("svg", Object.assign({ width: "150", height: "76", viewBox: "0 0 150 76", fill: "none", xmlns: "http://www.w3.org/2000/svg" }, a11yHiddenSvgProps, props),
4
+ React.createElement("rect", { x: "1", y: "1", width: "148", height: "74", rx: "8", fill: "white" }),
5
+ React.createElement("rect", { x: "4.44174", y: "9.60464", width: "141.116", height: "56.7907", rx: "5.16279", fill: "#A967FF" }),
6
+ React.createElement("rect", { x: "14.7674", y: "21.6512", width: "28.3953", height: "6.88372", rx: "0.860465", fill: "white" }),
7
+ React.createElement("rect", { x: "43.1628", y: "21.6512", width: "28.3953", height: "6.88372", rx: "0.860465", fill: "#A967FF" }),
8
+ React.createElement("rect", { x: "14.7674", y: "31.9767", width: "56.7907", height: "3.44186", rx: "0.860465", fill: "white" }),
9
+ React.createElement("rect", { x: "14.7674", y: "37.1395", width: "56.7907", height: "3.44186", rx: "0.860465", fill: "white" }),
10
+ React.createElement("rect", { x: "14.7674", y: "42.3023", width: "56.7907", height: "3.44186", rx: "0.860465", fill: "white" }),
11
+ React.createElement("rect", { x: "14.7674", y: "49.186", width: "18.9302", height: "5.16279", rx: "0.860465", fill: "white" }),
12
+ React.createElement("rect", { x: "33.6976", y: "49.186", width: "18.9302", height: "5.16279", rx: "0.860465", fill: "#A967FF" }),
13
+ React.createElement("rect", { x: "52.6279", y: "49.186", width: "18.9302", height: "5.16279", rx: "0.860465", fill: "#A967FF" }),
14
+ React.createElement("rect", { x: "78.4418", y: "9.60464", width: "56.7907", height: "56.7907", rx: "5.16279", fill: "#A967FF" }),
15
+ React.createElement("rect", { x: "0.5", y: "0.5", width: "149", height: "75", rx: "8.5", stroke: "black", strokeOpacity: "0.1" })));
16
+ export default Header;
@@ -0,0 +1,2 @@
1
+ export { Editor } from './Containers/Editor';
2
+ export * from './types';
@@ -0,0 +1,2 @@
1
+ export { Editor } from './Containers/Editor';
2
+ export * from './types';
@@ -0,0 +1,15 @@
1
+ import { Block } from '../../models';
2
+ import { EditorProps } from '../types';
3
+ export type EditorBlockId = number | string;
4
+ export declare function useEditorState({ content: intialContent, custom }: Omit<EditorProps, 'children'>): {
5
+ content: import("../../models").PageContent;
6
+ editControlsProps: {
7
+ activeBlockId: import("./reducer").EditorBlockId;
8
+ orderedBlocksCount: number;
9
+ onDelete: (id: EditorBlockId) => void;
10
+ onSelect: (id: EditorBlockId) => void;
11
+ onCopy: (index: number) => void;
12
+ onOrderChange: (oldIndex: number, newIndex: number) => void;
13
+ };
14
+ onAdd: (block: Block) => void;
15
+ };
@@ -0,0 +1,28 @@
1
+ import { useMemo, useReducer } from 'react';
2
+ import { HeaderBlockTypes } from '../../models';
3
+ import { getCustomHeaderTypes, getOrderedBlocks } from '../../utils';
4
+ import { ADD_BLOCK, COPY_BLOCK, DELETE_BLOCK, ORDER_BLOCK, SELECT_BLOCK, getReducer, } from './reducer';
5
+ import { addEditorProps } from './utils';
6
+ export function useEditorState({ content: intialContent, custom }) {
7
+ const headerBlockTypes = useMemo(() => [...HeaderBlockTypes, ...getCustomHeaderTypes(custom)], [custom]);
8
+ const reducer = useMemo(() => getReducer(headerBlockTypes), [headerBlockTypes]);
9
+ const [{ activeBlockId, content, orderedBlocksCount }, dispatch] = useReducer(reducer, {
10
+ activeBlockId: 0,
11
+ orderedBlocksCount: getOrderedBlocks(intialContent.blocks, headerBlockTypes).length,
12
+ content: addEditorProps(intialContent),
13
+ });
14
+ return useMemo(() => {
15
+ return {
16
+ content,
17
+ editControlsProps: {
18
+ activeBlockId,
19
+ orderedBlocksCount,
20
+ onDelete: (id) => dispatch({ type: DELETE_BLOCK, payload: id }),
21
+ onSelect: (id) => dispatch({ type: SELECT_BLOCK, payload: id }),
22
+ onCopy: (index) => dispatch({ type: COPY_BLOCK, payload: index }),
23
+ onOrderChange: (oldIndex, newIndex) => dispatch({ type: ORDER_BLOCK, payload: { oldIndex, newIndex } }),
24
+ },
25
+ onAdd: (block) => dispatch({ type: ADD_BLOCK, payload: block }),
26
+ };
27
+ }, [content, activeBlockId, orderedBlocksCount]);
28
+ }
@@ -0,0 +1,41 @@
1
+ import { Block, CustomConfig, PageContent } from '../../models';
2
+ export type EditorBlockId = number | string;
3
+ interface EditorState {
4
+ content: PageContent;
5
+ activeBlockId: EditorBlockId;
6
+ orderedBlocksCount: number;
7
+ custom?: CustomConfig;
8
+ }
9
+ interface OrderBlockParams {
10
+ oldIndex: number;
11
+ newIndex: number;
12
+ }
13
+ export declare const SELECT_BLOCK = "SELECT_BLOCK";
14
+ export declare const DELETE_BLOCK = "DELETE_BLOCK";
15
+ export declare const COPY_BLOCK = "COPY_BLOCK";
16
+ export declare const ADD_BLOCK = "ADD_BLOCK";
17
+ export declare const SET_REGION = "SET_REGION";
18
+ export declare const ORDER_BLOCK = "ORDER_BLOCK";
19
+ interface SelectBlock {
20
+ type: typeof SELECT_BLOCK;
21
+ payload: EditorBlockId;
22
+ }
23
+ interface DeleteBlock {
24
+ type: typeof DELETE_BLOCK;
25
+ payload: EditorBlockId;
26
+ }
27
+ interface CopyBlock {
28
+ type: typeof COPY_BLOCK;
29
+ payload: number;
30
+ }
31
+ interface AddBlock {
32
+ type: typeof ADD_BLOCK;
33
+ payload: Block;
34
+ }
35
+ interface OrderBlock {
36
+ type: typeof ORDER_BLOCK;
37
+ payload: OrderBlockParams;
38
+ }
39
+ export type EditorAction = SelectBlock | DeleteBlock | CopyBlock | AddBlock | OrderBlock;
40
+ export declare const getReducer: (headerBlockTypes: string[]) => (state: EditorState, action: EditorAction) => EditorState;
41
+ export {};