Commit Graph
162 Commits
Author SHA1 Message Date
Oleg Isonen d779985e8a fix: match project rules with published routes 2026-09-30 19:18:05 +01:00
Oleg Isonen 05706b5425 feat: Make Content Block templates the MDX authoring interface (#6307)
Closes #6306

## Outcome

Content Block templates are now the public component model for MDX
authoring.

- Standard Markdown resolves through matching Content Block templates.
- PascalCase JSX resolves to a named template first, then to a
registered component.
- Adding or changing a template immediately affects matching MDX,
including content authored before that template existed.
- Every supported standard MDX element is present in new Content Blocks
by default.
- Template `name` is a stable PascalCase JSX identifier. `label` remains
optional display text only.
- Lowercase JSX represents native HTML and SVG without exposing
`ws.element` in authored syntax.
- Unknown, ambiguous, and unsafe JSX stays in source, produces a
source-ranged Builder diagnostic, and is omitted from published output.
- Frontmatter images preserve exact `$ref` values and use the Asset
description for `alt` text.
- Keyboard and mouse insertion from the slash menu remove the trigger
slash and preserve the selected template.

## Public MDX contract

- Markdown is canonical for standard prose.
- Lowercase JSX creates native elements:
`<section><p>Text</p></section>`.
- PascalCase JSX uses templates and registered components:
`<PromotionCard />`, `<Heading tag="h1">Title</Heading>`, and `<YouTube
src="https://youtu.be/KI5JHpzBK1s" />`.
- Component-name collisions use stable qualified identifiers such as
`Checkbox` and `RadixCheckbox`.
- A self-closing template keeps its designed default subtree. An
explicitly paired empty template clears it.
- Static quoted values and bare booleans are supported.
- Imports, exports, expressions, spreads, functions, executable
JavaScript, unsafe attributes, `<$.*>`, and authored `<ws.element>` are
rejected.
- `ws` remains only for compiler primitives with no React component.

## Implementation

- [x] Add stable, unique template names and keep them separate from
labels.
- [x] Parse and validate Markdown and JSX through their ASTs with
precise source ranges.
- [x] Share component identity between template JSX, Content MDX,
Builder materialization, reload, copy, and publication.
- [x] Resolve templates live after add, edit, rename, reorder, removal,
undo/redo, collaboration updates, and reload.
- [x] Preserve authored props, children, Asset references, template
defaults, and the exact slash-menu template choice.
- [x] Make one typed MDX semantic inventory drive default templates and
slash-menu eligibility.
- [x] Move component-dependent template assembly into the component
registry.
- [x] Replace production `$`, `animation`, and `radix` JSX namespaces
with direct component imports.
- [x] Keep only explicit compiler primitives in `ws` template JSX.
- [x] Migrate repository templates, fixtures, stories, examples, MCP
guidance, CLI guidance, and generated outputs.
- [x] Add Builder unit and Playwright coverage for authoring,
diagnostics, insertion, synchronization, reload, and publication.
- [x] Review and update the authoritative Content Block and generated
MCP documentation.

## Compatibility

- Persisted project data continues to use namespaced component IDs and
`ws:element` for generic HTML elements. No project-data migration is
required.
- Legacy `<ws.element ws:tag="…">`, `<ws.element ws:name="…">`, `<$.*>`,
`<animation.*>`, and `<radix.*>` input remains readable during the
compatibility window.
- Current serializers and repository-owned sources emit only canonical
Markdown, lowercase intrinsic JSX, or PascalCase identifiers.
- Untouched user MDX is not rewritten automatically. Legacy syntax is
canonicalized when its owning source is edited.
- Deferred follow-up: remove legacy namespace readers and proxy support
only after the canonical writer is deployed and existing projects are
backfilled. This is intentionally outside this PR.

## Verification

- [x] CI package tests, typechecks, lint, package boundaries, generated
assets, migrations, and size checks pass.
- [x] All six Builder E2E shards pass.
- [x] Fixture checks pass on Ubuntu and Windows.
- [x] Targeted local Content Engine, Template, SDK, registry, Project
Build, migration, Builder, component, CLI, and Playwright tests pass.
- [x] Runtime contracts, CLI docs, and MCP docs were regenerated from
their owning sources.
- [x] Local fixture generation completed without an unexpected fixture
diff.
- [x] Documentation impact reviewed and included in this PR.
- [x] Review and approve the intentional List visual snapshot change.
- [x] Run the complete agent evaluation suite after explicit approval.
- [x] Run the network fixture link/sync pipeline against the matching PR
deployment after explicit permission.

## Known visual change

The generated List story now targets its actual default `ul` element
instead of `ol`, so the default list styling appears in the visual
snapshot. The visual change was reviewed and the approved visual check
passes.
2026-09-06 15:19:54 +02:00
Oleg Isonen d4b1994a6a fix: Improve editor selection and project tag contrast (#6302)
Closes #6301

## Summary

- Restore Dashboard project tags to the pre-color-refactor treatment:
fixed white text over a 30% black scrim in both application themes.
- Use one high-contrast text-selection treatment across native inputs,
textareas, contenteditable fields, and every shared CodeMirror editor.
- Preserve the existing subtle selection treatment for Navigator,
Project Settings, command menus, Dashboard navigation, and other
selected controls.
- Add direct Storybook coverage for the CSS fragment editor.
- Simplify chromatic color derivation from 571 to 329 lines without
changing computed colors.

## Technical choices

- Keep project tags independent from application-theme polarity because
they overlay arbitrary thumbnail artwork.
- Keep the existing `selectionBackground` control-state export unchanged
at its original 12% light / 20% dark accent blend.
- Define separate `--background-text-selection` and
`--foreground-on-text-selection` tokens exclusively for selected text.
- Use the bounded accent in light mode and a luminance-lifted accent in
dark mode so selected text remains distinct even with extreme custom
theme colors.
- Style CodeMirror through its existing selection layer and
`::selection` CSS hooks; no selection tracking or editor-state logic is
added.
- Leave canvas rich-text selection independent: authored canvas
documents do not load the Builder UI theme stylesheet.
- Replace five duplicated XYZ clamp formulas with the exact
upper-luminance cap they reduce to. The removed lower-bound and
white-mixing branches were unreachable because the minimum was fixed at
zero.

## Todo

- [x] Restore the original project-tag scrim and foreground in both
themes.
- [x] Inventory native, CodeMirror, and canvas rich-text selection
paths.
- [x] Unify native and shared CodeMirror text-selection colors.
- [x] Keep text selection independent from selected control and
navigation states.
- [x] Add the missing CSS fragment editor story.
- [x] Add light- and dark-mode browser regressions and confirm they fail
before the fix.
- [x] Enforce 4.5:1 selected-text contrast and 3:1 highlight-to-surface
contrast across supported theme inputs.
- [x] Remove duplicated and unreachable chromatic color derivation while
preserving outputs.
- [x] Review documentation impact; the design-system color-token
reference is updated, with no user-facing product documentation change
required.
- [x] Verify fixture impact; no fixture inputs or generated outputs are
affected.

## Verification

- `pnpm --filter @webstudio-is/design-system test` — 227 tests passed,
including the control/text separation regression, Navigator tree
interaction, default-palette comparisons, and the full supported-theme
contrast sweep
- `pnpm --filter @webstudio-is/design-system typecheck`
- `pnpm --filter @webstudio-is/builder exec vitest run
app/shared/code-editor-base.browser.test.tsx --project
app-browser-shared`
- `pnpm --filter @webstudio-is/builder exec vitest run
app/dashboard/projects/project-card.browser.test.tsx --project
app-browser-canvas-dashboard`
- `pnpm --filter @webstudio-is/builder typecheck`
- Targeted `oxlint`, formatting, and `git diff --check`
- Live dark-mode Dashboard verification of the restored subtle
navigation selection
- Storybook visual checks for the full color system and input/CodeMirror
selection in light and dark modes
2026-09-01 17:05:14 +02:00
Oleg Isonen f6c524572d feat: add Builder dark theme and rebuild colors
## Summary

Rebuilds Webstudio’s color system, migrates the entire Builder to it,
and introduces a complete dark theme.

A small set of theme colors and contrast controls now drives the
interface through relative CSS colors:

```text
Theme colors and contrast
    ↓
Light/dark derivation bounds
    ↓
Derived color families
    ↓
Reusable semantic colors
    ↓
Component composition
    ↓
Builder interface
```

CSS is the runtime source of truth. Light and dark modes share the same
theme inputs, so changing a theme color automatically updates its
surfaces, content, borders, states, and component presentation. The
refactor turns dark mode into a first-class Builder theme rather than a
separately maintained palette.

This is an atomic migration. Legacy color names and compatibility
aliases will not remain after all consumers have moved.

## Scope

- The color source, derivation model, semantic vocabulary, validation,
typing, and Storybook overview.
- Every design-system component.
- Builder, dashboard, authentication, shared UI, Query Builder, stories,
and tests that consume the legacy color scale.
- Removal of the legacy Stitches color scale after its final consumer is
migrated.
- A complete dark theme across application UI while keeping authored
canvas content independent.
- Complete light and dark visual verification.
- Unified browser-test infrastructure: Vitest Browser Mode for Design
System browser contracts and standard Playwright Test for all Builder
E2E workflows.

Literal colors remain only where color is the actual content or belongs
to a deliberately separate system, such as user-authored values,
external previews, brand artwork, data visualization, functional canvas
overlays, and source assets. Every remaining exception must have an
explicit owner.

## Architecture decisions

- Theme authors control six color families and three bounded contrast
controls.
- Relative CSS colors derive the rest of the system.
- Dark mode changes derivation bounds instead of maintaining a second
independent palette.
- Components consume a small reusable semantic vocabulary.
- Component states and exceptional presentation are composed inside
components.
- Builder-specific categorical meaning uses focused composite recipes,
not intent semantics or a larger global vocabulary.
- TypeScript validates public semantic CSS-variable names but does not
generate runtime colors.
- No token-manager dependency, compatibility aliases, or
component-specific public color tokens.
- A new semantic or theme variable is added only when existing semantics
and local composition cannot represent a reusable cross-feature
decision.

## Todo

### Color-system foundation

- [x] Establish direct CSS as the runtime source of truth.
- [x] Define bounded theme colors and contrast controls.
- [x] Derive light and dark modes from the same theme inputs.
- [x] Reduce the semantic inventory to reusable decisions and explicit
accessibility pairs.
- [x] Generate only TypeScript names for public semantic CSS variables.
- [x] Validate layers, references, cycles, consumption, naming,
generated types, and browser-computed contrast.
- [x] Add the Storybook color-system overview and theme controls.
- [x] Document the architecture and its relationship to the public Craft
specification.

### Design-system migration

- [x] Replace every active legacy color consumer in design-system
components and Storybook chrome.
- [x] Compose component states locally without component-specific public
tokens.
- [x] Preserve intentional preview and sample-content colors.
- [x] Add complete positive, negative, warning, informative, and accent
accessibility pairings.
- [x] Validate light and dark scheme-bound references independently.
- [x] Verify the design-system package with typecheck, lint, formatting,
Storybook, and 222 tests.

### Inventory and contract

- [x] Inventory all 319 legacy references across 107 Builder, Query
Builder, story, test, and design-system files.
- [x] Classify every reference as a direct semantic replacement, local
composite recipe, documented literal exception, or removable code.
- [x] Record the intentional authored-content, external-preview,
functional-preview, data-visualization, brand, and source-asset
exceptions.
- [x] Treat the public semantic vocabulary as closed by default and
justify any proposed addition by cross-feature reuse and accessibility
need.
- [x] Keep Builder code limited to typed public variables accepted by
`cssVar()`.

### Theme infrastructure

- [x] Add `system` (default), `light`, and `dark` application
preferences.
- [x] Persist the preference in existing client settings and resolve
`system` through `matchMedia`.
- [x] Apply the resolved scheme before paint and respond to
operating-system changes.
- [x] Expose the persisted theme control under **View → Color scheme**.
- [x] Keep authored canvas documents independent from the application
theme.
- [x] Ensure portals, overlays, embedded surfaces, and third-party
controls receive the correct interface scheme.

### Generic interface migration

- [x] Migrate shared dialogs, project settings, notifications, controls,
and Query Builder.
- [x] Migrate dashboard, authentication, publishing, and shared
application UI.
- [x] Migrate the Builder loading state, topbar, sidebars, navigator,
workspace, footer, settings, pages, alerts, and menus.
- [x] Replace fixed interface literals alongside their owning surfaces.
- [x] Remove the old scrollbar variable and hardcoded loading color.

### Style panel and style-source recipes

- [x] Migrate ordinary style-panel inputs, labels, layouts, spacing,
alignment, menus, property states, and value editors.
- [x] Model style-source provenance, kind, interaction, and error as
separate axes.
- [x] Compose categorical style-source colors from neutral and
accent-relative colors.
- [x] Use negative semantics only for actual errors, not overwritten
provenance.
- [x] Reuse one feature-owned recipe across style-source controls,
badges, menus, and values without adding global tokens.

### Canvas and editors

- [x] Migrate canvas selection, reusable outlines, grid guides, resize
handles, labels, badges, and overlays.
- [x] Keep collaborator colors as data visualization while guaranteeing
readable labels.
- [x] Prevent Builder theme values from leaking into authored content.
- [x] Migrate editor surfaces, selections, autocomplete, lint states,
and tooltips.
- [x] Derive syntax visualization from neutral and accent-relative
colors; reserve intent colors for diagnostics.

### Explicit color domains

- [x] Isolate external search and social previews from the application
scheme.
- [x] Preserve user-authored CSS values, functional color previews, and
checkerboards.
- [x] Review brand surfaces independently in both schemes.
- [x] Document every retained literal in the exception ledger.

### Stories, tests, and legacy removal

- [x] Migrate all affected Builder stories and tests.
- [x] Replace the design-system test that intentionally references the
legacy scale.
- [x] Add theme-preference and scheme-resolution behavior tests.
- [x] Remove the legacy `design-tokens.color` registry.
- [x] Remove the Stitches `colors` scale and `rawTheme.colors`.
- [x] Remove color-name conversion code that exists only for the legacy
scale.
- [x] Add a focused repository check that rejects legacy references.
- [x] Confirm no compatibility mappings or deprecated aliases remain.

### Browser-test infrastructure

- [x] Run pure Design System tests in Node and browser-dependent tests
in Vitest Browser Mode with Playwright Chromium.
- [x] Migrate all 79 Builder E2E workflows from the custom harness to
standard Playwright Test.
- [x] Replace filename-based shard discovery with standard Playwright
sharding.
- [x] Preserve clean-backend shard retries and upload Playwright failure
artifacts in CI.
- [x] Remove the custom runner, registry, and timeout infrastructure.

### Verification and documentation

- [x] Compare light-mode visual regressions directly with `main`; review
every difference rather than accepting snapshots wholesale.
- [x] Add representative dark coverage for dashboard, Builder shell,
style panel, dialogs, editors, canvas tools, and status states.
- [x] Test default and extreme custom-theme presets.
- [x] Verify semantic and categorical-recipe contrast.
- [x] Test first paint, persistence, system changes, portals, and canvas
isolation.
- [x] Run affected tests, typechecks, lint, formatting, and Storybook
checks.
- [x] Review fixture impact; no fixture inputs or generated outputs are
affected.
- [x] Review authoritative `docs/` content and update it where needed.
- [x] Review the final diff and make this checklist reflect delivered
scope.

## Current verification

- Design-system typecheck and generated-type freshness: passed.
- Design-system tests: 222 passed, including the full theme-parameter
contrast sweep and browser component coverage.
- Builder typecheck and production build: passed.
- Theme preference and scheme-resolution tests: 10 passed.
- Scoped Oxlint, formatting, and diff checks: passed.
- Design-system Storybook build and representative light/dark visual
review: passed.
- Builder E2E: 80/80 Playwright entries passed (setup plus 79
workflows).

Ref #3818
Closes #6267
2026-08-30 03:24:56 +01:00
Oleg Isonen f9681dc30f feat: MDX-backed Content Blocks (#6234)
## Summary

Supersede #6182 with a clean implementation of MDX-backed Content Blocks
on top of the unchanged `main` Content Block editing model. A connected
`.mdx` Asset changes where authored children are loaded and saved; it
must not change how Content mode inserts, edits, selects, moves, copies,
or deletes instances.

The previous implementation remains available in
`agent/mdx-content-block-6124` and
`agent/mdx-content-block-6124-review`. Reuse its independently tested
parsers, converters, schemas, Asset repository, template resolution,
publication, MCP, and UI work where those pieces fit the corrected
architecture. Do not port its per-operation storage routing, projected
editing stores, MDX undo/history, or atomic multi-root machinery.

Ref #6124
Ref #6182
Closes #6261

## Locked behavior

- `.md` keeps its existing Markdown behavior; `.mdx` enables MDX.
- Standard Markdown structures are stored as Markdown. JSX is used only
for structures Markdown cannot represent losslessly.
- Generic elements use `<ws.element ws:tag="…">`; template instances use
`<ws.element ws:name="…">`.
- Invalid, unsafe, or unsupported MDX never prevents editing the file or
publishing the project. Builder and publication use the same recovery
result: recoverable nodes are skipped with source-located warnings,
while an unrecoverable document renders no authored file content in
either environment.
- Connecting a source never serializes existing Content Block children
into the file. **Connect** removes ordinary persisted children,
preserves Templates, sets `src`, and uses file content.
- Disconnecting resets `src`, discards derived instances, leaves the
Content Block empty, and never changes the Asset.
- While connected, normal Content Block mutations update in-memory
instances synchronously. Asset persistence happens afterward and never
blocks rendering.
- Genuine external revision conflicts use the standard reload-required
flow. Rapid local edits are ordered/coalesced and must never conflict
with each other.
- Repeated scopes use Content Block ID plus Collection item identity.
- Multiple Content Blocks may intentionally share one MDX Asset. They
share one revisioned document session and edits propagate to every
connected occurrence.
- Missing templates show warnings/placeholders only in Builder and are
skipped on published sites.

## Reuse strategy

- [x] Audit all 62 original implementation commits and 5 later
review/fix commits
- [x] Reuse the shared Content Engine Markdown/MDX AST, parser,
serializer, diagnostics, reference discovery, and tests
- [x] Reuse SDK source schemas, instance-name utilities, unique template
naming, and source-integrity validation
- [x] Reuse template resolution/materialization and authored-tree
conversion after removing storage-operation coupling
- [x] Reuse revisioned Asset content repository, authorization, limits,
and browser/server transport
- [x] Reuse publication, document-graph, CLI, MCP, source-control UI,
frontmatter UI, and E2E work where contracts remain valid
- [x] Reuse tests as behavioral specifications; rewrite tests that
assert the rejected projection/routing architecture
- [x] Do not port per-operation MDX routing, alternate projected
mutation stores, semantic reconciliation after each command, MDX Builder
history/undo, atomic multi-file rollback, or canvas loading/saving UI


## Old-branch porting map — do not rewrite

Before implementing any checklist batch, inspect the named
implementation and tests on `agent/mdx-content-block-6124-review`. Move
the implementation and its tests first; change only the boundary that
conflicts with the rebuilt architecture. Do not create a second
implementation under a new name. When a test encodes the rejected
projected-store architecture, retain its behavioral assertion and
replace only its setup.

### Already ported

- `parseMarkdownAst`, `createMdxDocumentFromMarkdown`,
`parseMdxDocument`, `serializeMdxDocument`, `preferMarkdownSyntax`,
`discoverMdxBodyAssetReferences`, `discoverMdxAssetReferences`, and
`previewMarkdownToMdxConversion`
- Asset-reference, byte-stream, document-graph, Markdown, and MDX
helpers included in commit `76bc388ba9`
- Tests: the corresponding `packages/content-engine/src/**/*.test.ts`
files already on this branch

### Port with their existing tests

| Area | Functions to move or adapt | Tests to move with them |
| --- | --- | --- |
| Source contract and integrity | `parseContentBlockSourceProp`,
`getContentBlockSource`, `isEqualContentBlockSource`,
`formatContentBlockSourceIntegrityIssue`,
`getContentBlockSourceIntegrityIssues`,
`allocateUniqueContentBlockTemplateName` |
`packages/sdk/src/content-block.test.ts`,
`packages/sdk/src/schema/content-block.test.ts` |
| Existing instance/name utilities | `findChildReferenceIndex`,
`findParentInstanceReference`, `getInstanceName` |
`packages/sdk/src/instances-utils.test.tsx` |
| Template naming in mutations |
`assignUniqueBlockTemplateNamesMutable`,
`findBlockTemplateNameCollision`, `getSourceBackedBlockTemplateContext`,
`getBlockTemplateNameConfirmation`, `getBlockTemplateInsertionIndex` |
`packages/project-build/src/runtime/block.test.ts` |
| Content-mode property permissions | `getContentModePropEligibility`;
preserve its distinction between editable, design-only, incompatible,
and unknown props |
`packages/project-build/src/runtime/content-mode-permissions.test.ts` |
| Template resolution | `resolveMdxTemplates` |
`packages/project-build/src/runtime/mdx-template-resolution.test.ts` |
| Template materialization | `createMdxScopeIdGenerator`,
`materializeMdxTemplates` |
`packages/project-build/src/runtime/mdx-materialization.test.ts` |
| MDX → instances and instances → MDX |
`isMaterializedMdxAuthoredContentRoot`, `preserveMdxAuthoredContentIds`,
`materializeMdxAuthoredContent`, `reconcileMdxAuthoredContent`,
`omitTransientEmptyParagraphs`, `serializeMdxTemplateInsertion` |
`packages/project-build/src/runtime/mdx-authored-content.test.ts`;
retain the pure serialization cases from `mdx-storage-adapter.test.ts` |
| Revisioned Asset I/O | `createAssetContentRevision`,
`readAssetContentBytes`, the package-owned
`createHttpAssetContentRepository`, the thin Builder
`createBuilderHttpAssetContentRepository`, `createAssetContentBridge`,
`initAssetContentBridge`, `getAssetContentBridge`; keep one repository
implementation rather than copying the old Builder duplicate |
`packages/asset-uploader/src/content-repository.test.ts`,
`apps/builder/app/builder/shared/assets/mdx-content-repository.test.ts`,
`apps/builder/app/shared/asset-content-bridge.client.test.ts` |
| Source lifecycle planning | `createContentBlockBodyRemoval`,
`prepareContentBlockConnect`, `prepareContentBlockDisconnect`,
`prepareContentBlockSwitch`, `ContentBlockSourceRevisionConflictError` |
`packages/project-build/src/runtime/content-block-source-lifecycle.test.ts`
|
| Per-Asset revision/session behavior | `getContentBlockSessionSource`,
`isContentBlockSessionSourceCommitted`; reuse the loading,
authorization, revision, queue, conflict, retry, cancellation, and
source-replacement internals of `createMdxAssetEditingSession`, but key
the rebuilt session by Asset rather than Content Block/render root |
Port the applicable cases from
`packages/project-build/src/runtime/mdx-asset-session.test.ts`; replace
root-projection setup with in-memory snapshot setup |
| Template migrations | `validateMdxTemplateMigrationConfirmation`,
`planMdxTemplateMigration` |
`packages/project-build/src/runtime/mdx-template-migration.test.ts` |
| Publication | `createPublishedMdxMaterializationCache`,
`materializePublishedMdx`, `getPublishedMdxContentDatabaseMaxBytes`,
`getDynamicPublishedMdxSourceBlockIds`, `hasDynamicPublishedMdxSources`,
`createPublishedBuildContentCompilationPlan`,
`resolvePublishedMdxDependencyClosure`,
`resolvePublishedMdxAssetCandidates` |
`packages/project-build/src/runtime/published-mdx.test.ts`,
`packages/project-build/src/content-database.test.ts` |
| Build/import integrity | `assertContentBlockSourceIntegrity` and the
Content Block cases in
`getBuildIntegrityIssues`/`formatBuildIntegrityIssue` |
`packages/project-build/src/build-integrity.test.ts` |
| MDX paste/MCP insertion | `insertMdxText` and its input/result
schemas; retain parsing, confirmation, template-resolution, and
insertion-index logic, then invoke the normal mutation path |
`packages/project-build/src/runtime/mdx-paste.test.ts` |
| Builder source control | `createContentBlockSourceController`,
`createBuilderContentBlockSourceController` and the existing
source-control components | `content-block-source-controller.test.ts`,
`content-block-source.test.tsx` |
| Diagnostics | `formatContentBlockDiagnostic`,
`deduplicateContentBlockDiagnostics`, `takeNewContentBlockDiagnostics` |
Port only their focused cases from
`apps/builder/app/shared/content-block-content.test.ts` |

### Explicitly do not port

- `projectContentStorageChanges`, `createContentStorageProjection`,
`createContentStorageSelectorProjection`,
`executeContentStorageMutation`, `executeContentStorageTextReplacement`,
`executeContentStoragePropMutation`, and
`executeContentStorageStructuralMutation`
- `applyMdxContentStorageChanges` and `prepareMdxContentStorageWrites`;
replace them with one post-mutation snapshot serializer built from the
reusable pure `reconcileMdxAuthoredContent` converter
- `createContentBlockApplicationOperations` and the persistence-plan
wrappers that route individual editing commands
- Builder `$runtime*` projected stores, materialized mutation functions,
alternate selector/tree helpers, pending projected-change state, and
MDX-specific mutation sequences from `content-block-content.ts`
- Canvas loading/saving/open-file presentation state, MDX history/undo,
and atomic rollback machinery

## Implementation checklist

### 1. Preserve the `main` editing architecture

- [x] Keep normal synchronous insert, text, Enter, slash menu, property,
delete, move, wrap, copy/paste, selection, and focus mutations unchanged
- [x] Materialize connected content through the same runtime instance
interfaces used by ordinary Content Blocks
- [x] Keep connected authored children in memory and exclude them from
persisted build data
- [x] Route persistence only after a synchronous mutation has updated
the canvas
- [x] Never wait for Asset loading, conversion, or saving before
rendering an interaction
- [x] Add no MDX-specific implementation to individual editing commands

### 2. Shared Markdown and MDX conversion

- [x] Parse Markdown and the Markdown portion of MDX through one shared
AST and plugin configuration
- [x] Implement one shared MDX-to-instances converter and one shared
instances-to-MDX converter
- [x] Serialize headings, paragraphs, links, images, lists, tables, task
lists, blockquotes, thematic breaks, code, emphasis, strong,
strikethrough, and other supported GFM structures as Markdown
- [x] Serialize only non-lossless/custom structures as Webstudio JSX
- [x] Preserve nested Markdown in MDX elements, frontmatter, comments,
tight/loose list semantics, code whitespace, reference links, and Asset
references
- [x] Omit transient empty draft paragraphs instead of emitting
`<ws.element ws:tag="p" />`
- [x] Preserve unsupported source text and authored metadata whenever it
cannot be converted safely
- [x] Add deterministic round-trip and canonical-output coverage for
every supported Markdown structure

### 3. Invalid and unsafe MDX

- [x] Preserve file source exactly; never silently repair or rewrite
invalid source
- [x] Ignore imports, exports, expressions, executable JavaScript,
invalid properties, and other unsupported nodes when they can be
isolated
- [x] Continue rendering valid siblings and report every skipped subtree
once with filename, line, and column
- [x] Use the same recovery pipeline in Builder and publication so both
render the same authored result for the current file revision
- [x] When structural syntax prevents recovery, render no authored file
content in Builder or publication instead of retaining a stale
materialization
- [x] Skip an unrecoverable Content Block on published sites and
continue the build with a warning
- [x] Keep invalid and unsafe files editable and reconnectable
- [x] Enforce UTF-8, byte-size, depth, node-count, property-count, and
generated-output limits with source-located diagnostics where possible

### 4. File formats and Asset creation

- [x] Keep `.md` parsing and raw-HTML behavior unchanged
- [x] Support creating, opening, editing, deleting, and recreating
`.mdx` files through the normal text-file UI
- [x] Open `.mdx` in the same editor experience as `.md`
- [x] Always create an independent empty MDX Asset even when identical
empty files exist
- [x] Allow renaming `.md` to `.mdx` without converting or rewriting its
contents; after rename, handle invalid contents through the normal MDX
diagnostics and recovery pipeline
- [x] Update an already-open MDX editor immediately after canvas
persistence
- [x] Bound read/write buffering and verify the returned Asset identity
and revision

### 5. Source contracts and lifecycle

- [x] Support direct Asset bindings and dynamic expression bindings
- [x] Keep source mutation controls available only in Design mode; show
the connected filename and **Open** action read-only in Content mode
- [x] Reject duplicate source props, unsupported prop types, missing
Assets, non-MDX Assets, and unauthorized Assets
- [x] Analyze selected file diagnostics before confirmation without
modifying the block or file; MDX syntax diagnostics do not block
connection
- [x] For a non-empty block, show **Abort** and **Connect** and explain
that ordinary children will be replaced
- [x] On connect, remove every non-template child, preserve Templates,
set `src`, and materialize file content
- [x] Replace disconnect handoff with normal `src` reset; discard
derived content and leave the block empty
- [x] Remove disconnect confirmation and conversion; resetting a
repeated binding leaves every occurrence empty
- [x] Switching sources validates/loads the target before replacing the
usable binding and leaves both files unchanged
- [x] Revalidate Asset revision and project version when confirmation is
submitted
- [x] Make repeated connect/disconnect operations idempotent
- [x] Prevent disposed, stale, or out-of-order loads from replacing the
newest source
- [x] Keep loading, saving, conflict, empty-file, and open-file actions
off canvas

### 6. Asynchronous persistence and conflicts

- [x] Snapshot the current in-memory authored root after normal
mutations
- [x] Serialize/coalesce rapid edits per resolved Asset and always
prepare against the latest local snapshot
- [x] Allow independent Assets to save concurrently without scope
leakage
- [x] Use one revisioned document session and one ordered save queue per
Asset, even when multiple Content Blocks or render scopes reference it
- [x] After a shared Asset changes, rematerialize every connected
occurrence without persisting their generated instances to project data
- [x] Pin the resolved Asset and exact loaded revision for each write
- [x] Recheck authorization immediately before storage
- [x] Ensure local queued edits never produce stale-revision conflicts
with each other
- [x] On a genuine external revision conflict, preserve local content,
stop writes, and enter the standard reload-required state
- [x] Keep failed non-conflicting writes retryable without discarding
local content
- [x] Finish already accepted persistence writes after a Content Block
unmounts or switches source
- [x] Cancel obsolete loads, materializations, and UI updates after
unmount, reload, or source switch
- [x] Dispose project-scoped roots, queues, parse caches, failure state,
generations, and session subscriptions when the Asset session is
replaced
- [x] Invalidate Asset resources and synchronize open file editors after
successful writes
- [x] Keep multi-root persistence ordered, serial, and non-atomic;
report partial completion without rollback
- [x] Do not add Asset-history undo/redo; native text-editor undo
remains local to the open editor

### 7. Content mode parity

- [x] Empty connected blocks remain selectable and expose the normal
Content-mode `+` affordance
- [x] First insertion renders immediately
- [x] Enter creates and focuses the next paragraph immediately
- [x] Slash commands work in newly created empty paragraphs
- [x] Deleting one selected instance deletes exactly that instance
- [x] Mouse and keyboard moves use the same operation and permissions
- [x] Preserve sibling reorder, nested reparenting, and moves between
editable Content Blocks where `main` permits them
- [x] Preserve content-editable props such as Link `href`
- [x] Preserve copy, paste, cut, multi-cut, wrapping, unwrapping, grid
insertion, selection, Navigator order, and canvas order
- [x] Cover mutation routing centrally, retain the full unconnected
Builder suite, and exercise representative connected interactions in
real Builder E2E

### 8. Template names and permissions

- [x] Resolve only exact user-facing names from the direct flat
Templates list
- [x] Enforce unique names within each Templates list
- [x] Reject duplicate names during rename with inline validation
- [x] Allocate unique names during insert, paste, duplicate, move, wrap,
and unwrap
- [x] Apply valid template properties using the same permissions as
Content mode
- [x] Preserve and warn about ignored design-only, invalid, or stale
properties
- [x] Preserve template shell provenance without serializing expanded
template internals
- [x] Generate deterministic materialized IDs from source identity,
render scope, and authored usage path so focus/selection survives saves
- [x] Warn before renaming or deleting referenced templates; files
remain unchanged
- [x] Provide shared AST-based rename/remove migration operations for
MCP-assisted multi-file cleanup

### 9. Scope, frontmatter, and diagnostics

- [x] Scope materialized content by Content Block ID plus exact
Collection-item/render context
- [x] Prevent repeated instances and dynamic candidates from leaking
generated IDs, template resolution, or diagnostics across scopes while
sharing the underlying Asset source and revision where applicable
- [x] Remove frontmatter editing from Settings; edit the exact YAML
through the MDX Asset file editor
- [x] Preserve the exact frontmatter source byte-for-byte during canvas
body saves
- [x] Route canvas body changes and complete-file editor saves through
one revisioned per-Asset coordinator
- [x] Show a source warning indicator in Settings and precise
source-located diagnostics in the Asset editor
- [x] Deduplicate repeated diagnostics without losing distinct locations
- [x] Keep unresolved-template placeholders selectable and accessible
only in Builder

### 10. Asset references, transfer, and integrity

- [x] Discover and rewrite Asset references in frontmatter, Markdown
links/images, and MDX properties
- [x] Preserve Asset references while editing unrelated content
- [x] Include referenced Asset and template revisions in
dependency/cache identity
- [x] Route referenced Assets through published URL rewriting
- [x] Validate Content Block source integrity during project import,
fragment/page transfer, copy/paste, build integrity, and pre-publish
audit
- [x] Allow multiple Content Blocks and dynamic render scopes to
reference the same MDX Asset without treating the connection as an
integrity error
- [x] Preserve Templates when copying a connected Content Block
- [x] Preserve direct and dynamic Content Block source bindings when
copying or pasting within the same project
- [x] When copying only one rendered Collection item, resolve that
item’s current MDX Asset and replace the copied Content Block’s dynamic
source with a direct binding to that same Asset
- [x] When copying an entire Collection, preserve the Collection, its
instances, and its dynamic source bindings
- [x] Preserve the complete MDX source and frontmatter by reference;
copying a connected block must not rewrite the shared file
- [x] During cross-project transfer, copy every discoverable distinct
bound MDX Asset and rewrite transferred bindings to the destination
Assets
- [x] If some cross-project dynamic candidates cannot be discovered or
copied, continue with successful copies, preserve what can be
represented safely, and warn about skipped candidates
- [x] Revalidate source revisions and the destination project before
applying a cross-project transfer
- [x] If cross-project Asset creation or project insertion fails, leave
the source project unchanged and clean up any newly reserved destination
Asset
- [x] Use the same transfer operation through Builder and MCP

### 11. Dynamic sources and publication

- [x] Resolve dynamic bindings once per render/save scope
- [x] Require finite, discoverable candidate sets for publication and
load no unrelated MDX
- [x] Warn and skip unbounded, missing, unreadable, malformed, or unsafe
sources without failing the complete build
- [x] Materialize only rendered Content Blocks; ignore Templates
definitions and `src` on non-Content-Block instances
- [x] Skip unresolved template subtrees while keeping valid siblings
- [x] Include selected template styles, fonts, resources, unresolved
names, and referenced Asset revisions in generated dependency output
- [x] Keep draft-only MDX Assets out of publication retention

### 12. Builder, MCP, CLI, and shared operations

- [x] Use the same converters, source lifecycle, revision checks,
persistence service, diagnostics, and template migrations in Builder and
MCP
- [x] Keep frontmatter editing file-based; retain whole-frontmatter
runtime operations only where compatibility requires them
- [x] Avoid Builder-only or MCP-only mutation/conversion implementations
- [x] Regenerate runtime/API contracts from their source definitions
- [x] Update CLI Content Engine reference and generated MCP
documentation

### 13. Verification and delivery

- [x] Add regression tests that reproduce failures from the previous
implementation, including double deletion and blocked rendering
- [x] Cover two Content Blocks sharing one Asset: edits from either
block serialize once, update both canvases, preserve scope-specific
Templates, and cannot overwrite a newer local snapshot
- [x] Verify new tests fail against the broken implementation and pass
with the corrected behavior
- [x] Run SDK, Content Engine, Asset Uploader, Project Build, Builder,
React SDK, CLI, Protocol, and HTTP Client affected suites and typechecks
- [x] Run real Builder E2E for source lifecycle, live file refresh,
empty insertion, Enter/slash focus, Link props, delete, keyboard
reorder, switching, disconnect, conflicts, unresolved templates, dynamic
sources, and repeated scopes
- [x] Regenerate shared project fixture bundles and verify a second
generation leaves the tree clean
- [x] Run lint, package boundaries, `pnpm oxfmt --check`, and `git diff
--check`
- [x] Review and update authoritative `docs/` content and navigation
- [ ] Run the complete agent evaluation suite — not run because it
requires separate explicit approval

### 14. Content-mode parity and disconnect handoff

- [x] Allow keyboard reordering in Content mode through the normal move
command while keeping the editable Content Block boundary
- [x] Let already accepted Asset writes drain independently before
resetting the source; disconnect does not load, flush, or convert the
file
- [x] Remove MDX-to-instance copying from disconnect
- [x] Reset `src`, remove the derived tree, and leave the ordinary
Content Block empty
- [x] Preserve automatic text-editor focus after inserting editable
content from the template menu
- [x] Remove Builder frontmatter-save UI and report complete-file save
failures through the Asset editor
- [x] Add regression coverage for keyboard movement, disconnect
teardown, source switching, insertion focus, and paragraph deletion
focus restoration
- [x] Run the complete six-scenario MDX Content Block Builder E2E suite

### 15. Final architecture review fixes

- [x] Keep one canonical ordered pending document per Asset so shared
Content Block occurrences cannot conflict with one another
- [x] Merge ordered local edits from different occurrences while
preserving text changes, insertions, deletions, and sibling reordering;
keep external revisions on the strict reload-required path
- [x] Centralize typed render-scope parsing, repeated-occurrence
detection, scoped variable lookup, and dynamic Asset resolution across
Canvas, Settings, source lifecycle, and copy/paste
- [x] Capture the owning Asset session when a save is accepted so normal
unmount/source-switch teardown cannot redirect or lose it
- [x] Dispose project-owned roots, queues, caches, generations, failure
state, and subscriptions when replacing the project Asset session
- [x] Add regression coverage for same-Asset edits from two occurrences,
same-node last-write ordering, structural reorder, insertion
preservation, scoped source resolution, and project cleanup
- [x] Re-run affected full unit suites, typechecks, production build,
static checks, and all six MDX Content Block Builder E2E scenarios


### 16. Final persistence and transfer hardening

- [x] Drain every accepted per-Asset edit before project-session
teardown while retaining the owning authorization context
- [x] Drain canvas serialization queues and revisioned Asset writes
before pre-publish audit and publication
- [x] Block publication on a queued serialization failure or Asset
revision conflict
- [x] Copy actual Asset bytes during cross-project paste, preserve MDX
reference names, rewrite direct and Collection-backed Asset IDs, and
clean up newly created Assets when insertion fails
- [x] Include every resolved dynamic MDX source when copying an entire
Collection and warn while preserving successful copies when individual
Assets cannot be transferred
- [x] Keep MDX editor save failures visible with retry and route
conflicts through the standard reload-required flow
- [x] Give keyboard nested reparenting the same editable Content Block
boundary used by pointer movement
- [x] Add regression coverage and rerun the complete Content Engine and
Builder unit suites plus type, lint, formatting, package-boundary, and
diff checks

## Current rebuild status

- The connected Content Block now owns one complete MDX document:
frontmatter feeds designed-shell bindings and the explicit Body outlet
owns the authored MDX body.
- Builder and published output resolve the same frontmatter document
graph, including nested document references and Asset references.
- Direct frontmatter text/property edits use the existing ordered
per-Asset session; referenced-document values remain file-owned.
- Repeated Collection occurrences keep isolated runtime shell/Body
identities and occurrence-specific document values.
- The local blog article layout has been upgraded to the document/Body
model and its bindings validate cleanly.
- Full affected package suites and typechecks pass; every new regression
was demonstrated fail/pass.
- `pnpm lint`, package boundaries, `pnpm oxfmt --check`, generated
API/docs checks, fixture builds, and `git diff --check` pass.
- Full fixture synchronization is blocked by the development API
rejecting this local CLI version before fixture generation; existing
fixture bundles build successfully.
- Complete agent evaluations remain pending explicit approval.

### 17. Treat Content Block source as a property

- [x] Declare Content Block `src` in component metadata as a Design-mode
initial property labeled **Source**
- [x] Add the short property description: “Create an .mdx file in
Assets, then select or bind it here.”
- [x] Accept only a direct Asset or an expression resolving to an Asset
ID; reject URL/string sources, missing Assets, and non-MDX Assets
- [x] Extract and reuse the Image-style Asset picker and binding
presentation without duplicating source-control UI
- [x] Render Source through the normal properties section and remove the
separate source-section placement and special `src` filtering
- [x] Route Source changes through Content Block connect, switch, and
disconnect lifecycle operations instead of generic prop updates
- [x] Keep connect confirmation, Open, diagnostics, and persistence
state attached to Source; remove frontmatter and disconnect UI
- [x] Add regression coverage for direct Assets, dynamic Asset bindings,
invalid resolved values, lifecycle operations, and Design/Content mode
visibility
- [x] Re-review authoritative `docs/` content for the Source-property UI
change and update it if required

### 18. Source property UX

- [x] Show one full-width bindable Connect .mdx file button while
disconnected
- [x] Show equal-width filename and Open buttons while connected
- [x] Switch files from the filename button through the source lifecycle
- [x] Override PropertyLabel reset and Alt-click with the disconnect
lifecycle
- [x] Preserve confirmation, pending, failure, repeated-scope, and
dynamic-source behavior
- [x] Add regression coverage for connect, switch, binding, reset, and
disconnect
- [x] Update Content Block documentation
- [x] Run affected tests, typecheck, lint, formatting, package
boundaries, and diff checks


### 19. Reduced file-owned frontmatter follow-up

This checklist supersedes the earlier structured-frontmatter and
disconnect-copy behavior. Frontmatter remains file-owned and is edited
only in the MDX Asset editor.

#### A. Remove structured frontmatter UI

- [x] Remove the JSON frontmatter editor and unused Builder
controller/state
- [x] Keep source mutation Design-mode-only; show connected Source
read-only in Content mode and allow authorized editors to open the
complete file
- [x] Retain runtime frontmatter APIs only where compatibility requires
them

#### B. Preserve source and separate validation

- [x] Preserve the exact frontmatter envelope during every canvas body
save without parsing/stringifying YAML
- [x] Preserve comments, ordering, quoting, whitespace, BOM, newline
style, delimiters, and invalid but closed YAML
- [x] Keep the existing unsupported-node/property MDX recovery; do not
add an ad hoc partial parser
- [x] Parse body and frontmatter independently so either valid half
remains usable
- [x] Keep bounded Asset-query frontmatter extraction unchanged
- [x] Treat structurally malformed MDX as having no safe body tree

#### C. Share Asset state with the raw editor

- [x] Route canvas and complete-file changes through one ordered,
non-blocking per-Asset coordinator
- [x] Update canvas and clean raw editors immediately from shared
in-memory source
- [x] Reject stale dirty-editor saves, preserve unsaved text, and
require reload; never force-overwrite
- [x] Drain accepted writes after source replacement/disconnect and
report background failures globally
- [x] Dispose sessions only after they have no consumers and no queued
work

#### D. Connect, replace, and disconnect

- [x] Load and diagnose before connect; block only
unreadable/unauthorized/non-MDX Assets
- [x] Show **Abort / Connect** for non-empty blocks, including
diagnostics and the recoverable-content warning
- [x] Set `src` and delete persisted children through one runtime
mutation
- [x] Switch to a loaded source without waiting for the previous Asset's
network save
- [x] Remove disconnect confirmation and conversion
- [x] Reset `src` immediately, discard the derived tree, leave the block
empty, and preserve the Asset
- [x] Resetting a bound source leaves every repeated occurrence empty

#### E. Dynamic and shared sources

- [x] Keep one source/revision state per Asset and a separate derived
instances tree per occurrence
- [x] Resolve Templates independently per Content Block and preserve
Builder-only missing-template placeholders
- [x] Resolve bound `src` from the selected Collection occurrence
- [x] Make **Open** use the occurrence's resolved Asset; update the
filename and disable Open when unresolved
- [x] Add direct/bound tests including Collection item A opening `a.mdx`
and item B opening `b.mdx`

#### F. Diagnostics, MCP, and publication

- [x] Show an accessible warning icon beside Source with the first
diagnostic, line/column, and remaining count
- [x] Show precise YAML/MDX diagnostics in the Asset editor without
repetitive canvas/toast UI
- [x] Reuse parser/diagnostic/revision contracts in Builder, build,
publication, and MCP
- [x] Keep MCP frontmatter editing file-based and return structured
diagnostics for complete-source writes
- [x] Emit build warnings; published sites skip invalid/unsupported
content without diagnostic UI

#### G. Verification and documentation

- [x] Add fail/pass regressions for source preservation, independent
validation, stale raw saves, lifecycle, dynamic Open, shared Assets, and
cleanup
- [x] Run affected tests, typechecks, lint, formatting, package
boundaries, fixtures, and diff checks
- [x] Open Markdown and MDX editors at twice the default dialog size
with the right-side preview visible initially
- [x] Document canvas body editing, file-owned frontmatter, Content-mode
Asset access, and cloning an MDX Asset for a new post
- [x] Perform a final correctness, data-loss, DRY, simplification,
accessibility, and performance review
- [x] Keep this checklist synchronized with implementation status

### 20. Content-mode component properties

- [x] Show a connected Content Block Source read-only in Content mode
with an active **Open** action
- [x] Keep source switching, binding, reset, and disconnect available
only in Design mode
- [x] Expose HTML Embed code and preserve Code Text's code-editor
metadata on authored Text Content
- [x] Audit every registered component and expose authored payload while
keeping design, structure, and behavior controls in Design mode
- [x] Keep media dimensions and Code Text theme Design-only while
preserving adapter-owned intrinsic Image metadata during MDX round trips
- [x] Add exact component-permission and regression coverage
- [x] Update authoritative component documentation
- [x] Run affected full suites, typechecks, formatting, lint, package
boundaries, and generated contract/documentation checks


### 21. Designed document shell and Body outlet

- [x] Add one structural **Content Block Body** outlet and keep legacy
Content Blocks without it compatible
- [x] Materialize and persist only `document.body` children through the
Body outlet while preserving the surrounding designed shell and
Templates
- [x] Expose the connected document frontmatter through a Content Block
`document` parameter for shell text and property bindings
- [x] Write direct frontmatter-bound text and properties back through
the same ordered per-Asset session without blocking canvas mutations
- [x] Resolve document `$ref` dependencies and Asset references
consistently in Builder and published output
- [x] Keep referenced-document values read-only on canvas and direct
editors to the referenced file
- [x] Isolate repeated Collection occurrences while retaining
occurrence-specific source, frontmatter, shell, and Body content
- [x] Render the same designed shell, frontmatter values, and Body
substitution in generated/published output
- [x] Upgrade the local blog article layout to bind title, excerpt,
dates, author data, and images from frontmatter and render MDX through
Body
- [x] Add fail/pass regressions for nested Body discovery, lifecycle,
permissions, repeated values, document references, and generated shell
rendering
- [x] Update authoritative Content Block documentation
- [x] Run affected tests and typechecks, formatting, lint, package
boundaries, generated API/docs checks, and fixture builds


### 22. Final nested references and frontmatter editing

- [x] Keep direct frontmatter-bound text and property controls editable
in Content mode without exposing or replacing their bindings
- [x] Keep referenced-document values read-only and preserve legacy
instance-property name normalization
- [x] Render direct frontmatter text bindings through the plain-text
editing path
- [x] Resolve nested legacy and structured Asset references from
referenced Markdown/MDX frontmatter
- [x] Preserve missing Asset references, emit structured
`ASSET_NOT_FOUND` diagnostics, and keep them out of the document graph
- [x] Add fail/pass regressions for the real Settings control and
root/nested missing Asset-reference cases
- [x] Fix exact Content Block selection after the Body node appears in
Navigator
- [x] Run full affected suites/typechecks, all six MDX Content Block E2E
scenarios, deterministic fixture builds, generated checks, lint,
formatting, package boundaries, and diff checks

### Before merge

- [x] Resolve #6261: Nested Asset references in referenced Markdown
frontmatter work consistently in Assets queries, previews, publication,
and static export


### 23. Explicit writable expression bindings

- [x] Add an explicit `readwrite` mode to expression bindings; existing
expressions remain read-only by default
- [x] Accept `readwrite` only for direct static member paths and
centralize their parsing and validation
- [x] Require the expression root to provide a writable data source;
initially support the connected Content Block document frontmatter
- [x] Update Content Block permissions, canvas text editing, and
property controls to require a valid writable binding
- [x] Persist direct frontmatter edits through the existing ordered
per-Asset session
- [x] Create new direct frontmatter bindings with `readwrite` mode and
migrate existing compatible bindings
- [x] Preserve writable mode through schemas, serialization, loading,
copy/paste, transfer, and export
- [x] Add fail/pass regressions for valid paths, derived expressions,
unsupported sources, permissions, persistence, and compatibility
- [x] Review authoritative `docs/` content and update it if the
persisted binding contract affects user-facing documentation
- [x] Reject unsafe frontmatter paths and reject `readwrite` bindings
outside a connected Content Block document
- [x] Preserve expression binding mode through the public HTTP client
and document the MCP authoring contract
- [x] Limit frontmatter value write-back to Content mode so Design mode
retains normal binding replacement/reset behavior
- [x] Keep bindings inside Templates and across nested Content Block
ownership boundaries read-only
- [x] Upgrade compatible legacy bindings even when the Content Block is
disconnected during migration
- [x] Run affected tests, typechecks, formatting, lint, package
boundaries, fixture checks, and `git diff --check`

Verification: full SDK (567), Project Build (2,277), and Builder (2,695)
suites pass, along with affected Expression, Migration, Template, HTTP
Client, and MCP suites; typechecks, lint, formatting, package
boundaries, and diff checks pass. Generated contracts are refreshed.
Fixture synchronization remains blocked before generation because the
development API rejects this local CLI version as incompatible. The
checked-in bundles pass the current Protocol suite and every fixture
build with the current bundle version.
2026-08-29 20:15:20 +02:00
Oleg Isonen 5a57234c75 revert: Store Content Block content in MDX assets
Revert the accidental merge of #6125 so the implementation can continue in draft PR #6181.
2026-08-18 13:23:32 +01:00
Oleg Isonen 86b6310fff feat: Store Content Block content in MDX assets 2026-08-17 15:22:20 +01:00
Oleg Isonen 08e1e19b3f fix: expose existing text bindings in mixed content (#6008)
Closes #5992

## Summary

Expose the existing **Text content** binding control when a directly
text-capable selected instance contains expressions alongside other
content.

The supplied reading-time span keeps its existing child sequence:

- static prefix text
- bound expression

No data migration or new Settings editor is introduced. Normalization
happens only when the user explicitly resets a binding.
Expression-bearing nodes are excluded from canvas text editing because
the canvas editor cannot represent bindings safely. Literal descendants
in mixed trees remain canvas-editable, while bindings remain editable
through Settings.

## Implementation

- Reuse the existing scalar Text content and binding UI.
- Target expression children with indexed `instances.updateText`
mutations, preserving instance boundaries and unrelated siblings.
- Fail closed when the selected instance is missing or no longer has a
safe text target.
- Evaluate expressions through the binding control's existing live
scope.
- Centralize text-content target classification in project-build for
reuse by the engine and Builder.
- Reset every expression atomically through the engine's
`instances.setTextContent` operation, validate the complete replacement
set, and coalesce adjacent text nodes without crossing nested-instance
boundaries.
- Centralize expression-free canvas text-editor targeting in the
project-build lookup module.
- Route double-click, Enter, post-insert editing, cursor generation, and
keyboard navigation through the shared lookup rules.
- Exclude single-expression and mixed/nested expression targets from the
canvas editor in every mode.
- Preserve canvas editing for literal descendants inside otherwise mixed
content.
- Share canvas fixtures and simplify binding-removal capability to an
optional handler.

## Verification

- [x] Settings exposes and edits mixed text/expression targets without
replacing siblings.
- [x] Reset binding converts every expression on the instance and
normalizes adjacent text.
- [x] Missing, unsupported, stale, and incomplete replacement sets fail
closed.
- [x] Double-click and Enter do not open bound nodes in the canvas
editor.
- [x] Literal descendants within mixed trees remain canvas-editable.
- [x] Complete Builder suite passes (2,497 tests).
- [x] Complete project-build suite passes (2,070 tests).
- [x] New targeted Builder and project-build regression tests pass (175
tests).
- [x] Builder and project-build typechecks pass.
- [x] Repository lint passes.
- [x] Package-boundary validation passes.
- [x] Generated runtime operation contracts are updated from source.
- [x] Fixture inputs and outputs are unaffected.
- [x] Documentation impact reviewed: no documentation update is needed.
- [ ] Interactive browser smoke test was unavailable because the in-app
browser failed to initialize.
- [ ] Agent evaluations were not run because they require separate
approval.

## CI note

The previous head's Main workflow failed while pulling the E2E database
image with Docker Hub `toomanyrequests: Rate exceeded`. Lost Pixel
failed separately with a certificate error. Both are external
infrastructure failures; branch formatting, lint, package boundaries,
generated contracts/docs, tests, and typechecks were successful in that
run.

Supersedes #5993, which GitHub closed automatically when its head branch
was renamed.
2026-08-04 15:36:19 +02:00
Oleg Isonen ef94d85ccf feat: drag image assets onto canvas (#5912)
## Summary

- allow dragging a single image asset from the Assets panel onto the
canvas
- insert an Image component with its source bound to the dragged asset
in one undoable mutation
- preserve asset-folder drops and canceled drags
- build the Builder once in CI and reuse the compact build artifact
across all E2E shards

## E2E timing

Recent CI showed shard test runtimes of roughly 101–145 seconds, while
every shard also repeated a roughly two-minute Builder build. The four
shards are already reasonably balanced, so a fifth shard would not
address the primary bottleneck.

The shared artifact is about 30 MB uncompressed and roughly 5 MB
compressed because checked-out public assets are excluded. This should
return individual shard jobs to the 2–3 minute range.

## Validation

- 45 focused unit tests
- image asset to canvas E2E using the prebuilt-artifact path
- image asset to folder regression E2E
- Builder typecheck
- lint
- package-boundary validation
- workflow YAML validation
- shell syntax validation
2026-07-18 09:15:02 +02:00
Oleg Isonen dde30ffb54 feat: Improve MCP authoring, compact output, and agent onboarding (#5883)
## Summary

This improves how agents discover, author, inspect, and verify Webstudio
projects while reducing unnecessary MCP context usage.

## What changed

- Adds an **Agents** section to Project Settings with ready-to-run setup
commands and client configuration for Claude Code, Codex, Cursor, and VS
Code.
- Makes large list and schema responses compact and paginated by
default, with **verbose** available when complete records or diagnostics
are needed.
- Applies consistent compact output to assets, instances, styles, design
tokens, CLI schemas, and project-session metadata.
- Returns actionable expression warnings for props, resources, and
Collection bindings, including unknown variables and risky render-time
mutation resources.
- Improves Collection expression guidance so agents can bind array items
with the correct scoped variables.
- Reports rendered audit outcomes explicitly as complete, partial,
confirmation-required, or failed.
- Expands runtime output schemas so MCP clients can validate responses
reliably.
- Strengthens the packaged CLI smoke workflow with a realistic
seven-page stdio MCP scenario.

## Architecture

- Consolidates `project-build` from 65 file-oriented entrypoints to 11
architecture-owned surfaces.
- Separates the core model, contracts, runtime authoring, transfer,
state, project sessions, MCP, visual tooling, persistence codecs, and
authenticated server services.
- Isolates Node-only JSX evaluation from browser-safe transfer utilities
and authenticated server modules.
- Keeps persistence codecs independent from authenticated database
services, preventing unrelated module initialization.
- Defines shared instance-path types once and reuses them across runtime
modules.
- Preserves Immer initialization through explicit package side-effect
metadata.
- Adds package tests that prevent a return to source-file entrypoints or
generic exposure of Node-only surfaces.

## Validation

- Full repository checks, tests, typechecks, generated-file checks, and
fixtures
- All 163 Builder test files and 2,141 tests
- All 71 project-build test files and 1,794 tests
- Lint and package-boundary validation
- Full packed CLI release smoke test, including install, preview, agent
setup, seven-page stdio MCP workflow, rendered audit, and structured
commands
2026-07-15 18:11:28 +02:00
Oleg IsonenandClaude Fable 5 68b7458720 fix: restrict content mode text editing on canvas (#5866)
In content mode user should only edit what's inside a content block.

---------

Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-12 02:18:44 +02:00
Oleg Isonen d291e4b671 feat: Builder api runtime contracts guardrails for MCP (#5857)
This PR expands Webstudio MCP and CLI into a more complete agent
authoring interface. Agents can discover project capabilities, edit real
Webstudio content, use data/resources, verify visual output, and report
useful issues when workflows fail.

## MCP User Capabilities

- Create, update, duplicate, reorder, and delete pages.
- Create pages from templates and manage reusable page templates.
- Inspect project pages, instances, props, styles, assets, variables,
resources, and metadata.
- Insert Webstudio components and authored JSX fragments into pages.
- Edit text, props, styles, breakpoints, design tokens, and CSS
variables.
- Update page metadata, SEO fields, redirects, marketplace metadata, and
project settings.
- Create and use static data variables.
- Create and use dynamic resources fetched over HTTP.
- Use REST, GraphQL, and built-in system resources in authored pages.
- Bind data variables and resources to visible page content.
- Create resource-backed pages such as sitemap XML, structured SEO data,
and API-driven content sections.
- Preview current project state without requiring a publish step.
- Capture screenshots for visual verification.
- Verify responsive designs across desktop, tablet, and mobile
breakpoints.
- Use screenshot diff and OCR-style checks to inspect rendered output.
- Reset and refresh local MCP project state when needed.
- Discover available CLI/MCP commands from generated manuals.
- Use clearer examples for resources, data variables, JSX authoring,
previewing, and visual checks.
- Read marketplace product metadata without requiring a full project
snapshot.
- Get safer guidance when using low-level patch tools.
- Get a ready-to-copy Discord report template when MCP/CLI behavior is
confusing or broken.
2026-07-10 02:13:22 +02:00
Oleg Isonen 2a77c2a8b5 feat: Multiselect (#5834)
Closes https://github.com/webstudio-is/webstudio/issues/5310
2026-06-24 21:20:33 +02:00
Oleg Isonen 82c3d83fd1 fix: optimize CLI import for large data amount (#5831)
## Summary

- Add CLI project import support from synced `.webstudio/data.json` into
another project via a destination share link.
- Move project bundle import/export contract into
`@webstudio-is/protocol`, including bundle versioning, staged upload
constants, schema validation, and fixture coverage.
- Upload project bundle data through staged TUS upload before calling
the import RPC to avoid request body limits.
- Upload referenced assets as binary files through the existing asset
upload route before importing asset rows.
- Add `--skip-assets` and `--ignore-version-check` import options.
- Add retry handling for transient missing imported asset files by
re-uploading only the reported missing assets.
- Share missing-asset import error formatting/parsing through protocol
to avoid duplicated string contracts.
- Preserve browser asset upload behavior while adding API upload
support.
- Normalize schema naming across the branch to lower-case names without
`Schema` suffix.
2026-06-23 18:50:01 +02:00
Oleg Isonen e7b7faeca5 fix: performance optimizations (#5827) 2026-06-19 12:23:44 +02:00
Oleg Isonen ac29cf7d1d feat: Keyboard shorthands for instance positioning and slot bug fixes (#5821)
Closes https://github.com/webstudio-is/webstudio/issues/4586
Closes https://github.com/webstudio-is/webstudio/issues/4619

## Summary

Fixes shared Slot editing so linked Slot occurrences stay consistent
across structural edits and labels.

## Changes

- Fixed moving a direct Slot child out of a Slot so the child is removed
from all linked Slot occurrences.
- Fixed unwrapping a direct Slot child so the child is removed from all
linked Slot occurrences.
- Added linked Slot label sync when renaming from Navigator or Settings
panel.
- Added/updated tests for canonical Slots, legacy Slots, nested Slot
children, keyboard moves, unwrap, reparent, and label sync.
- Simplified stale Slot detach logic that was incorrectly cloning only
the selected Slot occurrence.

## Testing

- `pnpm --filter @webstudio-is/builder test --
app/shared/instance-utils/...`
- `pnpm --filter @webstudio-is/builder test --
app/builder/shared/commands.test.ts`
- `pnpm --filter @webstudio-is/builder typecheck`
- `pnpm lint`
- `git diff --check`
2026-06-16 02:25:28 +02:00
Oleg Isonen d49582bcf5 feat: Copy-paste pages, folders and page templates (#5798)
Closes https://github.com/webstudio-is/webstudio/issues/5797
## Summary

- Add page, page template, and folder copy/paste support, including
cross-project paste.
- Reuse a shared page item actions menu for page headers and context
menus with Copy, Duplicate, Delete, and shortcut hints.
- Add Paste to the pages context menu.
- Preserve template semantics when copying/pasting templates.
- Support folder copy with nested folders/pages.
- Add Backspace/Delete page deletion shortcuts and focus destructive
dialog actions for Enter confirmation.
- Rename `init-copy-paste.ts` to `copy-paste.ts`.

## Testing

- `pnpm --filter @webstudio-is/builder typecheck`
- `pnpm --filter @webstudio-is/builder test
app/shared/copy-paste/copy-paste.test.ts
app/shared/copy-paste/plugin-page.test.ts app/shared/page-utils.test.tsx
app/builder/features/pages/page-utils.test.ts`
- `git diff --check`
- E2E copy/delete flows were added in
`apps/builder/e2e/tests/pages-actions.e2e.ts`
2026-06-09 15:10:52 +02:00
Oleg Isonen b006947a85 feat: WIP realtime collaboration to builder (#5726)
https://github.com/webstudio-is/webstudio/issues/46
2026-04-27 23:19:21 +02:00
Oleg Isonen 04188dbbf4 feat: CSS Grid UI (#5614)
## Description

1. What is this PR about (link the issue and add a short description)

## Steps for reproduction

1. click button
2. expect xyz

## Code Review

- [ ] hi @kof, I need you to do
  - conceptual review (architecture, feature-correctness)
  - detailed review (read every line)
  - test it on preview

## Before requesting a review

- [ ] made a self-review
- [ ] added inline comments where things may be not obvious (the "why",
not "what")

## Before merging

- [ ] tested locally and on preview environment (preview dev login:
0000)
- [ ] updated [test
cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md)
document
- [ ] added tests
- [ ] if any new env variables are added, added them to `.env` file
2026-03-08 10:52:21 +01:00
Oleg Isonenandzehjotkah d87142965c feat: Breakpoint simulator (#5608)
## Problem

When defining CSS variables with different values for condition-based
breakpoints (e.g., `prefers-color-scheme:dark` vs
`prefers-color-scheme:light`), designers had no way to preview these
variations without manually changing system preferences.

Example:
```css
:root {
  --primary-color: #000;
  --background: #fff;
}

@media (prefers-color-scheme: dark) {
  :root {
    --primary-color: #fff;
    --background: #000;
  }
}
```

Previously, testing dark mode required switching OS settings back and
forth.

## Solution

Implements runtime CSS media rule manipulation to simulate
condition-based breakpoints without changing system settings. When a
designer selects a condition-based breakpoint, the simulator dynamically
modifies CSS media rules:

- Matching rules (e.g., `prefers-color-scheme:dark` when dark is
selected) → replaced with `(min-width: 0px)` (always true)
- Non-matching rules → appended with `(max-width: 0px)` (always false)
- Original media queries are stored and restored when switching away

## Features

**Core Functionality:**
- Simulates media query conditions by replacing them with
always-true/false queries
- Supports all condition-based media features (`prefers-color-scheme`,
`prefers-reduced-motion`, etc.)
- Handles both spaced and non-spaced formats

**Performance:**
- Caches media rules by feature to avoid repeated DOM traversal
- Debounces rapid breakpoint changes (50ms)
- Uses WeakMap for automatic memory management

**Robustness:**
- Validates restoration success with warning logs
- Handles CORS-restricted stylesheets gracefully
- Proper cleanup on abort signal with cache clearing

## Technical Implementation

**Key Functions:**
- `parseCondition()` - Parses condition strings
- `getMediaRulesForFeature()` - Caches and retrieves relevant media
rules
- `applySimulation()` - Debounced application of media rule
modifications
- `restoreAllRules()` - Restores original media queries
- `subscribeBreakpointSimulator()` - Integrates with nano-states and
lifecycle

**Integration:**
- Subscribes to `$selectedBreakpoint` nano-state
- Runs in design mode only
- Cleanup via AbortSignal

## Testing Instructions

**Setup:**
1. Create CSS variables with condition-based values
2. Configure breakpoints with conditions (e.g.,
`prefers-color-scheme:light`, `prefers-color-scheme:dark`)

**Test Cases:**
- Select condition-based breakpoint → verify canvas reflects correct
theme without changing OS settings
- Rapidly switch between breakpoints → verify smooth transitions
- Switch to width-based breakpoint → verify original media queries are
restored
- Check console for errors (should only see warnings for legitimate
issues)

## Impact

Designers can now preview dark/light themes and other condition-based
styles instantly without changing system settings, significantly
improving the workflow for building modern, accessible interfaces.

---------

Co-authored-by: zehjotkah <111518041+zehjotkah@users.noreply.github.com>
2026-02-05 22:33:20 +01:00
Oleg Isonenandzehjotkah 1f4c53419d feat: Pseudo elements (#5572)
This PR replaces the limited "States" dropdown in the Style Panel with a
flexible input field that supports any CSS selector, pseudo-class, or
pseudo-element. This allows for advanced styling capabilities such as
`:has()`, `:focus-visible`, and complex combinators.

## Key Changes

### Flexible Selector Input
- Replaced the fixed "States" category list with a free-form input
field.
- Supports **any** valid CSS selector (e.g., `:hover`, `::before`,
`:has(:checked)`).
- Validation logic ensures only valid selectors are accepted (triggered
on `Enter` key).

## How to Test
1. Select an element and open the Style Panel.
2. Click on the Local style source or a Token.
3. In the input field (bottom of menu), type a selector like `:hover` or
`:first-child` and press Enter.
4. Verify the selector is added and selected.

---------

Co-authored-by: zehjotkah <111518041+zehjotkah@users.noreply.github.com>
2026-01-19 17:28:47 +01:00
Oleg Isonen ff2e086632 feat: Convert instance to an instance of a different component (#5522)
Closes https://github.com/webstudio-is/webstudio/issues/5523

## Description

- convert command now shows a list of available components
- along the way cleaned up commands.ts and made namespaced subscribe api
to subscribe for specific actions

## Steps for reproduction

1. click button
2. expect xyz

## Code Review

- [ ] hi @kof, I need you to do
  - conceptual review (architecture, feature-correctness)
  - detailed review (read every line)
  - test it on preview

## Before requesting a review

- [ ] made a self-review
- [ ] added inline comments where things may be not obvious (the "why",
not "what")

## Before merging

- [ ] tested locally and on preview environment (preview dev login:
0000)
- [ ] updated [test
cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md)
document
- [ ] added tests
- [ ] if any new env variables are added, added them to `.env` file
2025-12-16 22:17:18 +01:00
Oleg Isonen dcdac0eaa7 feat: Project settings dialog accessible from dashboard (#5514)
## Description

1. What is this PR about (link the issue and add a short description)

## Steps for reproduction

1. click button
2. expect xyz

## Code Review

- [ ] hi @kof, I need you to do
  - conceptual review (architecture, feature-correctness)
  - detailed review (read every line)
  - test it on preview

## Before requesting a review

- [ ] made a self-review
- [ ] added inline comments where things may be not obvious (the "why",
not "what")

## Before merging

- [ ] tested locally and on preview environment (preview dev login:
0000)
- [ ] updated [test
cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md)
document
- [ ] added tests
- [ ] if any new env variables are added, added them to `.env` file
2025-12-15 17:23:16 +01:00
Bogdan Chadkin f46095ea2a fix: show only one "delete instance" command (#5324)
<img width="501" height="213" alt="image"
src="https://github.com/user-attachments/assets/8a5223e6-dbb7-42c6-89fa-1c8dd3945b52"
/>
2025-07-17 12:01:39 +02:00
Bogdan Chadkin 19a98fa1ae fix: order routes before navigating in preview (#5311)
Ref https://github.com/webstudio-is/webstudio/issues/5223

Navigating within preview didn't work well because we relied on order of
creation and more inclusive routes like `/*` could match before
`/my-page`.

Here fixed it with routes sorting. The algorithm is very simplified but
covers our usecases within builder.
2025-07-01 18:45:25 +03:00
Bogdan Chadkin fa875ab5c1 feat: use body element on new pages (#5222)
Ref https://github.com/webstudio-is/webstudio/issues/3632

Now new project and new page will have body element in the root instead
of body component.

<img width="422" alt="Screenshot 2025-05-20 at 00 15 37"
src="https://github.com/user-attachments/assets/aee568c5-f0e4-40f5-a5a3-e94fc765505d"
/>
2025-05-20 12:24:27 +03:00
Bogdan Chadkin 28e61f49bd experimental: add matching tag when insert element component (#5204)
Ref https://github.com/webstudio-is/webstudio/issues/3632

Now element does not provide default tag and instead builder will try to
find tag matching its parent.

This way we can insert element, give it "ul" tag
and then insert another element into it which will match only "li"


https://github.com/user-attachments/assets/3ea87624-9524-4f2e-91b2-d658d16d7a1b
2025-05-13 12:46:40 +04:00
Bogdan Chadkin 8c91170f63 fix: allow deleting from input in preview mode (#5194)
Fixes
https://discord.com/channels/955905230107738152/1369211497590554675

Delete on canvas is separateed from the one in builder so we can safely
remove preventDefault to allow entering or deleting from inputs in
preview mode.
2025-05-11 13:51:17 +04:00
Bogdan Chadkin e622e08df6 refactor: drop legacy matchers (#5146)
We already fully switched to component content model and no longer
necessary legacy matchers.
2025-04-20 16:59:22 +07:00
Bogdan Chadkin bd77a252c2 refactor: detect empty tags and components (#5132)
Here replaced "embed" and "control" components with content model. Many
components now detect no content based on html content model like with
img or input tags. In other cases component meta can explicitly specify
empty array to not accept anything.

```
meta = {
  contentModel: {
    category: 'instance',
    children: []
  }
}
```
2025-04-17 23:23:20 +07:00
Bogdan Chadkin 3b8c58b435 refactor: use content model to detect rich text (#5109)
Ref https://github.com/webstudio-is/webstudio/issues/3632

Here I finally got rid from "rich-text-child" necessity. With html
elements in the tree it will no longer work so we need a new way to work
with rich text.

Added a few new utilities to content model which detect rich text by
text inside or any textual tags. Span and links can still be detected as
containers rather than children when not surrounded by text and other
textual elements.
2025-04-10 14:16:34 +07:00
Bogdan Chadkin d5bc0f9760 feat: enforce html content model (#5074)
Ref https://github.com/webstudio-is/webstudio/issues/3632

This is a big step into native html elements support. I scraped content
model from html spec and now enforcing all html tags structure so we no
longer need to write custom restrictions.

Now paragraph cannot be nested into heading. Box cannot be nested into
span Text though still can in div Text. Any interactive elements cannot
be nested automatically. List item should have a list as direct parent
(collection and slot are exception because they don't have elements
inside).

Most rules are defined in this table
https://html.spec.whatwg.org/multipage/indices.html#elements-3
2025-04-01 22:07:56 +07:00
Bogdan Chadkin 051c1ba226 refactor: hyphenate style engine (#4977)
Migrated style object model to hyphenated css properties. A lot of
conversions no longer necessary.
2025-03-11 01:01:37 +07:00
Bogdan Chadkin af98a41edf fix: update display from none (#4969)
Fixes https://github.com/webstudio-is/webstudio/issues/4963

Looks like accidentally wrong method was used.
2025-03-08 12:23:47 +01:00
Bogdan Chadkin 21271086f2 fix: prevent inserting into instance with placeholder (#4901)
Closes https://github.com/webstudio-is/webstudio/issues/4897

Added "placeholder" field to component meta to signal the instance
accepts should not be insertion target. This reverts us to previous
behavior even with empty instances.

Also slightly refactored placeholder rendering to use attr() instead of
extra css variable.
2025-02-22 23:56:30 +07:00
Bogdan Chadkin 250b525ef9 refactor: move css generation to sdk (#4889)
No changes. Just moved generateCss from react-sdk to sdk.
2025-02-18 21:14:05 +07:00
Bogdan Chadkin c776166e8a fix: prevent dropping into image instance (#4789)
User reported he was able to drop components into images. Added lookup
for containers first and then for matching ones.

Testing

- add image
- try to drop box into it
2025-01-26 23:24:18 +07:00
Bogdan Chadkin 94f219c249 refactor: rewrite core components templates with jsx (#4756)
Here refactored all core components with jsx templates and moved them to
sdk package. Fixed all imports as well.
2025-01-17 18:29:40 +07:00
Ivan Starkov cbbf694c38 feat: Make canvas cursor style compatible across all browsers (#4727)
## Description

Safari does not change the cursor based on 
`-webkit-user-select: none;`

We need to explicitly set `cursor`

ref #1818

## Steps for reproduction

1. click button
2. expect xyz

## Code Review

- [ ] hi @kof, I need you to do
  - conceptual review (architecture, feature-correctness)
  - detailed review (read every line)
  - test it on preview

## Before requesting a review

- [ ] made a self-review
- [ ] added inline comments where things may be not obvious (the "why",
not "what")

## Before merging

- [ ] tested locally and on preview environment (preview dev login:
0000)
- [ ] updated [test
cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md)
document
- [ ] added tests
- [ ] if any new env variables are added, added them to `.env` file
2025-01-07 09:27:08 +03:00
Ivan Starkov e9fa0cd530 fix: Deleting in the code editor causes the instance on the canvas to be removed. (#4717)
## Description

Removed logic based on preventDefault

## Steps for reproduction

1. click button
2. expect xyz

## Code Review

- [ ] hi @kof, I need you to do
  - conceptual review (architecture, feature-correctness)
  - detailed review (read every line)
  - test it on preview

## Before requesting a review

- [ ] made a self-review
- [ ] added inline comments where things may be not obvious (the "why",
not "what")

## Before merging

- [ ] tested locally and on preview environment (preview dev login:
0000)
- [ ] updated [test
cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md)
document
- [ ] added tests
- [ ] if any new env variables are added, added them to `.env` file
2025-01-05 14:39:23 +03:00
Ivan Starkov 44ca2d2da6 fix: Clicking out of input without selecting dropdown still selects it (#4710)
## Description

closes #4615
Also fixes various of other issues. 

## Steps for reproduction

1. click button
2. expect xyz

## Code Review

- [ ] hi @kof, I need you to do
  - conceptual review (architecture, feature-correctness)
  - detailed review (read every line)
  - test it on preview

## Before requesting a review

- [ ] made a self-review
- [ ] added inline comments where things may be not obvious (the "why",
not "what")

## Before merging

- [ ] tested locally and on preview environment (preview dev login:
0000)
- [ ] updated [test
cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md)
document
- [ ] added tests
- [ ] if any new env variables are added, added them to `.env` file
2025-01-04 13:51:24 +03:00
Ivan Starkov d577a1ffc0 fix: Fix preview on css variables defined on the current element (#4705)
## Description

probably somehow related to #4448



## Steps for reproduction

define --color variable at :root and on current element.

See background or color preview on the current element. 


## Code Review

- [ ] hi @kof, I need you to do
  - conceptual review (architecture, feature-correctness)
  - detailed review (read every line)
  - test it on preview

## Before requesting a review

- [ ] made a self-review
- [ ] added inline comments where things may be not obvious (the "why",
not "what")

## Before merging

- [ ] tested locally and on preview environment (preview dev login:
0000)
- [ ] updated [test
cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md)
document
- [ ] added tests
- [ ] if any new env variables are added, added them to `.env` file
2025-01-04 08:44:42 +03:00
Oleg Isonen 42f57605e6 fix: Fixes hotkeys on radix select, dropdown etc (#4701)
closes https://github.com/webstudio-is/webstudio/issues/4550

## Description

1. Detect radix dropdown,select and co as part of the form controls that
also implement keyboard shortcuts and don't use global shortcuts on
these
2. Simplify shortcut settings by having just one setting that works for
everything: form tags, content editable, radix

## Steps for reproduction

1. click button
3. expect xyz

## Code Review

- [ ] hi @kof, I need you to do
  - conceptual review (architecture, feature-correctness)
  - detailed review (read every line)
  - test it on preview

## Before requesting a review

- [ ] made a self-review
- [ ] added inline comments where things may be not obvious (the "why",
not "what")

## Before merging

- [ ] tested locally and on preview environment (preview dev login:
0000)
- [ ] updated [test
cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md)
document
- [ ] added tests
- [ ] if any new env variables are added, added them to `.env` file
2025-01-03 10:27:00 +01:00
Ivan Starkov c385f6c3a7 fix: Blockquote editing placeholder (#4677)
## Description

Fixes this
<img width="639" alt="image"
src="https://github.com/user-attachments/assets/92f9da6e-c949-445f-bdce-cb95e0ca9ecd"
/>

with 

<img width="431" alt="image"
src="https://github.com/user-attachments/assets/740e19a1-98a3-4b22-951e-2c8e368571ad"
/>


## Steps for reproduction

1. click button
2. expect xyz

## Code Review

- [ ] hi @kof, I need you to do
  - conceptual review (architecture, feature-correctness)
  - detailed review (read every line)
  - test it on preview

## Before requesting a review

- [ ] made a self-review
- [ ] added inline comments where things may be not obvious (the "why",
not "what")

## Before merging

- [ ] tested locally and on preview environment (preview dev login:
0000)
- [ ] updated [test
cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md)
document
- [ ] added tests
- [ ] if any new env variables are added, added them to `.env` file
2024-12-30 19:16:50 +03:00
Bogdan Chadkin 1315731c76 refactor: insert new component copy (#4648)
Our copy paste is able to merge breakpoints so we can leverage it when
generate new component template. Here instead of passing base breakpoint
id I invoke insertWebstudioFragmentCopy with generated breakpoint which
is merged into project one.

Also switched plugin-embed, plugin-markdown and ai to use the same
insertWebstudioFragmentCopy utility.
2024-12-24 23:08:55 +07:00
Ivan Starkov fb67334790 experimental: Use placeholders for editable elements (#4644)
## Description

ref #4595

### TODO:
- [x] - Found bug that deleting last LI does not delete UL
- [x] - Consider removing default texts for paragraph link blockquote
and headings i.e. `Heading text you can edit`


https://p-cfc5b051-3b7a-4a59-a994-44d8d2f8b836-dot-styles.development.webstudio.is/

The following components are considered non-collapsible in **Edit** and
**Content** modes:
*Paragraph*, *Heading*, *ListItem*, *Blockquote*, *Link*.

We are adding placeholders for these components when they are empty,
using the following logic (partially inspired by Notion):

1. **If a component is empty and not being edited**, we display the same
label as shown in the components tree.

![image](https://github.com/user-attachments/assets/a9c41829-ee62-427e-910e-0acd6df1c513)

2. **If a component is empty and being edited**, the behavior depends on
its location:
   - **Inside a content block:**  
- For *Paragraph*, we display: `Write something or press '/' for
commands...`.
     - For all other components, we display the label.  
   - **Outside a content block:**  
     - Always display the label.  

<img width="435" alt="image"
src="https://github.com/user-attachments/assets/96e0c79c-92dc-40c3-a768-db8322a38c3b"
/>


### Update: Default Content Block Component Changed

The default content block component has been updated. Add the new
component

### PS
On Publish and Preview previous behaviour.




## Steps for reproduction

1. click button
4. expect xyz

## Code Review

- [ ] hi @kof, I need you to do
  - conceptual review (architecture, feature-correctness)
  - detailed review (read every line)
  - test it on preview

## Before requesting a review

- [ ] made a self-review
- [ ] added inline comments where things may be not obvious (the "why",
not "what")

## Before merging

- [ ] tested locally and on preview environment (preview dev login:
0000)
- [ ] updated [test
cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md)
document
- [ ] added tests
- [ ] if any new env variables are added, added them to `.env` file
2024-12-23 19:05:15 +03:00
Ivan Starkov a27c8b9c9e experimental: Enter support (#4627)
## Description

ref #4595 

- Enter on block creates new paragraph, text or h1 block if any exists
in templates
- New text added through `/` command is fully selected
- If after command block is empty it's replaced with another block
- esc now closes the `/` menu
- backspace on empty now deletes block


Play here


https://p-0b40acbe-34df-4475-8f52-120d5b97da4e-dot-enter.development.webstudio.is/?mode=content

- [x] - Bug (Next PR)
<img width="325" alt="image"
src="https://github.com/user-attachments/assets/0dfa447b-dbfd-4c60-b553-ca041da23a4f"
/>
to reproduce
`Enter`, `/` select Heading, type `blabla`, then `/`, then `Enter`



## Steps for reproduction

1. click button
2. expect xyz

## Code Review

- [ ] hi @kof, I need you to do
  - conceptual review (architecture, feature-correctness)
  - detailed review (read every line)
  - test it on preview

## Before requesting a review

- [ ] made a self-review
- [ ] added inline comments where things may be not obvious (the "why",
not "what")

## Before merging

- [ ] tested locally and on preview environment (preview dev login:
0000)
- [ ] updated [test
cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md)
document
- [ ] added tests
- [ ] if any new env variables are added, added them to `.env` file
2024-12-20 22:57:02 +03:00
Ivan Starkov ea88935731 feat: RichText edit / command menu (#4621)
## Description

ref #4595

Search is working

<img width="246" alt="image"
src="https://github.com/user-attachments/assets/5dc850e4-6a36-4996-9aaa-f051ac7e977f"
/>

Arrow keys, enter, mouse click is working.



https://p-15889dd9-ed47-46db-9411-fa18c1efb2fe-dot-edit.development.webstudio.is/

- [x] - Enter and click
- [ ] - Repeat > N then close menu (later)
- [x] - In case of select item clear cmd `/blabla`
- [x] - Put cursor inside 1st editable block of the new instance
- [x] - Should work only inside editable content

## Steps for reproduction

1. click button
2. expect xyz

## Code Review

- [ ] hi @kof, I need you to do
  - conceptual review (architecture, feature-correctness)
  - detailed review (read every line)
  - test it on preview

## Before requesting a review

- [ ] made a self-review
- [ ] added inline comments where things may be not obvious (the "why",
not "what")

## Before merging

- [ ] tested locally and on preview environment (preview dev login:
0000)
- [ ] updated [test
cases](https://github.com/webstudio-is/webstudio/blob/main/apps/builder/docs/test-cases.md)
document
- [ ] added tests
- [ ] if any new env variables are added, added them to `.env` file
2024-12-20 16:21:56 +03:00
Bogdan Chadkin 9dd1d8979b experimental: add wrap/unwrap commands (#4588)
Ref https://github.com/webstudio-is/webstudio/issues/1696
https://github.com/webstudio-is/webstudio/issues/4356
https://github.com/webstudio-is/webstudio/issues/3981

Added following new commands

- wrap in box
- wrap in link
- unwrap

All three follow constraints and prevent unwanted wrapping and
unwrapping for example wrap in link will not wrap a text with link or
list with list item cannot be unwrapped.

<img width="420" alt="image"
src="https://github.com/user-attachments/assets/698168e1-d583-43e1-b6f7-bd0185cad7df"
/>
2024-12-16 17:33:22 +07:00
Bogdan Chadkin 302f5daa7f refactor: hardcode asset and upload path in builder (#4579)
We hardcoded asset base url in image loader.
Though locally different one is not resolved properly. So aligned local
and deployed image paths with /cgi/asset/ everywhere. Images are now
uploaded to public/cgi/asset locally.
2024-12-13 23:18:22 +07:00