Skip to content

v2.0.0-beta.2 — React-parity custom UI + demo polish - #19

Merged
goodlime merged 18 commits into
mainfrom
feat/v2-beta2-react-parity
Jun 21, 2026
Merged

v2.0.0-beta.2 — React-parity custom UI + demo polish#19
goodlime merged 18 commits into
mainfrom
feat/v2-beta2-react-parity

Conversation

@goodlime

Copy link
Copy Markdown
Contributor

v2.0.0-beta.2

Second beta. Headline is the React-parity custom-UI provider system — the library now mirrors the @grapesjs/react component model so consumers can build a fully bespoke editor shell in Angular templates.

Library (ships to npm)

  • Custom-UI providers<gjs-*-provider> components for pages, blocks, layers, selectors, styles, traits, devices, assets, modal; plus <gjs-canvas> and the gjsContainer directive.
  • Editor component/service wiring for custom mode, project load/save, and selection state.
  • Selectors/Styles panels now render in custom mode (__trgCustom() on wire — custom mode skips the default panel render where the engine's initial event fires).
  • 38 lib tests (vitest run), build:lib clean.

Demo (does not ship to npm)

  • One tokenized design system (OKLCH, light/dark) across toolbar, both custom rails, default-mode GrapesJS panels, and HTML export.
  • Content persists across Custom ↔ Default UI switches; dropped blocks auto-select.
  • Drag ghost follows the cursor; GrapesJS's own .gjs-placeholder shows the real insertion point.
  • Typed style inspector (sliders / colour swatches / segmented align / selects) from a curated styleManager.
  • Layers hide GrapesJS textnodes; default-mode device selector pinned inside its command bar.

Release mechanics

  • Merge → pages.yml deploys the demo.
  • Tag v2.0.0-beta.2publish.yml publishes to npm under the beta dist-tag (Trusted Publishing).

goodlime added 18 commits June 20, 2026 10:02
Add nine <gjs-*-provider> components mirroring @grapesjs/react's render-props surface (blocks, layers, selectors, styles, traits, pages, devices, assets, modal), a <gjs-canvas> custom-UI mount point, and the *gjsContainer directive for projecting GrapesJS-owned elements.

Editor component gains async CDN plugin loading, editorCreated/projectUpdated outputs, grapesjsCss/waitReady inputs, SSR safety, and a height/width:100% host-fill default. Service adds isInitialized; editorReady now fires on onReady() (breaking vs beta.1).

Selectors and Styles providers self-trigger their initial custom event on wire() so their panels render in custom-UI mode, where GrapesJS skips the default panel render that would otherwise fire it.
Rework the demo to showcase every provider with a full custom editor shell (pages, blocks with drag ghost, layers tree, selectors, styles, traits, assets/modal overlays) alongside the default-UI mode.

Layers rows now select via editor.select(component) — a GrapesJS Component has no .select() method, so the previous call threw at runtime.

Raise anyComponentStyle budget to fit the demo stylesheet; rename the private workspace package to grapesjs-angular-workspace.
Tokenized design-system spec (light/dark) and the interactive editor-chrome mockup it derives from, as the visual source of truth for the demo redesign.
…les.css

One :root token set (surfaces, text, lines, accent, selection, status, shadow, type, radii) plus a [data-theme=dark] override, defined after the grapes.min.css import so overrides win. Sets global body background/color/font. Nothing consumes the accent/panel tokens yet — wired in following commits.
UI in Inter, mono surfaces (IDs, selectors, style values, HTML export) in JetBrains Mono, per the redesign spec. preconnect + display=swap.
Toolbar icon button (inline sun/moon) flips data-theme on documentElement so both custom rails and the GrapesJS panels inherit it. Initial theme = saved choice, else OS prefers-color-scheme; persisted to localStorage. Editor logic untouched.
Toolbar gains a clear action hierarchy (Get HTML primary / Save secondary / Reset quiet-destructive) and a token-styled device select. Every custom-rail surface (panels, page list with accent active-bar, block tiles, layer tree, selector chips, state/trait controls, read-only style list, drag ghost, drop indicator, asset/modal overlays, HTML export) now maps to tokens — zero hardcoded hex, #0f0 and #276ef1 gone, and the .property-list !important pile-up is removed via scoping. Adds focus-visible rings and a prefers-reduced-motion guard.
Map the engine's --gjs-* variables (verified against the installed build) onto our design tokens so they re-resolve on theme flip, plus minimal scoped .gjs-* overrides for the colours GrapesJS hardcodes (panel/title/field borders, canvas selection badge -> --select). Flipping Custom <-> Default in either light or dark now reads as one product — no stock-grey panels.
Replace the single Custom/Default button with a real 2-segment control, and the bare <pre> export with a slide-up dock (header + HTML pill + Copy + close) on a panel surface. Reuses existing editor logic via a thin setCustomUi(boolean) and a copyHtml() clipboard helper. Slide animation respects prefers-reduced-motion.
… drops

Each Custom<->Default toggle recreates the gjs-editor, and onEditorReady was unconditionally re-seeding the sample, wiping edits. Now snapshot the project on switch (setCustomUi) and restore it in the new instance; seed the sample only on first load and on Reset. Also select the dropped component on block:drag:stop so its styles/traits populate without a second click.

Verified: a component added in one mode survives the switch (and back) into the recreated editor.
The custom-UI right rail was read-only, so the State dropdown had nothing to affect. Each style property now renders an editable control (select for select/radio types via getOptions, text input otherwise, read-only value for composite/stack shorthands), bound to property.upValue(). Editing drives the canvas; switching State now writes state-specific rules (e.g. :hover). Selectors panel gets a mono targets readout, styled chips, a labeled State field, and a proper empty state. Both panels gate on the current selection.

Verified live: editing font-size/text-align updates the canvas; selecting hover state + editing creates a :hover rule.
Render each block's own GrapesJS media SVG as the tile icon (fill=currentColor, so it themes), memoized per block id through DomSanitizer. Block tiles become icon-over-label, matching the reference mockup.
…ock icon

In custom-UI mode the block drag ends via sorter:drag:end, NOT block:drag:stop (which the cleanup was listening for). So dragging never reset: the source button stayed dimmed/'active', the floating ghost stuck at a stale position (looking like 'no ghost' on later drags), and the drop never auto-selected. Clean up on sorter:drag:end instead, and auto-select the dropped element via component:add while the drag is active. The ghost now carries the block's icon so it's clearly visible as you drag.

Verified via the editor event lifecycle: block:drag:start sets dragging; a component added mid-drag auto-selects; sorter:drag:end resets dragging/label/icon.
Layers: filter out non-layerable nodes (textnodes that surfaced as meaningless 'Box' rows), mirroring GrapesJS's own layer manager. Verified: 0 'Box' rows remain.

Drag: drop the demo's full-canvas 'DROP HERE' overlay (it covered the real indicator and the badge sat centered, not at the cursor). Rely on GrapesJS's own .gjs-placeholder — a precise insertion line at the drop point — themed to --accent in global styles.css. The floating ghost (icon + label) still follows the cursor.
…, selects)

The right rail was a wall of identical text/select boxes. Drive it from a curated styleManager (Typography / Background / Spacing) so each property is the right control: range sliders with value readout (font-size, line-height, padding, margin), colour swatches (color, background-color), a segmented control (text-align), and selects for true enums (font-weight). Small typed helpers wrap GrapesJS's dynamic Property API (slider unit handling, colour->hex, options). Applies to both custom and default UI.

Verified live: the font-size slider updates the canvas (with unit), and the segmented text-align sets alignment.
The .gjs-pn-devices-c panel is 44px but the canvas starts at 40px (--gjs-canvas-top), so its bottom edge bled into the canvas. Pin the panel to the bar height and center the dropdown within it (bottom now 5px clear of the canvas).
The REDESIGN-SPEC and mockup were process artifacts for the demo
re-skin, not part of the demo app or the published library.
@goodlime
goodlime merged commit 33dbdb5 into main Jun 21, 2026
1 check passed
@goodlime
goodlime deleted the feat/v2-beta2-react-parity branch June 21, 2026 14:16
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant