@gravity-ui/page-constructor ·
![storybook](https://img.shields.io/badge/Storybook-deployed-ff4685)
Install
npm install @gravity-ui/page-constructor
Page constructor
Page-constructor
is a library for rendering web pages or their parts based on JSON
data (support for YAML
format is to be added later).
When creating pages, component-based approach is used: a page is built using a set of ready-made blocks that can be placed in any order. Each block has a certain type and set of input data parameters.
For the format of input data and list of available blocks, see the documentation.
Getting started
The page constructor is imported as a React component. To make sure it runs properly, wrap it in PageConstructorProvider
:
import {PageConstructor, PageConstructorProvider} from '@gravity-ui/page-constructor';
const Page: WithChildren<PageProps> = ({content}) => (
<PageConstructorProvider>
<PageConstructor content={content} />
</PageConstructorProvider>
);
Parameters
interface PageConstructorProps {
content: PageContent;
shouldRenderBlock?: ShouldRenderBlock;
custom?: Custom;
renderMenu?: () => React.ReactNode;
}
interface PageConstructorProviderProps {
isMobile?: boolean;
locale?: LocaleContextProps;
location?: Location;
metrika?: Metrika;
ssrConfig?: SSR;
theme?: 'light' | 'dark';
}
export interface PageContent extends Animatable {
blocks: Block[];
menu?: Menu;
background?: MediaProps;
footnotes?: string[];
}
interface Custom {
blocks?: CustomItems;
subBlocks?:CustomItems;
headers?: CustomItems;
loadable?: LoadableConfig;
}
type ShouldRenderBlock = (block: Block, blockKey: string) => Boolean;
interface Location = {
history?: History;
search?: string;
hash?: string;
pathname?: string;
hostname?: string;
};
interface Locale = {
lang?: Lang;
tld?: string;
};
interface SSR = {
isServer?: boolean;
}
interface Metrika = {
metrika?: any;
pixel?: any;
}
Custom blocks
The page constructor lets you use blocks that are user-defined in their app. Blocks are regular React components.
To pass custom blocks to the constructor:
-
Create a block in your app.
-
In your code, create an object with the block type (string) as a key and an imported block component as a value.
-
Pass the object you created to the custom.blocks
, custom.headers
or custom.subBlocks
parameter of the PageConstructor
component (custom.headers
specifies the block headers to be rendered separately above general content).
-
Now you can use the created block in input data (the content
parameter) by specifying its type and data.
To use mixins and constructor style variables when creating custom blocks, add import in your file:
@import '~@gravity-ui/page-constructor/styles/styles.scss';
Loadable blocks
It's sometimes necessary that a block renders itself based on data to be loaded. In this case, loadable blocks are used.
To add custom loadable
blocks, pass to the PageConstructor
the custom.loadable
property with data source names (string) for the component as a key and an object as a value.
export interface LoadableConfigItem {
fetch: FetchLoadableData;
component: React.ComponentType;
}
type FetchLoadableData<TData = any> = (blockKey: string) => Promise<TData>;
Grid
The page constructor uses the bootstrap
grid and its implementation based on React components that you can use in your own project (including separately from the constructor).
Usage example:
import {Grid, Row, Col} from '@gravity-ui/page-constructor/';
const Page: React.FC<PageProps> = ({children}) => (
<Grid>
<Row>
<Col sizes={{lg: 4, sm: 6, all: 12}}>{children}</Col>
</Row>
</Grid>
);
Blocks
Each block is an atomic top-level component. They're stored in the src/units/constructor/blocks
directory.
Sub-blocks
Sub-blocks are components that can be used in the block children
property. In a config, a list of child components from sub-blocks is specified. Once rendered, these sub-blocks are passed to the block as children
.
How to add a new block to the page-constructor
-
In the src/blocks
or src/sub-blocks
directory, create a folder with the block or sub-block code.
-
Add the block or sub-block name to enum BlockType
orSubBlockType
and describe its properties in the src/models/blocks.ts
or src/models/sub-blocks.ts
file in a similar way to the existing ones.
-
Add export for the block in the src/blocks/index.ts
file and for the sub-block in the src/sub-blocks/index.ts
file.
-
Add a new component or block to mapping in src/constructor-items.ts
.
-
Add a validator for the new block:
- Add a
schema.ts
file to the block or sub-block directory. In this file, describe a parameter validator for the component in json-schema
format. - Export it in the
schema/validators/blocks.ts
or schema/validators/sub-blocks.ts
file. - Add it to
enum
or selectCases
in the schema/index.ts
file.
-
In the block directory, add the README.md
file with a description of input parameters.
-
In the block directory add storybook demo in __stories__
folder. (All demo content for story should be placed in data.json
at story dir)
Themes
The PageConstructor
lets you use themes: you can set different values for individual block properties depending on the theme selected in the app.
To add a theme to a block property:
-
In the models/blocks.ts
file, define the type of the respective block property using the ThemeSupporting<T>
generic, where T
is the type of the property.
-
In the file with the block's react
component, get the value of the property with the theme via getThemedValue
and ThemeValueContext
(see examples in the Banner.tsx
block).
-
Add theme support to the property validator: in the block's schema.ts
file, wrap this property in withTheme
.
i18n
To make sure the i18n library used in your project runs properly, perform its initialization and set the project's current locale value in lang
. For example:
import {configure, Lang} from '@gravity-ui/page-constructor';
configure({lang: Lang.En});
Development
npm ci
npm run dev