feat: add experimental YFM HTML Constructor extension#1152
Draft
makhnatkin wants to merge 62 commits into
Draft
Conversation
Reviewer's GuideIntroduces a new experimental GridBlockTemplates extension that defines a ProseMirror atom node, React-based NodeView UI, HTML serialization, and localStorage-backed template parsing/storage, plus Storybook demo and tests. File-Level Changes
|
…locks Replace native HTML5 drag with a pointer-based drag handle so reordering works reliably over preview HTML; make the handle visible above block content (z-index, float background, touch-action: none). Keep user-entered raw HTML verbatim inside the block instead of unwrapping its root element, so a pasted <div>text</div> stays as <div class="block-N"><div>text</div></div> on serialization. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Add a second textarea in the container gear popup for free-form CSS rules
with selectors (.grid {}, .block-1 {}). Rules are scoped to the grid
instance so they never leak to other grids, applied live in the preview
and serialized into a <style> tag inside the html block.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Wrap the menu in both the container-templates and block-insert popups in a scrollable container (max-height) so a long list of templates no longer overflows the viewport; the search field stays pinned above it. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
…tyles
Replace inline CSS everywhere with a single selector-based model. The
container gear has one CSS field (.grid {}, .block-1 {}); the block gear
keeps HTML + a CSS field where & targets the block root and other
selectors are scoped under it. All rules are scoped to the instance and
emitted into a <style> tag instead of style="" attributes; templates
convert their inline style to rules on insert.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
96c23f0 to
ac65a91
Compare
Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
…r scrollable Structure content never rendered because parsing a string that starts with `<template>` via DOMParser places that element into `<head>`, leaving `document.body` empty. Use a real `<template>` element instead. Also make the code editor columns scroll internally with `overscroll-behavior: contain`, so long HTML/CSS is reachable/editable and scrolling no longer scrolls the page underneath. Co-authored-by: Cursor <cursoragent@cursor.com>
Redesign the HTML/CSS settings panel: HTML and CSS are shown as tabs in a compact view and switch to a side-by-side layout via a "Compact view" toggle. Add line numbers, a close button, and refreshed styling. Update the initial subtitle wording. Co-authored-by: Cursor <cursoragent@cursor.com>
Replace the anchored structure-templates popup with a centered modal that groups templates by family in collapsible sections and shows each structure as a card with a live, scaled shadow-DOM preview. Structures with themes get a stacked-card look and an "N themes" badge. Adds search, import and clear controls plus the related i18n keys. Co-authored-by: Cursor <cursoragent@cursor.com>
Hovering a stacked structure card now opens a popup with a preview tile per theme, so a themed variant can be picked directly. Selecting a theme keeps the structure's HTML and applies the chosen theme's CSS. Co-authored-by: Cursor <cursoragent@cursor.com>
Render the structure picker through the toolbar's expandedContent like the code editor, so the toolbar stays and the panel opens below it instead of a centered modal. Adds a "panel" expanded view (chromeless panel chrome without marking the code button as selected) and reuses the same mechanism across the toolbar's primary group. Co-authored-by: Cursor <cursoragent@cursor.com>
Use the larger close button (size l, 18px icon) in the code editor to match the structure picker panel. Co-authored-by: Cursor <cursoragent@cursor.com>
Layer the stacked card so the closer sheet sits above the farther one and both stay behind the preview, keeping a stable order on hover. Highlight the whole stack's border (preview + sheets) on hover. Co-authored-by: Cursor <cursoragent@cursor.com>
… a marketplace cover A structure is now strictly a layout container: any non-block markup inside a structure template is discarded during parsing, and the structure starts empty with its blocks providing all content. The Gravity UI landing intro is moved from structure content into a dedicated block. Family templates now capture their inner HTML/CSS, used as the family cover in the external templates marketplace (never rendered by the editor). Co-authored-by: Cursor <cursoragent@cursor.com>
…de editor The block HTML editor now renders the spec wrapper div (`<div class="g-md-hc-block g-md-hc-block-N">` and `</div>`) as greyed-out, non-editable first and last lines, with the editable markup in between. The CSS editor stays fully editable. The framed HTML pane shares one scroll area with an auto-growing textarea so the wrapper lines and line numbers stay aligned. Co-authored-by: Cursor <cursoragent@cursor.com>
…he popup The structure panel's theme picker renders in a portal outside the toolbar, so the panel's outside-pointerdown handler closed the panel before the theme button's click fired, dropping the insertion. Treat any element carrying the constructor stop class (portaled popups included) as inside. Co-authored-by: Cursor <cursoragent@cursor.com>
The Import button showed the export glyph (ArrowUpFromSquare); switch it to the matching import glyph (ArrowDownToSquare). Co-authored-by: Cursor <cursoragent@cursor.com>
…ure panel Replace the old menu-style block insert popup with a panel that mirrors the structure picker: searchable, family groups, live scaled previews, a Custom HTML entry, and a hover popup with the block's state/theme variants. Extract the shared shadow-DOM LivePreview so both pickers reuse it. Co-authored-by: Cursor <cursoragent@cursor.com>
…ditor The structure code editor now renders the complete document — its own content plus every block's markup — inside a locked g-md-hc-structure frame, with all CSS combined. Everything inside the frame is editable; on commit the inner markup is split back into structure content + blocks (preserving block identity by position), and CSS is consolidated into the structure stylesheet. Structure edits commit on blur to avoid fighting the cursor with re-assembled values. Co-authored-by: Cursor <cursoragent@cursor.com>
…h icon Co-authored-by: Cursor <cursoragent@cursor.com>
… picker A "Custom structure" button opens an inline HTML + CSS editor; on insert it applies a fresh structure built from the entered markup and styles (clearing any existing blocks), mirroring the block picker's custom HTML flow. Co-authored-by: Cursor <cursoragent@cursor.com>
Replace the block picker's "Custom HTML" single-field entry with a "Custom block" editor that has separate HTML and CSS inputs, matching the custom structure flow. Co-authored-by: Cursor <cursoragent@cursor.com>
…one component Extract the shared picker UI (header, search, custom HTML/CSS editor, collapsible family groups, preview cards with a stacked variants popup) into a single configurable TemplatePickerPanel driven by a normalized card model. The structure and block panels are now thin wrappers that map their templates to cards and pass picker-specific labels, extra editors (template import) and actions. Co-authored-by: Cursor <cursoragent@cursor.com>
…heme Replace the legacy dropdown menus on an existing block (and the structure theme switch) with the unified card picker. The state button now uses a sliders icon and is disabled when the block has no related states; the theme switch stays disabled when no themes are available. The picker gained optional search/custom slots, flat (header-less) groups and active-card highlighting; preview building moved to shared blockUtils helpers. Co-authored-by: Cursor <cursoragent@cursor.com>
… animation Raise the drag handle above the toolbar and content so it is never covered, give it more corner padding and a hover elevation, and animate the dragged block with a subtle scale, lift shadow and fade. Co-authored-by: Cursor <cursoragent@cursor.com>
…amed HTML scroll Introduce a localStorage-backed preferences store shared across every HTML constructor instance on the page, and bind the code editor's "compact view" toggle to it so the choice is remembered instead of resetting each time. Fix the framed (structure) HTML pane not scrolling: lay its gutter and stack out at natural height so the body becomes the scroll container. Co-authored-by: Cursor <cursoragent@cursor.com>
…are clearable The bundled "Gravity UI" family was passed as static `templates.items`, while the picker's "Clear all templates" button only looks at localStorage — so it was always disabled and could never remove them. Seed the defaults into storage once (guarded by a flag) and drop the static items, so the whole list is read from localStorage and the clear button can delete it. Co-authored-by: Cursor <cursoragent@cursor.com>
…ng contract Quick-style controls (background, text color, rounding, border) now serialize as CSS custom properties instead of concrete properties, so user-authored themes can react to them. Each aspect has light/dark companions (--g-md-hc-<name>-light/-dark) resolved for the active Gravity UI theme, with a fallback chain: toolbar override -> theme companion -> neutral default. The contract stylesheet is injected in output markup and template previews; the editor consumes the same variables via SCSS (keeping chrome fallbacks). Adds a theming doc describing the contract for theme authors. Co-authored-by: Cursor <cursoragent@cursor.com>
Adds a `scopeStyles` option that isolates each constructor's generated CSS by wrapping it in a unique class derived from the node's (persisted) entity id and prefixing the per-instance rules with it. This prevents styles from one constructor leaking into another on the same page. The generic contract stylesheet stays unscoped (it is identical per instance). Off by default; enabled in the demo for evaluation. Co-authored-by: Cursor <cursoragent@cursor.com>
Replace the bulky 40px edit button that overlapped the text with a compact 28px circular brand badge pinned to the highlight's top-right corner, refine the highlight outline (softer ring, rounded), add subtle pop-in animations, and give the inline textarea a matching focus ring. Co-authored-by: Cursor <cursoragent@cursor.com>
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.
Summary
Reworks the experimental
GridBlockTemplatesextension intoYfmHtmlConstructorand aligns the template model with the new HTML Constructor spec.This PR is stacked on top of
feat/yfm-html-block-templates-and-preview, so the diff stays scoped to the constructor experiment.What Changed
YfmHtmlConstructor, with actioncreateYfmHtmlConstructorand node nameyfm_html_constructor.family,structure,block, andthemetemplates; grouping now comes fromfamilyinstead ofgroup.<template>sets, including unknown-attribute validation, unique ids, finite priorities, reference validation, top-level style extraction, and ignored family/theme content.::: htmlwith deterministicg-md-hc-structure-*andg-md-hc-block-*wrappers and generated styles, removing the old grid output classes and scopes.demo/src/defaults/yfm-html-constructor.Extensions / YFMnext to the existingYFM HTMLstory.User Impact
The preview now demonstrates the structure-based HTML Constructor flow from the new spec. Template packs can define reusable structures, blocks, states, and themes, and users can compose them through two family-grouped menus.
Validation
pnpm --filter @gravity-ui/markdown-editor typecheckandpnpm --filter @markdown-editor/demo typecheckpassed before the final parser fallback cleanup.Notes
GridBlockTemplates,type="container",group, or the old storage key..worktrees/andinfra/docs-gen/EXTRACTION_PIPELINE_RU.mdare not part of this PR.