## 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.
Commit db78ae4 (`feat: Bring back blue token color and remove Figma
token sync pipeline`) deleted
`packages/design-system/src/__generated__/figma-design-tokens` but
`.storybook/preview.tsx` still imports `color` from it, breaking
Chromatic/Storybook builds.
The same `color` export already exists in `design-tokens.ts` (the source
that was previously used to generate the deleted file).
```diff
- import { color } from "../packages/design-system/src/__generated__/figma-design-tokens";
+ import { color } from "../packages/design-system/src/design-tokens";
```
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
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`
## Summary
Fixes insertion into legacy Slot instances whose children are stored
directly under the Slot instead of under the newer hidden Fragment
wrapper.
Previously, adding an element to an old Slot could insert the new
element into the first existing Slot child. The insertion path assumed
the first Slot child was always a Fragment.
## Changes
- Normalize legacy Slot children during insertion by wrapping direct
Slot children in a Fragment.
- Preserve the existing behavior for valid `Slot -> Fragment ->
children` structures.
- Add regression tests for:
- low-level `insertInstanceChildrenMutable`
- UI-facing `insertWebstudioElementAt`
## Validation
```bash
pnpm --filter @webstudio-is/builder test -- app/shared/instance-utils.test.tsx
pnpm --filter @webstudio-is/builder typecheck
```
User reported:
The repeated animation issue has been fixed on Webstudio Cloud hosting,
but the bug still exists — and is actually even worse — on self-hosted
deployments, whether it's on Netlify or Vercel.
Animations sometimes play twice on the initial page load. They also
replay before navigating to another page and when clicking an anchor
link that points to a section on the same page.
Additionally, on the very first visit to the website, the first
interaction with Radix components causes all animations to replay again.
As far as I can tell, this no longer happens after assets are cached,
but the initial glitch is still noticeable and doesn't look very
polished from a user experience perspective.
Originally we made the token color purple to make it more distinct from
local style source, but now local style source is visually different and
having both blue makes sense because when its blue, active style values
are matching the blue color and it makes it more clear what that blue
color on values means.
Closes https://github.com/webstudio-is/webstudio/issues/2966
## Description
Fixes visitor-facing crashes when a text binding resolves to a non-text
value, such as an object returned from a resource.
Generated expression children now render through `renderText`, which
preserves strings and numbers and renders other runtime values as empty
text. This prevents React SSR from throwing `Objects are not valid as a
React child` when resource data shape changes unexpectedly.
## Changes
- Added `renderText(value)` runtime helper.
- Wrapped generated expression children with `renderText(...)`.
- Updated generated page imports to include `renderText`.
- Added rendering tests for resource status/error fields and
object-shaped bindings.
## Tests
```bash
pnpm --filter @webstudio-is/react-sdk test -- context.test.tsx component-generator.test.tsx
pnpm --filter @webstudio-is/react-sdk typecheck
pnpm --filter ./packages/cli typecheck
**Description**
Prevents published pages from rerendering the outgoing generated page
during pending internal navigation.
React Router can rerender the current route while the next route loader
is pending. The generated `Page` was rendered directly inside that
route, so the entire outgoing page could rerender before the next page
appeared.
This adds a memoized `PageBoundary` keyed by `url`, so the generated
page only rerenders/remounts when the actual page URL changes. The SDK
context value is memoized by `resources`, preserving same-URL resource
updates without exposing the full page tree to unrelated
pending-navigation rerenders.
**Changes**
- Added `PageBoundary` to React Router and Remix/default HTML route
templates.
- Kept `key={url}` behavior for HTML Embed script reloads on dynamic
pages.
- Added regression tests for:
- no outgoing page rerender while destination navigation is pending
- same-URL resource changes still update generated page content
- Added Vitest setup for `sdk-components-react-router`.
**Verification**
```txt
pnpm --filter @webstudio-is/sdk-components-react-router test src/link.test.tsx
pnpm --filter @webstudio-is/sdk-components-react-router typecheck
pnpm --filter @webstudio-is/sdk-cli typecheck
```
## Summary
Adds timezone selection support to the Time component.
Users can now choose:
- `UTC` for deterministic server/client rendering
- `visitor` to render UTC during SSR, then update to the browser
timezone after hydration
- an IANA timezone such as `Europe/Berlin`
Also adds a timezone combobox control in the settings panel with common
timezone options, supported IANA timezone values, typed input, and
preview descriptions.
## Changes
- Added `timeZone` prop to the Time component, defaulting to `UTC`
- Updated standard and custom-format date rendering to use the selected
timezone
- Added visitor timezone mode with hydration-safe UTC fallback
- Added `timeZone` prop metadata and settings-panel control support
- Added timezone combobox control with previews
- Added tests for:
- explicit timezone rendering
- custom format timezone rendering
- date rollover in another timezone
- invalid timezone fallback
- trimmed timezone values
- visitor timezone hydration behavior
## Verification
- `pnpm --filter @webstudio-is/sdk-components-react test --
time.test.ts`
- `pnpm --filter @webstudio-is/sdk-components-react typecheck`
- `pnpm --filter @webstudio-is/builder typecheck`
- `pnpm exec prettier --check ...`
**Summary**
Fixes content-mode edit permissions so editor-only users can perform
allowed content workflows without backend “build permission” failures.
**Changes**
- Added shared content-mode permission validation used by backend
authorization.
- Aligned content-mode capabilities around editable props, editable
instances, content roots, pages, assets, and template insertion.
- Allowed content-safe instance/text/page/template/style changes while
keeping design/data/resource changes build-only.
- Updated template insertion to preserve content-safe local styles and
reuse tokens by id.
- Added accessible `SyncStatusDot` for e2e-visible sync state without
replacing the existing sync status UI.
- Added builder e2e setup with Postgres/PostgREST and a first
content-mode browser test:
- edit existing text as an editor-only user
- wait for saved state via the sync status dot
- reload and verify persistence
**Verification**
- `pnpm --filter=@webstudio-is/builder test -- sync-status.test.tsx`
- `pnpm --filter=@webstudio-is/builder typecheck`
- `git diff --check`
- `pnpm e2e:builder`
Adds permission protection around page templates so content editors can
create pages from templates without being able to open, edit, or patch
template pages directly.
## Description
1. Issue: https://github.com/webstudio-is/webstudio/issues/4931
2. Adds V1 of Page Templates for designers:
- stores project-local page templates separately from published pages
- adds a designer-only Page Templates section in the Pages panel
- supports creating, editing, duplicating, deleting, and reordering
templates
- supports creating a regular page from a template through a prefilled
page settings dialog
- makes canvas/page awareness, asset usage, asset replacement, and
page-copy utilities template-aware while keeping templates out of normal
public page lookup paths
## Steps for reproduction
1. Open the builder in Design mode and open the Pages panel.
2. Click the New Template button in the Page Templates section.
3. Fill in template settings, including name, title, description, search
toggle, social image, and custom metadata.
4. Click Create template and expect the new template to appear under
Page Templates and load on the canvas with an editable blank body.
5. Add content to the template canvas, reopen template settings, change
metadata, close/reopen settings, and expect the changes to persist.
6. Click the `+` action on the template row and expect a Create Page
from Template dialog prefilled from the template with a unique page
path.
7. Change page settings, click Create page, and expect a normal page to
be created in the root folder with copied content and metadata while the
template remains unchanged.
8. Right-click a template row, choose Duplicate, and expect a new
independent template copy with a deduplicated name.
9. Drag templates within the Page Templates section and expect the order
to persist.
10. Right-click a template row, choose Delete, confirm deletion, and
expect the template and its canvas tree to be removed. If the deleted
template was selected, expect the builder to navigate back to the home
page.
11. Switch to Content mode and expect template management UI to be
hidden.
12. Use a template social image from Assets, check asset usages, replace
the asset, and expect the template social image reference to update.
## 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
- [x] made a self-review
- [x] added inline comments where things may be not obvious (the "why",
not "what")
## Before merging
- [x] 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
---------
Co-authored-by: shreyanshkotak <sk7739@nyu.edu>
**Summary**
Fixes slot occurrence mutations so operations on one rendered slot
instance do not leak into other slot instances sharing the same slot
content.
**Changes**
- Unwrap now skips the hidden slot `Fragment` and unwraps the visible
slot occurrence on the first command.
- Added shared slot content detachment before path-sensitive mutations:
- delete
- reparent
- wrap
- duplicate
- convert `Slot` to non-slot component
- Added regression tests for two slot instances sharing `fragment ->
div` content.
**Validation**
```bash
pnpm --filter @webstudio-is/builder test -- app/shared/instance-utils.test.tsx
pnpm --filter @webstudio-is/builder typecheck
```
**Summary**
Validates CSS custom property values as raw CSS token streams before
saving/parsing them.
This prevents malformed values like `#sd'` from being normalized into
`sd` or serialized into broken canvas CSS that invalidates the whole
generated rule.
**Changes**
- Added tokenizer-based validation for custom property values.
- Rejects malformed strings, URLs, comments, unmatched blocks, and
trailing backslashes.
- Preserves raw custom property declaration values before `css-tree` can
repair/normalize them.
- Prevents custom property value editing from coercing invalid input
through fallback parsing like `kebabCase()` or color recovery.
- Added regression tests for advanced panel input and CSS data parsing.
**Verification**
- `pnpm --filter @webstudio-is/css-data test -- parse-css-value.test.ts
parse-css.test.ts`
- `pnpm --filter @webstudio-is/builder test --
parse-intermediate-or-invalid-value.test.ts parse-style-input.test.ts`
## Description
Adds support for plain text pages. Related to
https://github.com/webstudio-is/webstudio/issues/4257
This PR introduces `text` as a supported document type, stores plain
text page content in page metadata, and generates `text/plain` route
handlers for Remix and React Router templates.
It also limits HTML-specific Builder actions on text pages, excludes
XML/text pages from the generated static sitemap, and adds SDK coverage
for text document schema and sitemap behavior.
## Steps for reproduction
1. Create or edit a page in Builder.
2. Set the document type to `TEXT`.
3. Enter plain text content in page settings.
4. Build with a Remix or React Router template.
5. Open the generated text page URL, for example `/robots.txt`.
6. Expect the response body to contain the configured text content with
`Content-Type: text/plain; charset=utf-8`.
7. In Builder, expect HTML insert/wrap/convert/tag actions to be
unavailable for text pages.
## 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
- [x] made a self-review
- [ ] added inline comments where things may be not obvious (the "why",
not "what")
## Before merging
- [x] 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
- [x] added tests
- [ ] if any new env variables are added, added them to `.env` file
---------
Co-authored-by: shreyanshkotak <sk7739@nyu.edu>
Co-authored-by: Shrek <122366903+shreyanshkotak@users.noreply.github.com>