@mjml-agent-editor/editor 0.5.0 → 0.5.2

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
@@ -4047,7 +4047,9 @@ function registerBlocks(editor, blocks, category, media) {
4047
4047
  category,
4048
4048
  media: block.media ?? media,
4049
4049
  content: withClosedTags(block.mjml),
4050
- 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
4051
4053
  });
4052
4054
  }
4053
4055
  }
@@ -4090,6 +4092,15 @@ function builtinBlock(labels) {
4090
4092
  }
4091
4093
  var CANVAS_CSS = 'img:not([src]), img[src=""] { min-height: 120px; background: #f4f4f5; outline: 1px dashed #a1a1aa; outline-offset: -1px; }';
4092
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
+
4093
4104
  // src/components/editor/table-type.ts
4094
4105
  var import_core3 = require("@mjml-agent-editor/core");
4095
4106
  var DROPPED = "script, style, link, iframe, frame, object, embed, applet, base, meta, animate, set, svg, math, template";
@@ -4189,6 +4200,8 @@ function fixPluginTypes(editor) {
4189
4200
  editor.Components.addType(type.id, {
4190
4201
  ...type.id === "mj-column" && { view: groupedColumnView(view) },
4191
4202
  ...type.id === "mj-group" && { view: redrawnGroupView(view) },
4203
+ ...type.id === "mj-social" && { view: stackedSocialGroupView(view) },
4204
+ ...type.id === "mj-social-element" && { view: socialIconView(view) },
4192
4205
  model: {
4193
4206
  defaults: {
4194
4207
  "style-default": {},
@@ -4247,6 +4260,75 @@ function redrawnGroupView(base) {
4247
4260
  }
4248
4261
  };
4249
4262
  }
4263
+ function socialLayout(mode, align) {
4264
+ if (mode !== "vertical") {
4265
+ return {
4266
+ icon: { display: "inline-table", gridColumn: "", gridTemplateColumns: "", alignItems: "" },
4267
+ column: { display: "", gridTemplateColumns: "", justifyContent: "" }
4268
+ };
4269
+ }
4270
+ const side = align === "left" ? "start" : align === "right" ? "end" : "center";
4271
+ return {
4272
+ icon: {
4273
+ display: "grid",
4274
+ gridColumn: "1 / -1",
4275
+ gridTemplateColumns: "subgrid",
4276
+ alignItems: "center"
4277
+ },
4278
+ column: { display: "grid", gridTemplateColumns: "auto auto", justifyContent: side }
4279
+ };
4280
+ }
4281
+ var groupLayout = (group) => {
4282
+ const attributes = group?.getAttributes() ?? {};
4283
+ return socialLayout(attributes.mode, attributes.align);
4284
+ };
4285
+ function stackedSocialGroupView(base) {
4286
+ return {
4287
+ render() {
4288
+ const drawn = base.render.call(this);
4289
+ Object.assign(this.getChildrenContainer().style, groupLayout(this.model).column);
4290
+ return drawn;
4291
+ }
4292
+ };
4293
+ }
4294
+ function socialLabel(icon) {
4295
+ const row = icon.querySelector("tr");
4296
+ const cell = Array.from(row?.cells ?? []).find((td) => !td.querySelector("table"));
4297
+ return cell?.firstElementChild ?? null;
4298
+ }
4299
+ function socialIconView(base) {
4300
+ return {
4301
+ // The label decides whether MJML draws a label cell, so a change to it redraws the icon.
4302
+ init() {
4303
+ base.init.call(this);
4304
+ this.listenTo(this.model.components(), "add remove", this.render);
4305
+ },
4306
+ // A change to the group's attributes redraws its icons, so each lays out the cell as well.
4307
+ render() {
4308
+ const drawn = base.render.call(this);
4309
+ const { icon, column } = groupLayout(this.model.parent());
4310
+ Object.assign(this.el.style, icon);
4311
+ if (icon.display === "grid") {
4312
+ for (const part of this.el.querySelectorAll(
4313
+ ":scope > tbody, :scope > tbody > tr"
4314
+ )) {
4315
+ part.style.display = "contents";
4316
+ }
4317
+ }
4318
+ if (this.el.parentElement) Object.assign(this.el.parentElement.style, column);
4319
+ return drawn;
4320
+ },
4321
+ // With its label, so MJML draws the label's cell, and on the side `icon-position` says.
4322
+ getInnerMjmlTemplate() {
4323
+ const { start, end } = base.getInnerMjmlTemplate.call(this);
4324
+ return { start: `${start}${this.model.getInnerHTML()}`, end };
4325
+ },
4326
+ // The label's components are drawn in that cell; the plugin's container is the `<img>`.
4327
+ getChildrenContainer() {
4328
+ return socialLabel(this.el) ?? base.getChildrenContainer.call(this);
4329
+ }
4330
+ };
4331
+ }
4250
4332
 
4251
4333
  // src/components/editor/EmailEditor.tsx
4252
4334
  var import_jsx_runtime17 = require("react/jsx-runtime");
@@ -4372,7 +4454,6 @@ function EmailEditor({
4372
4454
  requestAnimationFrame(() => blockSearchRef.current?.focus());
4373
4455
  };
4374
4456
  const [composeTarget, setComposeTarget] = (0, import_react10.useState)(null);
4375
- const selectionSource = (0, import_react10.useRef)("other");
4376
4457
  const editorRef = (0, import_react10.useRef)(null);
4377
4458
  const { running: turnRunning, locked: readOnly, setLocked } = useAgentTurn();
4378
4459
  const readOnlyRef = (0, import_react10.useRef)(false);
@@ -4528,23 +4609,24 @@ function EmailEditor({
4528
4609
  decorate(c);
4529
4610
  });
4530
4611
  editor.on("load", () => {
4531
- const body = editor.Canvas.getBody();
4532
- body?.addEventListener(
4533
- "mousedown",
4534
- () => {
4535
- selectionSource.current = "canvas";
4536
- },
4537
- true
4612
+ editor.Canvas.getBody()?.addEventListener(
4613
+ "click",
4614
+ (e) => setTimeout(() => {
4615
+ if (clickShowsSettings(editor.getSelected()?.getEl(), e.target)) {
4616
+ setSidebarView("settings");
4617
+ }
4618
+ })
4538
4619
  );
4539
4620
  editor.Canvas.getDocument()?.addEventListener("keydown", onBlockSearchKey);
4540
4621
  showBodyInLayers();
4541
4622
  });
4542
4623
  editor.on("component:selected", (c) => {
4543
4624
  keepStructureOpen();
4544
- if (selectionSource.current === "canvas") setSidebarView("settings");
4545
- selectionSource.current = "other";
4546
4625
  buildCrumbs(c);
4547
4626
  });
4627
+ editor.on("block:drag:stop", (added) => {
4628
+ if (dropShowsSettings(added, editor.getSelected())) setSidebarView("settings");
4629
+ });
4548
4630
  editor.on("component:deselected", () => {
4549
4631
  buildCrumbs(editor.getSelected());
4550
4632
  });
@@ -4811,7 +4893,6 @@ function EmailEditor({
4811
4893
  {
4812
4894
  view: sidebarView,
4813
4895
  onViewChange: setSidebarView,
4814
- markLayersSource: () => selectionSource.current = "layers",
4815
4896
  blockSearchRef
4816
4897
  }
4817
4898
  ),
@@ -4855,7 +4936,6 @@ function EmailEditor({
4855
4936
  function LeftSidebar({
4856
4937
  view,
4857
4938
  onViewChange,
4858
- markLayersSource,
4859
4939
  blockSearchRef
4860
4940
  }) {
4861
4941
  const editor = (0, import_react9.useEditorMaybe)();
@@ -4963,36 +5043,29 @@ function LeftSidebar({
4963
5043
  ] })
4964
5044
  }
4965
5045
  ) }),
4966
- /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)(
4967
- "div",
4968
- {
4969
- className: cn("flex min-h-0 flex-1 flex-col", view !== "layers" && "hidden"),
4970
- onMouseDownCapture: markLayersSource,
4971
- children: [
4972
- /* @__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: [
4973
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: labels.expandAll }),
4974
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4975
- Switch,
4976
- {
4977
- checked: layersExpanded,
4978
- onCheckedChange: toggleLayers,
4979
- className: "data-[state=checked]:bg-brand data-[state=unchecked]:bg-panel-border"
4980
- }
4981
- )
4982
- ] }),
4983
- /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
4984
- "div",
4985
- {
4986
- id: "gjs-layers",
4987
- className: "min-h-0 flex-1 overflow-y-auto",
4988
- onDoubleClickCapture: (e) => {
4989
- if (e.target.closest("[data-name]")) e.stopPropagation();
4990
- }
4991
- }
4992
- )
4993
- ]
4994
- }
4995
- )
5046
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsxs)("div", { className: cn("flex min-h-0 flex-1 flex-col", view !== "layers" && "hidden"), children: [
5047
+ /* @__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: [
5048
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)("span", { children: labels.expandAll }),
5049
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5050
+ Switch,
5051
+ {
5052
+ checked: layersExpanded,
5053
+ onCheckedChange: toggleLayers,
5054
+ className: "data-[state=checked]:bg-brand data-[state=unchecked]:bg-panel-border"
5055
+ }
5056
+ )
5057
+ ] }),
5058
+ /* @__PURE__ */ (0, import_jsx_runtime17.jsx)(
5059
+ "div",
5060
+ {
5061
+ id: "gjs-layers",
5062
+ className: "min-h-0 flex-1 overflow-y-auto",
5063
+ onDoubleClickCapture: (e) => {
5064
+ if (e.target.closest("[data-name]")) e.stopPropagation();
5065
+ }
5066
+ }
5067
+ )
5068
+ ] })
4996
5069
  ] });
4997
5070
  }
4998
5071
  function Breadcrumb({