@mjml-agent-editor/editor 0.4.2 → 0.5.0

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 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(section) {
3208
- const children = section.components().models;
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 inGroup = visible.filter((f) => f.group === group);
3726
- if (inGroup.length === 0) return null;
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
- inGroup.map(row)
3741
+ inGroup2.map(row)
3730
3742
  ] }, group);
3731
3743
  }),
3732
3744
  advancedCount > 0 && /* @__PURE__ */ (0, import_jsx_runtime16.jsxs)("section", { className: "py-1", children: [
@@ -4173,12 +4185,17 @@ function fixPluginTypes(editor) {
4173
4185
  for (const type of editor.Components.getTypes()) {
4174
4186
  if (!type.id.startsWith("mj-") || type.id === "mj-table") continue;
4175
4187
  const base = type.model.prototype.getAttrToHTML;
4188
+ const view = type.view.prototype;
4176
4189
  editor.Components.addType(type.id, {
4190
+ ...type.id === "mj-column" && { view: groupedColumnView(view) },
4191
+ ...type.id === "mj-group" && { view: redrawnGroupView(view) },
4177
4192
  model: {
4178
4193
  defaults: {
4179
4194
  "style-default": {},
4180
4195
  ...type.id === "mj-column" && {
4181
- droppable: (source) => COLUMN_CHILDREN.has(String(source.get("tagName")))
4196
+ droppable: (source) => COLUMN_CHILDREN.has(String(source.get("tagName"))),
4197
+ // The plugin moves a column only within sections, so a group's could not even swap.
4198
+ draggable: '[data-gjs-type="mj-section"], [data-gjs-type="mj-group"]'
4182
4199
  },
4183
4200
  // GrapesJS's own is an SVG's markup, which the canvas wrote into `src` and saved.
4184
4201
  ...type.id === "mj-image" && { src: "" }
@@ -4195,6 +4212,41 @@ function fixPluginTypes(editor) {
4195
4212
  });
4196
4213
  }
4197
4214
  }
4215
+ var inGroup = (column) => column.parent()?.get("type") === "mj-group";
4216
+ function groupedColumnView(base) {
4217
+ return {
4218
+ getMjmlTemplate() {
4219
+ if (!inGroup(this.model)) return base.getMjmlTemplate.call(this);
4220
+ const siblings = "<mj-column></mj-column>".repeat(
4221
+ Math.max((this.model.collection?.length ?? 1) - 1, 0)
4222
+ );
4223
+ const width = (c) => {
4224
+ const value = c?.getAttributes().width;
4225
+ return typeof value === "string" && value ? ` width="${value.replace(/"/g, "")}"` : "";
4226
+ };
4227
+ let body = this.model;
4228
+ while (body && body.get("type") !== "mj-body") body = body.parent();
4229
+ return {
4230
+ start: `<mjml><mj-body${width(body)}><mj-section><mj-group${width(this.model.parent())}>`,
4231
+ end: `${siblings}</mj-group></mj-section></mj-body></mjml>`
4232
+ };
4233
+ },
4234
+ getTemplateFromEl(container) {
4235
+ if (!inGroup(this.model)) return base.getTemplateFromEl.call(this, container);
4236
+ return container.firstChild?.querySelector(
4237
+ "div > table > tbody > tr > td > div > div"
4238
+ ) ?? null;
4239
+ }
4240
+ };
4241
+ }
4242
+ function redrawnGroupView(base) {
4243
+ return {
4244
+ init() {
4245
+ base.init.call(this);
4246
+ this.listenTo(this.model.components(), "add remove", this.render);
4247
+ }
4248
+ };
4249
+ }
4198
4250
 
4199
4251
  // src/components/editor/EmailEditor.tsx
4200
4252
  var import_jsx_runtime17 = require("react/jsx-runtime");
@@ -4335,6 +4387,25 @@ function EmailEditor({
4335
4387
  setLocked(false);
4336
4388
  };
4337
4389
  }, [turn, setLocked]);
4390
+ const inert = readOnly || loading;
4391
+ const wasLocked = (0, import_react10.useRef)(false);
4392
+ (0, import_react10.useEffect)(() => {
4393
+ if (inert) {
4394
+ wasLocked.current = true;
4395
+ return;
4396
+ }
4397
+ const root = wasLocked.current && editorRef.current?.Canvas.getDocument()?.documentElement;
4398
+ wasLocked.current = false;
4399
+ if (!root) return;
4400
+ const overflow = root.style.overflow;
4401
+ root.style.overflow = "hidden";
4402
+ void root.offsetHeight;
4403
+ const frame = requestAnimationFrame(() => root.style.overflow = overflow);
4404
+ return () => {
4405
+ cancelAnimationFrame(frame);
4406
+ root.style.overflow = overflow;
4407
+ };
4408
+ }, [inert]);
4338
4409
  const [crumbs, setCrumbs] = (0, import_react10.useState)([]);
4339
4410
  const [picker, setPicker] = (0, import_react10.useState)(
4340
4411
  null
@@ -4436,7 +4507,7 @@ function EmailEditor({
4436
4507
  fixPluginTypes(editor);
4437
4508
  registerBlocks(editor, blocks, labels.blockCategorySections, SECTION_SVG);
4438
4509
  setupLayerNames(editor, labels);
4439
- const STRUCTURE = /* @__PURE__ */ new Set(["mj-wrapper", "mj-section", "mj-column"]);
4510
+ const STRUCTURE = /* @__PURE__ */ new Set(["mj-wrapper", "mj-section", "mj-group", "mj-column"]);
4440
4511
  const showBodyInLayers = () => {
4441
4512
  const body = findByTag("mj-body");
4442
4513
  if (!body) return;
@@ -4722,9 +4793,14 @@ function EmailEditor({
4722
4793
  "div",
4723
4794
  {
4724
4795
  className: "relative flex h-full min-h-0 flex-1",
4725
- inert: readOnly,
4796
+ inert,
4726
4797
  onKeyDown: (e) => onBlockSearchKey(e.nativeEvent),
4727
4798
  children: [
4799
+ 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: [
4800
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Spinner, {}),
4801
+ " ",
4802
+ labels.loadingEditor
4803
+ ] }),
4728
4804
  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: [
4729
4805
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Spinner, {}),
4730
4806
  " ",
@@ -4766,12 +4842,7 @@ function EmailEditor({
4766
4842
  editorRef.current?.AssetManager.close();
4767
4843
  }
4768
4844
  }
4769
- ),
4770
- 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: [
4771
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Spinner, {}),
4772
- " ",
4773
- labels.loadingEditor
4774
- ] })
4845
+ )
4775
4846
  ] }),
4776
4847
  /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(Breadcrumb, { crumbs, onSelect: (c) => editorRef.current?.select(c) })
4777
4848
  ] })