experimental: Paste from Webflow 3 (#3466)

## Description

More components: Richt Text, Supescript, Subscript, Emphasized, Strong,
Section, Container, Quick Stack, VStack, HStack

## 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:
5de6)
- [ ] 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.example`
and the `builder/env-check.js` if mandatory
This commit is contained in:
Oleg Isonen authored and GitHub committed 2024-06-01 02:17:39 +02:00
1 parent 5df7b1aa68
commit 028cd799db
2 files changed
+430 -11

No files matched your search

@@ -57,7 +57,7 @@ test("Heading", () => {
]);
});
test("Link", () => {
test("Link Block, Button, Text Link", () => {
const fragment = toWebstudioFragment({
type: "@webflow/XscpData",
payload: {
@@ -341,6 +341,360 @@ test("Blockquote", () => {
]);
});
test("Strong", () => {
const fragment = toWebstudioFragment({
type: "@webflow/XscpData",
payload: {
nodes: [
{
_id: "25ffefdf-c015-5edd-7673-933b41a25328",
type: "Strong",
tag: "strong",
classes: [],
children: ["25ffefdf-c015-5edd-7673-933b41a25329"],
},
{
_id: "25ffefdf-c015-5edd-7673-933b41a25329",
text: true,
v: "Bold Text",
},
],
styles: [],
},
});
expect(fragment.instances).toEqual([
{
id: expect.not.stringMatching("instanceId"),
type: "instance",
component: "Bold",
children: [
{
type: "text",
value: "Bold Text",
},
],
},
]);
});
test("Emphasized", () => {
const fragment = toWebstudioFragment({
type: "@webflow/XscpData",
payload: {
nodes: [
{
_id: "25ffefdf-c015-5edd-7673-933b41a25328",
type: "Emphasized",
tag: "em",
classes: [],
children: ["25ffefdf-c015-5edd-7673-933b41a25329"],
},
{
_id: "25ffefdf-c015-5edd-7673-933b41a25329",
text: true,
v: "Emphasis",
},
],
styles: [],
},
});
expect(fragment.instances).toEqual([
{
id: expect.not.stringMatching("instanceId"),
type: "instance",
component: "Italic",
children: [
{
type: "text",
value: "Emphasis",
},
],
},
]);
});
test("Superscript", () => {
const fragment = toWebstudioFragment({
type: "@webflow/XscpData",
payload: {
nodes: [
{
_id: "25ffefdf-c015-5edd-7673-933b41a25328",
type: "Superscript",
tag: "sup",
classes: [],
children: ["25ffefdf-c015-5edd-7673-933b41a25329"],
},
{
_id: "25ffefdf-c015-5edd-7673-933b41a25329",
text: true,
v: "Superscript",
},
],
styles: [],
},
});
expect(fragment.instances).toEqual([
{
id: expect.not.stringMatching("instanceId"),
type: "instance",
component: "Superscript",
children: [
{
type: "text",
value: "Superscript",
},
],
},
]);
});
test("Subscript", () => {
const fragment = toWebstudioFragment({
type: "@webflow/XscpData",
payload: {
nodes: [
{
_id: "25ffefdf-c015-5edd-7673-933b41a25328",
type: "Subscript",
tag: "sub",
classes: [],
children: ["25ffefdf-c015-5edd-7673-933b41a25329"],
},
{
_id: "25ffefdf-c015-5edd-7673-933b41a25329",
text: true,
v: "Subscript",
},
],
styles: [],
},
});
expect(fragment.instances).toEqual([
{
id: expect.not.stringMatching("instanceId"),
type: "instance",
component: "Subscript",
children: [
{
type: "text",
value: "Subscript",
},
],
},
]);
});
test("Section", () => {
const fragment = toWebstudioFragment({
type: "@webflow/XscpData",
payload: {
nodes: [
{
_id: "25ffefdf-c015-5edd-7673-933b41a25328",
type: "Section",
tag: "section",
classes: [],
children: ["25ffefdf-c015-5edd-7673-933b41a25329"],
},
],
styles: [],
},
});
expect(fragment.instances).toEqual([
{
id: expect.not.stringMatching("instanceId"),
type: "instance",
component: "Box",
children: [],
},
]);
});
test("BlockContainer", () => {
const fragment = toWebstudioFragment({
type: "@webflow/XscpData",
payload: {
nodes: [
{
_id: "25ffefdf-c015-5edd-7673-933b41a25328",
type: "BlockContainer",
tag: "div",
classes: [],
children: [],
},
],
styles: [],
},
});
expect(fragment.instances).toEqual([
{
id: expect.not.stringMatching("instanceId"),
type: "instance",
component: "Box",
children: [],
},
]);
});
test("Block", () => {
const fragment = toWebstudioFragment({
type: "@webflow/XscpData",
payload: {
nodes: [
{
_id: "25ffefdf-c015-5edd-7673-933b41a25328",
type: "Block",
tag: "div",
classes: [],
children: [],
},
],
styles: [],
},
});
expect(fragment.instances).toEqual([
{
id: expect.not.stringMatching("instanceId"),
type: "instance",
component: "Box",
children: [],
},
]);
});
test("V Flex", () => {
const fragment = toWebstudioFragment({
type: "@webflow/XscpData",
payload: {
nodes: [
{
_id: "25ffefdf-c015-5edd-7673-933b41a25328",
type: "VFlex",
tag: "div",
classes: [],
children: [],
},
],
styles: [],
},
});
expect(fragment.instances).toEqual([
{
id: expect.not.stringMatching("instanceId"),
type: "instance",
component: "Box",
children: [],
},
]);
});
test("H Flex", () => {
const fragment = toWebstudioFragment({
type: "@webflow/XscpData",
payload: {
nodes: [
{
_id: "25ffefdf-c015-5edd-7673-933b41a25328",
type: "HFlex",
tag: "div",
classes: [],
children: [],
},
],
styles: [],
},
});
expect(fragment.instances).toEqual([
{
id: expect.not.stringMatching("instanceId"),
type: "instance",
component: "Box",
children: [],
},
]);
});
test("Quick Stack", () => {
const fragment = toWebstudioFragment({
type: "@webflow/XscpData",
payload: {
nodes: [
{
_id: "91782272-bf55-194d-ce85-9ddc69c51dee",
type: "Layout",
tag: "div",
classes: [],
children: [
"91782272-bf55-194d-ce85-9ddc69c51def",
"91782272-bf55-194d-ce85-9ddc69c51df0",
],
data: {
style: {
base: {
main: {
noPseudo: {
gridTemplateColumns: "1fr 1fr",
gridTemplateRows: "auto",
},
},
},
},
},
},
{
_id: "91782272-bf55-194d-ce85-9ddc69c51def",
type: "Cell",
tag: "div",
classes: [],
children: [],
},
{
_id: "91782272-bf55-194d-ce85-9ddc69c51df0",
type: "Cell",
tag: "div",
classes: [],
children: [],
},
],
styles: [],
},
});
expect(fragment.instances).toEqual([
{
id: expect.not.stringMatching("instanceId"),
type: "instance",
component: "Box",
children: [],
},
{
id: expect.not.stringMatching("instanceId"),
type: "instance",
component: "Box",
children: [],
},
{
id: expect.not.stringMatching("instanceId"),
type: "instance",
component: "Box",
children: [
{ type: "id", value: expect.not.stringMatching("instanceId") },
{ type: "id", value: expect.not.stringMatching("instanceId") },
],
},
]);
});
test("Basic styles with a class", () => {
const fragment = toWebstudioFragment({
type: "@webflow/XscpData",
@@ -21,11 +21,65 @@ export const mimeType = "application/json";
// A list of Webflow component names that need to be mapped.
const componentMappers = {
Block(wfNode: WfNode) {
if ("type" in wfNode === false || wfNode.type !== "Block") {
return;
Block(wfNode: WfElementNode) {
if (wfNode.type === "Block") {
return wfNode.data?.text ? "Text" : "Box";
}
return wfNode.data.text ? "Text" : "Box";
return wfNode.type;
},
Section(wfNode: WfElementNode) {
if (wfNode.type === "Section") {
return "Box";
}
return wfNode.type;
},
RichText(wfNode: WfElementNode) {
if (wfNode.type === "RichText") {
return "Box";
}
return wfNode.type;
},
Strong(wfNode: WfElementNode) {
if (wfNode.type === "Strong") {
return "Bold";
}
return wfNode.type;
},
Emphasized(wfNode: WfElementNode) {
if (wfNode.type === "Emphasized") {
return "Italic";
}
return wfNode.type;
},
BlockContainer(wfNode: WfElementNode) {
if (wfNode.type === "BlockContainer") {
return "Box";
}
return wfNode.type;
},
Layout(wfNode: WfElementNode) {
if (wfNode.type === "Layout") {
return "Box";
}
return wfNode.type;
},
Cell(wfNode: WfElementNode) {
if (wfNode.type === "Cell") {
return "Box";
}
return wfNode.type;
},
VFlex(wfNode: WfElementNode) {
if (wfNode.type === "VFlex") {
return "Box";
}
return wfNode.type;
},
HFlex(wfNode: WfElementNode) {
if (wfNode.type === "HFlex") {
return "Box";
}
return wfNode.type;
},
};
@@ -43,11 +97,11 @@ const WfTextNode = z.object({
text: z.boolean(),
});
const WfNode = z.union([
const WfElementNode = z.union([
WfBaseNode.extend({ type: z.enum(["Heading"]) }),
WfBaseNode.extend({
type: z.enum(["Block"]),
data: z.object({ text: z.boolean().optional() }),
data: z.object({ text: z.boolean().optional() }).optional(),
}),
WfBaseNode.extend({ type: z.enum(["List"]) }),
WfBaseNode.extend({ type: z.enum(["ListItem"]) }),
@@ -62,8 +116,21 @@ const WfNode = z.union([
}),
WfBaseNode.extend({ type: z.enum(["Paragraph"]) }),
WfBaseNode.extend({ type: z.enum(["Blockquote"]) }),
WfTextNode,
WfBaseNode.extend({ type: z.enum(["RichText"]) }),
WfBaseNode.extend({ type: z.enum(["Strong"]) }),
WfBaseNode.extend({ type: z.enum(["Emphasized"]) }),
WfBaseNode.extend({ type: z.enum(["Superscript"]) }),
WfBaseNode.extend({ type: z.enum(["Subscript"]) }),
WfBaseNode.extend({ type: z.enum(["Section"]) }),
WfBaseNode.extend({ type: z.enum(["BlockContainer"]) }),
WfBaseNode.extend({ type: z.enum(["Layout"]) }),
WfBaseNode.extend({ type: z.enum(["Cell"]) }),
WfBaseNode.extend({ type: z.enum(["VFlex"]) }),
WfBaseNode.extend({ type: z.enum(["HFlex"]) }),
]);
type WfElementNode = z.infer<typeof WfElementNode>;
const WfNode = z.union([WfElementNode, WfTextNode]);
type WfNode = z.infer<typeof WfNode>;
const WfStyle = z.object({
@@ -181,9 +248,7 @@ const addInstance = (
const component =
wfNode.type in componentMappers
? componentMappers[wfNode.type as keyof typeof componentMappers](
wfNode
) ?? wfNode.type
? componentMappers[wfNode.type as keyof typeof componentMappers](wfNode)
: wfNode.type;
fragment.instances.push({