@mjml-agent-editor/editor 0.4.3 → 0.5.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/canvas.cjs +114 -59
- package/dist/canvas.cjs.map +1 -1
- package/dist/canvas.js +114 -59
- package/dist/canvas.js.map +1 -1
- package/package.json +1 -1
package/dist/canvas.cjs
CHANGED
|
@@ -2846,6 +2846,13 @@ var SCHEMA = {
|
|
|
2846
2846
|
{ attr: "direction", label: "reverseColumns", group: "advanced", control: { type: "toggle", on: "rtl" } },
|
|
2847
2847
|
{ attr: "border", label: "border", group: "advanced", control: { type: "text", placeholder: "1px solid #cccccc" } }
|
|
2848
2848
|
],
|
|
2849
|
+
// MJML allows a group these and `width` only: padding or a border fails strict. Its width is
|
|
2850
|
+
// not offered, as the canvas does not draw it: the plugin's group drops MJML's rule for it.
|
|
2851
|
+
"mj-group": [
|
|
2852
|
+
{ attr: "vertical-align", label: "verticalAlign", group: "layout", control: { type: "segmented", options: VERTICAL_ALIGN } },
|
|
2853
|
+
{ attr: "background-color", label: "backgroundColor", group: "style", control: { type: "color" } },
|
|
2854
|
+
{ attr: "direction", label: "reverseColumns", group: "advanced", control: { type: "toggle", on: "rtl" } }
|
|
2855
|
+
],
|
|
2849
2856
|
"mj-column": [
|
|
2850
2857
|
{ attr: "vertical-align", label: "verticalAlign", group: "layout", control: { type: "segmented", options: VERTICAL_ALIGN }, default: "top" },
|
|
2851
2858
|
{ attr: "padding", label: "padding", group: "spacing", control: { type: "box", units: PX_PCT } },
|
|
@@ -3204,8 +3211,12 @@ var COLUMN_RATIOS = {
|
|
|
3204
3211
|
[1, 2, 1]
|
|
3205
3212
|
]
|
|
3206
3213
|
};
|
|
3207
|
-
function columnsOf(
|
|
3208
|
-
|
|
3214
|
+
function columnsOf(container) {
|
|
3215
|
+
let children = container.components().models;
|
|
3216
|
+
const only = children.length === 1 ? children[0] : null;
|
|
3217
|
+
if (tagOf2(container) === "mj-section" && only && tagOf2(only) === "mj-group") {
|
|
3218
|
+
children = only.components().models;
|
|
3219
|
+
}
|
|
3209
3220
|
return children.length > 0 && children.every((c) => tagOf2(c) === "mj-column") ? children : null;
|
|
3210
3221
|
}
|
|
3211
3222
|
function ratioWidths(ratio) {
|
|
@@ -3268,6 +3279,7 @@ function StructureSection({
|
|
|
3268
3279
|
}) {
|
|
3269
3280
|
switch (tagOf3(component)) {
|
|
3270
3281
|
case "mj-section":
|
|
3282
|
+
case "mj-group":
|
|
3271
3283
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(ColumnWidths, { component, labels, locked });
|
|
3272
3284
|
case "mj-social":
|
|
3273
3285
|
return /* @__PURE__ */ (0, import_jsx_runtime15.jsx)(
|
|
@@ -3722,11 +3734,11 @@ function ElementSettings({
|
|
|
3722
3734
|
] }),
|
|
3723
3735
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)(StructureSection, { editor, component, labels, locked }),
|
|
3724
3736
|
GROUPS.map((group) => {
|
|
3725
|
-
const
|
|
3726
|
-
if (
|
|
3737
|
+
const inGroup2 = visible.filter((f) => f.group === group);
|
|
3738
|
+
if (inGroup2.length === 0) return null;
|
|
3727
3739
|
return /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("section", { className: "border-b border-panel-border/60 py-2", children: [
|
|
3728
3740
|
/* @__PURE__ */ (0, import_jsx_runtime16.jsx)("h3", { className: "px-3 pb-1 text-[10px] font-semibold tracking-wider text-panel-muted-fg/80 uppercase", children: groupName(group, labels) }),
|
|
3729
|
-
|
|
3741
|
+
inGroup2.map(row)
|
|
3730
3742
|
] }, group);
|
|
3731
3743
|
}),
|
|
3732
3744
|
advancedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("section", { className: "py-1", children: [
|
|
@@ -4035,7 +4047,9 @@ function registerBlocks(editor, blocks, category, media) {
|
|
|
4035
4047
|
category,
|
|
4036
4048
|
media: block.media ?? media,
|
|
4037
4049
|
content: withClosedTags(block.mjml),
|
|
4038
|
-
attributes: tileAttributes(block.id)
|
|
4050
|
+
attributes: tileAttributes(block.id),
|
|
4051
|
+
// Selected once dropped, as grapesjs-mjml's own blocks are, so its Settings open.
|
|
4052
|
+
select: true
|
|
4039
4053
|
});
|
|
4040
4054
|
}
|
|
4041
4055
|
}
|
|
@@ -4078,6 +4092,15 @@ function builtinBlock(labels) {
|
|
|
4078
4092
|
}
|
|
4079
4093
|
var CANVAS_CSS = 'img:not([src]), img[src=""] { min-height: 120px; background: #f4f4f5; outline: 1px dashed #a1a1aa; outline-offset: -1px; }';
|
|
4080
4094
|
|
|
4095
|
+
// src/components/editor/settings-follow.ts
|
|
4096
|
+
function clickShowsSettings(selected, target) {
|
|
4097
|
+
return !!selected && !!target && selected.contains(target);
|
|
4098
|
+
}
|
|
4099
|
+
function dropShowsSettings(added, selected) {
|
|
4100
|
+
const first = Array.isArray(added) ? added[0] : added;
|
|
4101
|
+
return first !== void 0 && first === selected;
|
|
4102
|
+
}
|
|
4103
|
+
|
|
4081
4104
|
// src/components/editor/table-type.ts
|
|
4082
4105
|
var import_core3 = require("@mjml-agent-editor/core");
|
|
4083
4106
|
var DROPPED = "script, style, link, iframe, frame, object, embed, applet, base, meta, animate, set, svg, math, template";
|
|
@@ -4173,12 +4196,17 @@ function fixPluginTypes(editor) {
|
|
|
4173
4196
|
for (const type of editor.Components.getTypes()) {
|
|
4174
4197
|
if (!type.id.startsWith("mj-") || type.id === "mj-table") continue;
|
|
4175
4198
|
const base = type.model.prototype.getAttrToHTML;
|
|
4199
|
+
const view = type.view.prototype;
|
|
4176
4200
|
editor.Components.addType(type.id, {
|
|
4201
|
+
...type.id === "mj-column" && { view: groupedColumnView(view) },
|
|
4202
|
+
...type.id === "mj-group" && { view: redrawnGroupView(view) },
|
|
4177
4203
|
model: {
|
|
4178
4204
|
defaults: {
|
|
4179
4205
|
"style-default": {},
|
|
4180
4206
|
...type.id === "mj-column" && {
|
|
4181
|
-
droppable: (source) => COLUMN_CHILDREN.has(String(source.get("tagName")))
|
|
4207
|
+
droppable: (source) => COLUMN_CHILDREN.has(String(source.get("tagName"))),
|
|
4208
|
+
// The plugin moves a column only within sections, so a group's could not even swap.
|
|
4209
|
+
draggable: '[data-gjs-type="mj-section"], [data-gjs-type="mj-group"]'
|
|
4182
4210
|
},
|
|
4183
4211
|
// GrapesJS's own is an SVG's markup, which the canvas wrote into `src` and saved.
|
|
4184
4212
|
...type.id === "mj-image" && { src: "" }
|
|
@@ -4195,6 +4223,41 @@ function fixPluginTypes(editor) {
|
|
|
4195
4223
|
});
|
|
4196
4224
|
}
|
|
4197
4225
|
}
|
|
4226
|
+
var inGroup = (column) => column.parent()?.get("type") === "mj-group";
|
|
4227
|
+
function groupedColumnView(base) {
|
|
4228
|
+
return {
|
|
4229
|
+
getMjmlTemplate() {
|
|
4230
|
+
if (!inGroup(this.model)) return base.getMjmlTemplate.call(this);
|
|
4231
|
+
const siblings = "<mj-column></mj-column>".repeat(
|
|
4232
|
+
Math.max((this.model.collection?.length ?? 1) - 1, 0)
|
|
4233
|
+
);
|
|
4234
|
+
const width = (c) => {
|
|
4235
|
+
const value = c?.getAttributes().width;
|
|
4236
|
+
return typeof value === "string" && value ? ` width="${value.replace(/"/g, "")}"` : "";
|
|
4237
|
+
};
|
|
4238
|
+
let body = this.model;
|
|
4239
|
+
while (body && body.get("type") !== "mj-body") body = body.parent();
|
|
4240
|
+
return {
|
|
4241
|
+
start: `<mjml><mj-body${width(body)}><mj-section><mj-group${width(this.model.parent())}>`,
|
|
4242
|
+
end: `${siblings}</mj-group></mj-section></mj-body></mjml>`
|
|
4243
|
+
};
|
|
4244
|
+
},
|
|
4245
|
+
getTemplateFromEl(container) {
|
|
4246
|
+
if (!inGroup(this.model)) return base.getTemplateFromEl.call(this, container);
|
|
4247
|
+
return container.firstChild?.querySelector(
|
|
4248
|
+
"div > table > tbody > tr > td > div > div"
|
|
4249
|
+
) ?? null;
|
|
4250
|
+
}
|
|
4251
|
+
};
|
|
4252
|
+
}
|
|
4253
|
+
function redrawnGroupView(base) {
|
|
4254
|
+
return {
|
|
4255
|
+
init() {
|
|
4256
|
+
base.init.call(this);
|
|
4257
|
+
this.listenTo(this.model.components(), "add remove", this.render);
|
|
4258
|
+
}
|
|
4259
|
+
};
|
|
4260
|
+
}
|
|
4198
4261
|
|
|
4199
4262
|
// src/components/editor/EmailEditor.tsx
|
|
4200
4263
|
var import_jsx_runtime17 = require("react/jsx-runtime");
|
|
@@ -4320,7 +4383,6 @@ function EmailEditor({
|
|
|
4320
4383
|
requestAnimationFrame(() => blockSearchRef.current?.focus());
|
|
4321
4384
|
};
|
|
4322
4385
|
const [composeTarget, setComposeTarget] = (0, import_react10.useState)(null);
|
|
4323
|
-
const selectionSource = (0, import_react10.useRef)("other");
|
|
4324
4386
|
const editorRef = (0, import_react10.useRef)(null);
|
|
4325
4387
|
const { running: turnRunning, locked: readOnly, setLocked } = useAgentTurn();
|
|
4326
4388
|
const readOnlyRef = (0, import_react10.useRef)(false);
|
|
@@ -4335,9 +4397,10 @@ function EmailEditor({
|
|
|
4335
4397
|
setLocked(false);
|
|
4336
4398
|
};
|
|
4337
4399
|
}, [turn, setLocked]);
|
|
4400
|
+
const inert = readOnly || loading;
|
|
4338
4401
|
const wasLocked = (0, import_react10.useRef)(false);
|
|
4339
4402
|
(0, import_react10.useEffect)(() => {
|
|
4340
|
-
if (
|
|
4403
|
+
if (inert) {
|
|
4341
4404
|
wasLocked.current = true;
|
|
4342
4405
|
return;
|
|
4343
4406
|
}
|
|
@@ -4352,7 +4415,7 @@ function EmailEditor({
|
|
|
4352
4415
|
cancelAnimationFrame(frame);
|
|
4353
4416
|
root.style.overflow = overflow;
|
|
4354
4417
|
};
|
|
4355
|
-
}, [
|
|
4418
|
+
}, [inert]);
|
|
4356
4419
|
const [crumbs, setCrumbs] = (0, import_react10.useState)([]);
|
|
4357
4420
|
const [picker, setPicker] = (0, import_react10.useState)(
|
|
4358
4421
|
null
|
|
@@ -4454,7 +4517,7 @@ function EmailEditor({
|
|
|
4454
4517
|
fixPluginTypes(editor);
|
|
4455
4518
|
registerBlocks(editor, blocks, labels.blockCategorySections, SECTION_SVG);
|
|
4456
4519
|
setupLayerNames(editor, labels);
|
|
4457
|
-
const STRUCTURE = /* @__PURE__ */ new Set(["mj-wrapper", "mj-section", "mj-column"]);
|
|
4520
|
+
const STRUCTURE = /* @__PURE__ */ new Set(["mj-wrapper", "mj-section", "mj-group", "mj-column"]);
|
|
4458
4521
|
const showBodyInLayers = () => {
|
|
4459
4522
|
const body = findByTag("mj-body");
|
|
4460
4523
|
if (!body) return;
|
|
@@ -4475,23 +4538,24 @@ function EmailEditor({
|
|
|
4475
4538
|
decorate(c);
|
|
4476
4539
|
});
|
|
4477
4540
|
editor.on("load", () => {
|
|
4478
|
-
|
|
4479
|
-
|
|
4480
|
-
|
|
4481
|
-
|
|
4482
|
-
|
|
4483
|
-
|
|
4484
|
-
|
|
4541
|
+
editor.Canvas.getBody()?.addEventListener(
|
|
4542
|
+
"click",
|
|
4543
|
+
(e) => setTimeout(() => {
|
|
4544
|
+
if (clickShowsSettings(editor.getSelected()?.getEl(), e.target)) {
|
|
4545
|
+
setSidebarView("settings");
|
|
4546
|
+
}
|
|
4547
|
+
})
|
|
4485
4548
|
);
|
|
4486
4549
|
editor.Canvas.getDocument()?.addEventListener("keydown", onBlockSearchKey);
|
|
4487
4550
|
showBodyInLayers();
|
|
4488
4551
|
});
|
|
4489
4552
|
editor.on("component:selected", (c) => {
|
|
4490
4553
|
keepStructureOpen();
|
|
4491
|
-
if (selectionSource.current === "canvas") setSidebarView("settings");
|
|
4492
|
-
selectionSource.current = "other";
|
|
4493
4554
|
buildCrumbs(c);
|
|
4494
4555
|
});
|
|
4556
|
+
editor.on("block:drag:stop", (added) => {
|
|
4557
|
+
if (dropShowsSettings(added, editor.getSelected())) setSidebarView("settings");
|
|
4558
|
+
});
|
|
4495
4559
|
editor.on("component:deselected", () => {
|
|
4496
4560
|
buildCrumbs(editor.getSelected());
|
|
4497
4561
|
});
|
|
@@ -4740,9 +4804,14 @@ function EmailEditor({
|
|
|
4740
4804
|
"div",
|
|
4741
4805
|
{
|
|
4742
4806
|
className: "relative flex h-full min-h-0 flex-1",
|
|
4743
|
-
inert
|
|
4807
|
+
inert,
|
|
4744
4808
|
onKeyDown: (e) => onBlockSearchKey(e.nativeEvent),
|
|
4745
4809
|
children: [
|
|
4810
|
+
loading && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "absolute inset-0 z-30 flex items-center justify-center gap-2 bg-white/70 text-sm text-zinc-500", children: [
|
|
4811
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Spinner, {}),
|
|
4812
|
+
" ",
|
|
4813
|
+
labels.loadingEditor
|
|
4814
|
+
] }),
|
|
4746
4815
|
readOnly && /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("div", { className: "absolute inset-0 z-30 flex cursor-not-allowed items-start justify-center bg-white/20 pt-3", children: /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("span", { className: "flex items-center gap-2 rounded-full bg-panel px-3 py-1 text-xs text-panel-fg shadow", children: [
|
|
4747
4816
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Spinner, {}),
|
|
4748
4817
|
" ",
|
|
@@ -4753,7 +4822,6 @@ function EmailEditor({
|
|
|
4753
4822
|
{
|
|
4754
4823
|
view: sidebarView,
|
|
4755
4824
|
onViewChange: setSidebarView,
|
|
4756
|
-
markLayersSource: () => selectionSource.current = "layers",
|
|
4757
4825
|
blockSearchRef
|
|
4758
4826
|
}
|
|
4759
4827
|
),
|
|
@@ -4784,12 +4852,7 @@ function EmailEditor({
|
|
|
4784
4852
|
editorRef.current?.AssetManager.close();
|
|
4785
4853
|
}
|
|
4786
4854
|
}
|
|
4787
|
-
)
|
|
4788
|
-
loading && /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: "absolute inset-0 z-10 flex items-center justify-center gap-2 bg-white/70 text-sm text-zinc-500", children: [
|
|
4789
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Spinner, {}),
|
|
4790
|
-
" ",
|
|
4791
|
-
labels.loadingEditor
|
|
4792
|
-
] })
|
|
4855
|
+
)
|
|
4793
4856
|
] }),
|
|
4794
4857
|
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Breadcrumb, { crumbs, onSelect: (c) => editorRef.current?.select(c) })
|
|
4795
4858
|
] })
|
|
@@ -4802,7 +4865,6 @@ function EmailEditor({
|
|
|
4802
4865
|
function LeftSidebar({
|
|
4803
4866
|
view,
|
|
4804
4867
|
onViewChange,
|
|
4805
|
-
markLayersSource,
|
|
4806
4868
|
blockSearchRef
|
|
4807
4869
|
}) {
|
|
4808
4870
|
const editor = (0, import_react9.useEditorMaybe)();
|
|
@@ -4910,36 +4972,29 @@ function LeftSidebar({
|
|
|
4910
4972
|
] })
|
|
4911
4973
|
}
|
|
4912
4974
|
) }),
|
|
4913
|
-
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
|
|
4914
|
-
"
|
|
4915
|
-
|
|
4916
|
-
|
|
4917
|
-
|
|
4918
|
-
|
|
4919
|
-
|
|
4920
|
-
|
|
4921
|
-
|
|
4922
|
-
|
|
4923
|
-
|
|
4924
|
-
|
|
4925
|
-
|
|
4926
|
-
|
|
4927
|
-
|
|
4928
|
-
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
"
|
|
4932
|
-
|
|
4933
|
-
|
|
4934
|
-
|
|
4935
|
-
|
|
4936
|
-
if (e.target.closest("[data-name]")) e.stopPropagation();
|
|
4937
|
-
}
|
|
4938
|
-
}
|
|
4939
|
-
)
|
|
4940
|
-
]
|
|
4941
|
-
}
|
|
4942
|
-
)
|
|
4975
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: cn("flex min-h-0 flex-1 flex-col", view !== "layers" && "hidden"), children: [
|
|
4976
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("label", { className: "flex items-center justify-between gap-2 border-b border-panel-border px-3 py-2 text-xs text-panel-muted-fg", children: [
|
|
4977
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: labels.expandAll }),
|
|
4978
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
4979
|
+
Switch,
|
|
4980
|
+
{
|
|
4981
|
+
checked: layersExpanded,
|
|
4982
|
+
onCheckedChange: toggleLayers,
|
|
4983
|
+
className: "data-[state=checked]:bg-brand data-[state=unchecked]:bg-panel-border"
|
|
4984
|
+
}
|
|
4985
|
+
)
|
|
4986
|
+
] }),
|
|
4987
|
+
/* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
|
|
4988
|
+
"div",
|
|
4989
|
+
{
|
|
4990
|
+
id: "gjs-layers",
|
|
4991
|
+
className: "min-h-0 flex-1 overflow-y-auto",
|
|
4992
|
+
onDoubleClickCapture: (e) => {
|
|
4993
|
+
if (e.target.closest("[data-name]")) e.stopPropagation();
|
|
4994
|
+
}
|
|
4995
|
+
}
|
|
4996
|
+
)
|
|
4997
|
+
] })
|
|
4943
4998
|
] });
|
|
4944
4999
|
}
|
|
4945
5000
|
function Breadcrumb({
|