feat: added page-constructor extension#1096
Merged
separatrixxx merged 13 commits intomainfrom Apr 25, 2026
Merged
Conversation
Reviewer's GuideAdds a new standalone @gravity-ui/markdown-editor-page-constructor-extension package that defines a YFM Page Constructor node/spec, React-based node view with live preview and editing, toolbar integration, split-mode preview HOC, and wires the package into the monorepo tooling (linting, build, tests, and release-please). File-Level Changes
Tips and commandsInteracting with Sourcery
Customizing Your ExperienceAccess your dashboard to:
Getting Help
|
There was a problem hiding this comment.
Hey - I've found 2 issues, and left some high level feedback:
- The toolbar item calls
e.actions.createYfmPageConstructor.isActive(), but the correspondingActionSpec(addYfmPageConstructor) doesn’t define anisActiveimplementation, so at runtime this may beundefined; either implement anisActivehandler or stop wiring it through the toolbar item. useYfmPageConstructorRuntimeperforms a dynamic import on every render of the HOC instead of in an effect, which can cause unnecessary work; consider wrapping the import inuseEffect(oruseEffectOnce) inside the hook so the runtime is loaded only once per mount.
Prompt for AI Agents
Please address the comments from this code review:
## Overall Comments
- The toolbar item calls `e.actions.createYfmPageConstructor.isActive()`, but the corresponding `ActionSpec` (`addYfmPageConstructor`) doesn’t define an `isActive` implementation, so at runtime this may be `undefined`; either implement an `isActive` handler or stop wiring it through the toolbar item.
- `useYfmPageConstructorRuntime` performs a dynamic import on every render of the HOC instead of in an effect, which can cause unnecessary work; consider wrapping the import in `useEffect` (or `useEffectOnce`) inside the hook so the runtime is loaded only once per mount.
## Individual Comments
### Comment 1
<location path="packages/page-constructor-extension/src/YfmPageConstructorNodeView/YfmPageConstructorView.tsx" line_range="117-118" />
<code_context>
+ const [menuOpen, , closeMenu, toggleMenuOpen] = useBooleanState(false);
+
+ // Local state mirrors ProseMirror attribute; updates preview optimistically
+ const [content, setContent] = useState(
+ () => node.attrs[YfmPageConstructorConsts.NodeAttrs.content] || '',
+ );
+
</code_context>
<issue_to_address>
**issue (bug_risk):** Local `content` state can diverge from ProseMirror node attrs and never resync on external updates.
`content` is only initialised from `node.attrs[...]` and then updated via `handleChange`, so if `node.attrs` changes externally (e.g. collaborative edits or other transactions), the component rerenders with a new `node` but keeps the old `content`, leaving the preview stale. Consider syncing `content` from `node.attrs` whenever you’re not editing, e.g. via a `useEffect` that watches `node.attrs[content]` and `editing` and updates local state only when `editing === false`.
</issue_to_address>
### Comment 2
<location path="packages/page-constructor-extension/src/hocs/withYfmPageConstructor/useYfmPageConstructorRuntime.ts" line_range="2-4" />
<code_context>
+/** @internal */
+export function useYfmPageConstructorRuntime() {
+ import(
+ /* webpackChunkName: "page-constructor-runtime" */ '@diplodoc/page-constructor-extension/runtime'
+ );
+}
</code_context>
<issue_to_address>
**suggestion (performance):** The dynamic import inside the hook body runs on every render, which is unnecessary work.
Calling `import()` unconditionally in the hook body means it runs on every render, creating a new (ignored) promise each time. Even if the browser dedupes the actual chunk load, this is avoidable overhead and can trip unhandled-promise lint rules.
Consider moving the `import()` into an effect so it runs once per mount, e.g. `useEffectOnce(() => { void import(...); });`, which preserves lazy loading without repeated calls.
</issue_to_address>Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.
makhnatkin
reviewed
Apr 23, 2026
Collaborator
|
Please also add a demo story for this PR |
d3m1d0v
reviewed
Apr 24, 2026
d3m1d0v
reviewed
Apr 24, 2026
d3m1d0v
reviewed
Apr 25, 2026
8301477 to
6eb3662
Compare
d3m1d0v
approved these changes
Apr 25, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Creating a page-constructor extension in a separate package
Summary by Sourcery
Add a new page-constructor extension package for the markdown editor, including schema, node view, actions, toolbar integration, and preview support, and wire it into the monorepo tooling and release configuration.
New Features:
Enhancements:
Documentation:
Tests: