Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
125 commits
Select commit Hold shift + click to select a range
911af01
feat: experimental Editor functionality
Oct 4, 2024
d316c6c
feat: add yaml support for editor v2
Oct 12, 2024
5ea3e09
feat: add zoom support for editor v2
Oct 15, 2024
f94f342
feat: add groups, block buttons and panel open button
Nov 2, 2024
9d2f5d5
feat: add PostMessage API and Synchronized store
Feb 3, 2025
4f99954
feat: add PostMessage API and Synchronized store
DaffPunks Feb 3, 2025
b548f21
fix: rework state, fix listeners
DaffPunks Feb 13, 2025
3b3c219
fix: refactor common, store and hooks
DaffPunks Feb 21, 2025
7df0a1b
refactor: distinct editor v2, add components config
qradle-yndx Mar 4, 2025
91fa72e
fix: common imports
qradle-yndx Mar 9, 2025
afdd411
fix: overlay css
qradle-yndx Mar 9, 2025
336a7d5
feat: tree selected block style
qradle-yndx Mar 9, 2025
c60d470
feat: editor global config navigation
qradle-yndx Mar 10, 2025
e47cf30
feat: editor tree tab
qradle-yndx Mar 10, 2025
b9910d2
fix: editor blocks previews
qradle-yndx Mar 10, 2025
7a93fb2
feat: editor tree controls
qradle-yndx Mar 11, 2025
11a4f15
feat: editor source yaml json controls
qradle-yndx Mar 11, 2025
f02154e
fix: editor right tabs lvl
qradle-yndx Mar 11, 2025
8ec78f6
feat: editor blocks search input
qradle-yndx Mar 12, 2025
563b9c4
fix: editor containers imports
qradle-yndx Mar 12, 2025
d3fb219
fix: pc item path id array for editor
qradle-yndx Mar 12, 2025
2fc2e45
fix: prettier
qradle-yndx Mar 14, 2025
6910d33
fix: update react imports for linter
qradle-yndx Mar 14, 2025
c5c738b
fix: lint errors
qradle-yndx Mar 15, 2025
a9696c5
feat: add device switcher
qradle-yndx Mar 28, 2025
92806a7
fix: ai refactor viewswitches
qradle-yndx Mar 31, 2025
37b3d16
feat: add c9r top component
qradle-yndx Mar 31, 2025
8128703
feat: editor tree selection
qradle-yndx Mar 31, 2025
23c8c24
feat: editor tree dnd
qradle-yndx Mar 31, 2025
2954c67
fix: update editor block config styles
qradle-yndx Apr 1, 2025
b32261b
fix: update selected block borders
qradle-yndx Apr 2, 2025
09ba739
fix: remove unused hook
qradle-yndx Apr 2, 2025
dc8a470
fix: remove block selection from click event
qradle-yndx Apr 2, 2025
de7fb47
feat: add scroll to selected block
qradle-yndx Apr 3, 2025
da9795b
feat: add scroll to selected block in the Tree component
qradle-yndx Apr 3, 2025
4e615f2
fix: selected block after blocks reorder
qradle-yndx Apr 3, 2025
13ab234
fix: refactor pc editor events
qradle-yndx Apr 3, 2025
26c5ba6
feat: unselect block on deletion
qradle-yndx Apr 3, 2025
048e1ba
fix: eslint
qradle-yndx Apr 4, 2025
f90dc9b
fix: return editor-v2 back to src
qradle-yndx Apr 7, 2025
5df335d
fix: eslint
qradle-yndx Apr 7, 2025
3ec3406
fix: editor for radiobutton
qradle-yndx Apr 7, 2025
3c6521f
feat: update styles for Overlay
DaffPunks Apr 8, 2025
b65d68f
fix: build
qradle-yndx Apr 7, 2025
ba4307c
fix: styles for dark theme
qradle-yndx Apr 7, 2025
897b768
fix: update editor-v2 exports
qradle-yndx Apr 7, 2025
f2159fb
fix: editor blocks styles
qradle-yndx Apr 8, 2025
d3f8532
fix: title style editor source code
qradle-yndx Apr 8, 2025
3fce385
fix: editor root styles
qradle-yndx Apr 8, 2025
e161a01
fix: brand colors
qradle-yndx Apr 9, 2025
e17c428
fix: editor zoom device centering
qradle-yndx Apr 9, 2025
61ec833
fix: restore editor refresh fields
qradle-yndx Apr 9, 2025
706c9cc
fix: paddings
qradle-yndx Apr 9, 2025
e84c135
fix: root css
qradle-yndx Apr 9, 2025
eec4375
fix: editor add initialContent
qradle-yndx Apr 15, 2025
e2e2991
fix: eslint disable
qradle-yndx Apr 16, 2025
2e58203
fix: json/yaml tab for selected block
qradle-yndx Apr 28, 2025
7b7479c
fix: add anyof case for editorv2
qradle-yndx Apr 28, 2025
a8bc181
fix: navigation item props
qradle-yndx Apr 28, 2025
1519e09
feat: add previewMode for editor
qradle-yndx Apr 29, 2025
8dcbbd8
fix: linter
qradle-yndx Apr 29, 2025
4ed9bb9
fix: linter2
qradle-yndx Apr 29, 2025
e59a37b
fix: filter editor blocks
qradle-yndx May 5, 2025
d826e1f
fix: ui review fixes
qradle-yndx May 14, 2025
ff46828
feat: update playground, add form builder
DaffPunks Jun 9, 2025
be0ba5d
feat: update UI styles, fix bugs
DaffPunks Jul 14, 2025
6eb8e02
feat: extract form-generator
DaffPunks Aug 12, 2025
d4ce061
fix: fix eslint warnings
DaffPunks Aug 12, 2025
d5dc5ba
fix: remove TestEditorBlock styles
DaffPunks Aug 12, 2025
8349968
feat: update package.json exports
DaffPunks Aug 12, 2025
f8348c5
fix: use @bem-react/classname in PC Form Generator
DaffPunks Aug 12, 2025
f6a09cf
feat: separate form-builder and form-generator
DaffPunks Aug 13, 2025
50b12e7
feat: update blocks importing
DaffPunks Mar 16, 2026
d4dfeb3
fix: rebase fixes
DaffPunks Mar 16, 2026
b5f7d83
feat: add cmd+z to revert changes (#1402)
niktverd Mar 31, 2026
a8c2b34
feat: new form-generator (#1391)
aeksandla Mar 31, 2026
5898ba9
fix: fullscreen mode, switch device mode, replace native dnd on dnd-k…
Valent1325 Apr 17, 2026
5585bc3
feat: update editor and form-generator
DaffPunks Apr 19, 2026
1723dca
feat: rework overlay
DaffPunks Apr 20, 2026
54ba37d
feat: rework folders
DaffPunks Apr 20, 2026
2257ce8
feat: few fixes and new playground example
DaffPunks Apr 22, 2026
6017093
feat: update exports and fix linter
DaffPunks Apr 23, 2026
c0082b7
Merge branch 'main' into alpha/editor-feature
DaffPunks Apr 23, 2026
c8893d8
feat: fix lint errors
DaffPunks Apr 23, 2026
a990318
fix: fix lint errors
DaffPunks Apr 23, 2026
8c489da
8.5.0-alpha.0
gravity-ui-bot Apr 23, 2026
2cbd4c6
Merge remote-tracking branch 'origin/main' into alpha/editor-feature
aeksandla Apr 23, 2026
69dfa1c
fix build command
aeksandla Apr 23, 2026
3ba8d7b
Merge remote-tracking branch 'origin/main' into alpha/editor-feature
aeksandla Apr 23, 2026
102759c
Merge branch 'main' into alpha/editor-feature
aeksandla Apr 23, 2026
1911d23
fix: change icons import and postMessage directive
DaffPunks Apr 24, 2026
0870d80
8.5.0-alpha.1
gravity-ui-bot Apr 24, 2026
b35e96f
feat: fix height calculation with ON_RESIZE event
DaffPunks Apr 24, 2026
7e40da0
8.5.0-alpha.2
gravity-ui-bot Apr 24, 2026
69cdaf0
Merge branch 'main' into alpha/editor-feature
aeksandla Apr 27, 2026
49cdca7
Merge branch 'main' into alpha/editor-feature
aeksandla Apr 27, 2026
50c329c
chore: fix preview build (#1428)
aeksandla May 4, 2026
261529b
feat: new form-builder (#1437)
PelaFad May 4, 2026
8cb75bb
8.5.0-alpha.3
gravity-ui-bot May 4, 2026
2d11ffd
fix: change form-builder v2
May 4, 2026
3c2dde4
8.5.0-alpha.4
gravity-ui-bot May 4, 2026
acdeb35
refactor: add export form-generator-v2 (#1440)
PelaFad May 5, 2026
7448bd1
8.5.0-alpha.5
gravity-ui-bot May 5, 2026
bf45504
feat: add source to postMessage
DaffPunks May 12, 2026
8d300c6
8.5.0-alpha.6
gravity-ui-bot May 12, 2026
9f73c1a
feat: add blockbase fix for header-block
DaffPunks May 14, 2026
0c1a115
8.5.0-alpha.8
gravity-ui-bot May 14, 2026
fd04e7e
8.5.0-alpha.9
gravity-ui-bot May 14, 2026
22c6488
fix: items and items-wrap height fix
DaffPunks May 15, 2026
8dbebf7
feat: add for all blocks imports and schema
DaffPunks May 15, 2026
36d1b3f
fix: change BlockBaseExt rules
DaffPunks May 15, 2026
665a476
fix: fix Banner and CardLayout grid-row layout
DaffPunks May 15, 2026
a98a082
feat: add Iframe maximum height limit
DaffPunks May 15, 2026
4c14b13
8.5.0-alpha.10
gravity-ui-bot May 15, 2026
5d7f37b
feat: add form-generator for all block stories
DaffPunks May 15, 2026
c0692ef
feat: add hotkey for fullscreen mode exit
DaffPunks May 21, 2026
1b67c20
fix: update GravityBlocksExt params
DaffPunks May 21, 2026
8ef7a5d
8.5.0-alpha.11
gravity-ui-bot May 21, 2026
fa6eaf3
fix: middlescreen lint fixed
DaffPunks May 21, 2026
ee4d725
8.5.0-alpha.12
gravity-ui-bot May 21, 2026
490a5d8
fix: fix form generator after review (#1434)
aeksandla May 21, 2026
0c9a889
Merge remote-tracking branch 'origin/main' into alpha/editor-feature
aeksandla Jun 8, 2026
0a2322d
Update package.lock
aeksandla Jun 8, 2026
18bb3db
fix: editor design fixes (#1469)
aeksandla Jun 11, 2026
0cdb65a
fix: page switch (#1470)
aeksandla Jul 10, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
3 changes: 3 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ node_modules
/coverage
/widget
/schema
/playground/dist

/playwright/playwright/.cache/
playwright
/playwright-report
/scripts
5 changes: 5 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -34,3 +34,8 @@ playwright-report*
# Skill eval artifacts (workspaces are local-only test outputs)
.agents/skills/*-workspace/
.claude/skills/*-workspace/

# Playground
/playground/node_modules
/playground/.next
/playground/.env
6 changes: 5 additions & 1 deletion .prettierignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,12 @@ CONTRIBUTING.md
/widget
/schema


/playwright/playwright/.cache/
playwright

# npm files
package.json
package.json

# Playground
/playground/.next
3 changes: 3 additions & 0 deletions .storybook/addons/form-addon/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const ADDON_ID = 'formaddon';
export const TOOL_ID = `${ADDON_ID}/tool`;
export const GLOBAL_KEY = 'formAddon';
9 changes: 9 additions & 0 deletions .storybook/addons/form-addon/preset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
function managerEntries(entry: string[] = []) {
return [...entry, require.resolve('./register')];
}

function previewAnnotations(entry: string[] = []) {
return [...entry, require.resolve('./preview')];
}

module.exports = {managerEntries, previewAnnotations};
67 changes: 67 additions & 0 deletions .storybook/addons/form-addon/preview.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
import * as React from 'react';

import {ThemeProvider} from '@gravity-ui/uikit';
import {useArgs} from '@storybook/preview-api';
import {Decorator} from '@storybook/react';

import FormGenerator from '../../../src/form-generator-v2/FormGenerator';
import type {Fields} from '../../../src/form-generator-v2/types';

import {GLOBAL_KEY} from './constants';

export const withFormAddon: Decorator = (Story, context) => {
const [args, updateArgs] = useArgs();
const inputs = context.parameters.inputs as Fields | undefined;
const isActive = Boolean(context.globals[GLOBAL_KEY]);

if (!isActive || !inputs) {
return <Story />;
}

return (
<ThemeProvider theme="dark">
<div style={{display: 'flex', alignItems: 'flex-start', width: '100%'}}>
<div
style={{
flex: 1,
position: 'sticky',
top: 0,
marginLeft: 'var(--g-spacing-4)',
paddingTop: 'var(--g-spacing-4)',
}}
>
<Story />
</div>
<div
style={{
width: 420,
flexShrink: 0,
border: '1px solid var(--g-color-line-generic)',
borderRadius: 'var(--g-border-radius-m)',
margin: 'var(--g-spacing-4)',
}}
>
<h4
style={{
padding: 'var(--g-spacing-4) var(--g-spacing-3)',
fontFamily: 'var(--g-text-subheader-font-family)',
fontWeight: 'var(--g-text-subheader-font-weight)',
fontSize: 'var(--g-text-subheader-3-font-size)',
lineHeight: 'var(--g-text-subheader-3-line-height)',
margin: 0,
}}
>
Form
</h4>
<FormGenerator
blockConfig={inputs}
contentConfig={args}
onUpdate={updateArgs}
/>
</div>
</div>
</ThemeProvider>
);
};

export const decorators = [withFormAddon];
55 changes: 55 additions & 0 deletions .storybook/addons/form-addon/register.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import * as React from 'react';

import {IconButton} from '@storybook/components';
import {EditIcon} from '@storybook/icons';
import {addons, types, useGlobals} from '@storybook/manager-api';
const STORY_PREPARED = 'storyPrepared';
const STORY_CHANGED = 'storyChanged';

import {ADDON_ID, GLOBAL_KEY, TOOL_ID} from './constants';

addons.register(ADDON_ID, () => {
addons.add(TOOL_ID, {
type: types.TOOL,
title: 'Form editor',
render: () => <FormTool />,
});
});

function FormTool() {
const [globals, updateGlobals] = useGlobals();
const isActive = Boolean(globals[GLOBAL_KEY]);
const [hasInputs, setHasInputs] = React.useState(false);

React.useEffect(() => {
const channel = addons.getChannel();

const onPrepared = ({parameters}: {parameters: Record<string, unknown>}) => {
setHasInputs(Boolean(parameters?.inputs));
};

const onChanged = () => setHasInputs(false);

channel.on(STORY_PREPARED, onPrepared);
channel.on(STORY_CHANGED, onChanged);

return () => {
channel.off(STORY_PREPARED, onPrepared);
channel.off(STORY_CHANGED, onChanged);
};
}, []);

if (!hasInputs) {
return null;
}

return (
<IconButton
active={isActive}
title="Toggle form editor"
onClick={() => updateGlobals({[GLOBAL_KEY]: !isActive})}
>
<EditIcon />
</IconButton>
);
}
13 changes: 13 additions & 0 deletions .storybook/addons/result-addon/AddonResult.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
.result-addon {
padding: 11px;
}

.result-addon pre {
margin: 10px 0 0;
padding: 0;
}

.result-addon__empty {
opacity: 0.5;
font-style: italic;
}
3 changes: 3 additions & 0 deletions .storybook/addons/result-addon/constants.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export const ADDON_ID = 'resultaddon';
export const PANEL_ID = `${ADDON_ID}/panel`;
export const EVENT_ID = `${ADDON_ID}/update`;
5 changes: 5 additions & 0 deletions .storybook/addons/result-addon/preset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
function managerEntries(entry: string[] = []) {
return [...entry, require.resolve('./register')];
}

module.exports = {managerEntries};
46 changes: 46 additions & 0 deletions .storybook/addons/result-addon/register.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import * as React from 'react';
import {AddonPanel} from '@storybook/components';
import {addons, types, useChannel, useGlobals} from '@storybook/manager-api';
import {ClipboardButton, ThemeProvider} from '@gravity-ui/uikit';

import {ADDON_ID, EVENT_ID, PANEL_ID} from './constants';

import './AddonResult.css';

const ResultPanel = () => {
const [globals] = useGlobals();
const [content, setContent] = React.useState<unknown>(null);

useChannel({
[EVENT_ID]: (value: unknown) => {
setContent(value);
},
});

const json = React.useMemo(
() => (content !== null ? JSON.stringify(content, null, 2) : ''),
[content],
);

return (
<ThemeProvider theme={globals.theme}>
<div className="result-addon">
{json ? <ClipboardButton text={json} /> : null}
<pre>{json || <span className="result-addon__empty">No data yet</span>}</pre>
</div>
</ThemeProvider>
);
};

addons.register(ADDON_ID, () => {
addons.add(PANEL_ID, {
type: types.PANEL,
title: 'Result',
paramKey: 'resultPanel',
render: ({active, key}) => (
<AddonPanel active={Boolean(active)} key={key}>
<ResultPanel />
</AddonPanel>
),
});
});
32 changes: 32 additions & 0 deletions .storybook/addons/result-addon/useResultPanel.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import * as React from 'react';
import {useChannel} from '@storybook/preview-api';

import {EVENT_ID} from './constants';

/**
* Drop-in replacement for useState that also mirrors the value to the Result panel.
*
* Usage in a story:
* const [content, setContent] = useResultPanel<Content>({});
*/
export function useResultPanel<T>(initial: T): [T, (value: T) => void] {
const [value, setValue] = React.useState<T>(initial);

const emit = useChannel({});

const update = React.useCallback(
(next: T) => {
setValue(next);
emit(EVENT_ID, next);
},
[emit],
);

// Emit initial value so the panel is not empty on first render.
React.useEffect(() => {
emit(EVENT_ID, initial);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);

return [value, update];
}
6 changes: 2 additions & 4 deletions .storybook/decorators/docs/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import * as React from 'react';
import {ThemeProvider} from '@gravity-ui/uikit';

import {themes} from '../../theme';
import {MobileContext} from '../../../src/context/mobileContext';

import {cn} from '../../../src/utils/cn';

import './DocsDecorator.scss';
Expand All @@ -20,9 +20,7 @@ export function DocsDecorator({children, context}: DocsDecoratorProps) {
return (
<div className={b()}>
<DocsContainer context={context} theme={themes[theme as 'dark' | 'light']}>
<ThemeProvider theme={theme}>
<MobileContext.Provider value={false}>{children}</MobileContext.Provider>
</ThemeProvider>
<ThemeProvider theme={theme}>{children}</ThemeProvider>
</DocsContainer>
</div>
);
Expand Down
6 changes: 1 addition & 5 deletions .storybook/decorators/withPageConstructorProvider.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,7 @@ import {PageConstructorProvider} from '../../src/containers/PageConstructor/Prov

export const withPageConstructorProvider: Decorator = (Story, context) => {
return (
<PageConstructorProvider
isMobile={context.globals.platform === 'mobile'}
locale={{lang: context.globals.lang}}
theme={context.globals.theme}
>
<PageConstructorProvider>
<Story {...context} />
</PageConstructorProvider>
);
Expand Down
2 changes: 2 additions & 0 deletions .storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ const config = {
},
},
'./addons/yaml-addon/preset',
'./addons/result-addon/preset',
'./addons/form-addon/preset',
'./addons/theme-addon/register.tsx',
'@storybook/addon-mdx-gfm',
'@storybook/addon-webpack5-compiler-babel',
Expand Down
5 changes: 5 additions & 0 deletions .storybook/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ const preview: Preview = {
decorators: [withLang, withMobile, withContextProvider, withPageConstructorProvider],

parameters: {
inputs: {disable: true},
resultPanel: {disable: true},
layout: 'fullscreen',
docs: {
theme: themeLight,
Expand Down Expand Up @@ -55,6 +57,9 @@ const preview: Preview = {
},

globalTypes: {
formAddon: {
defaultValue: false,
},
theme: {
name: 'Theme',
description: 'Global theme for components',
Expand Down
2 changes: 1 addition & 1 deletion .storybook/utils.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import yfm from '@diplodoc/transform';
import {ConstructorBlock} from '../src';
import {contentTransformer} from '../src/text-transform';
import {contentTransformer} from '../src/gravity-blocks/text-transform';

export const yfmTransform = (content: string) => yfm(content).result.html;

Expand Down
32 changes: 31 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -540,7 +540,7 @@ If you want to release a new version in previous major after commit it to the ma
7. Check your changes in CHANGELOG.md and approve robot's PR.
8. Squash and merge PR. You can see release process on [the Actions tab](https://github.com/gravity-ui/page-constructor/actions).

## Page constructor editor
## Page Constructor Editor v1

Editor provides user interface for page content management with realtime preview.

Expand Down Expand Up @@ -593,6 +593,36 @@ When working with AI agents on this project, the Memory Bank serves as a compreh

AI agents can read these files to quickly get up to speed with the project context and make more informed decisions about code changes and implementations.

## Page Constructor Editor v2

Editor provides user interface for page content management with realtime preview.

Based on Iframe postMessage communication.

How to use:

```tsx
import {Editor} from '@gravity-ui/page-constructor/editor-v2';

export const MyAppEditor = ({initialContent, onUpdate, disableUrlField}: MyAppEditorProps) => (
<Editor
initialUrl={'https://url-to-page-with-page-constructor.com'}
content={initialContent}
disableUrlField={disableUrlField}
onUpdate={onUpdate}
/>
);
```

### How to develop

```shell
npm run deps:install
npm run dev:playground
```

Directory `/playground` contains NextJS service with integrated PC and Editor for development purposes.

## Tests

Comprehensive documentation is available at the provided [link](./test-utils/docs/README.md).
Loading