@mjml-agent-editor/editor 0.1.16 → 0.2.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/index.d.cts CHANGED
@@ -14,8 +14,10 @@ import { UIMessage, ChatTransport } from 'ai';
14
14
  * keep existing hosts working unchanged, and a host overrides only the keys it cares about.
15
15
  *
16
16
  * Flat and shallow-merged on purpose. A nested dictionary reads better and merges worse —
17
- * overriding one key inside a group would silently drop its siblings. `toolLabels` is the
18
- * single nested map, and it is merged key by key for exactly that reason.
17
+ * overriding one key inside a group would silently drop its siblings. The only nested maps
18
+ * are the ones keyed by an id (`toolLabels`, `blockLabels`, `elementNames`,
19
+ * `inspectorLabels`), and those are
20
+ * merged key by key for exactly that reason.
19
21
  *
20
22
  * Values that interpolate are functions rather than templates with placeholders, so the
21
23
  * translator controls word order instead of the format string.
@@ -38,10 +40,68 @@ interface EditorLabels {
38
40
  readonly exportMjml: string;
39
41
  /** `kind` is already upper-cased ("MJML", "HTML"). */
40
42
  readonly copied: (kind: string) => string;
43
+ readonly tabBlocks: string;
44
+ readonly tabSettings: string;
45
+ readonly tabLayers: string;
41
46
  readonly searchBlocks: string;
47
+ readonly noBlocksMatch: string;
48
+ readonly blockCategoryLayout: string;
49
+ readonly blockCategoryContent: string;
50
+ /** Keyed by grapesjs-mjml block id (`mj-1-column`, `mj-social-group`, …); merged key by key. */
51
+ readonly blockLabels: Readonly<Record<string, string>>;
52
+ /** Keyed by MJML tag, for the breadcrumb; merged key by key. */
53
+ readonly elementNames: Readonly<Record<string, string>>;
42
54
  readonly expandAll: string;
43
55
  readonly selectAnElement: string;
56
+ readonly settingsEmpty: string;
57
+ readonly emailSettings: string;
58
+ readonly loadingEditor: string;
59
+ readonly commentOnElement: string;
60
+ readonly groupContent: string;
61
+ readonly groupLayout: string;
62
+ readonly groupSpacing: string;
63
+ readonly groupStyle: string;
64
+ readonly groupAdvanced: string;
65
+ readonly otherAttributes: string;
66
+ readonly removeAttribute: string;
67
+ readonly resetToDefault: string;
68
+ readonly selectParent: string;
69
+ readonly duplicate: string;
70
+ readonly deleteElement: string;
71
+ readonly multipleSelected: (count: number) => string;
72
+ readonly editEachSide: string;
73
+ readonly increase: string;
74
+ readonly decrease: string;
75
+ /** The unit a length is in, on the button that changes it. */
76
+ readonly changeUnit: (unit: string) => string;
77
+ /** How a length without a unit (a line-height multiplier) shows its unit. */
78
+ readonly noUnit: string;
79
+ readonly sidesVertical: string;
80
+ readonly sidesHorizontal: string;
81
+ readonly sideTop: string;
82
+ readonly sideRight: string;
83
+ readonly sideBottom: string;
84
+ readonly sideLeft: string;
85
+ readonly linkTypeProfile: string;
86
+ readonly linkTypeShare: string;
87
+ readonly allScreenSizes: string;
88
+ readonly columnWidths: string;
89
+ /** A section's columns, by their proportions ("1:2"). */
90
+ readonly columnRatio: (ratio: string) => string;
91
+ readonly socialNetworks: string;
92
+ readonly addNetwork: string;
93
+ readonly navbarLinks: string;
94
+ readonly addLink: string;
95
+ /** The text a new navigation link starts with. */
96
+ readonly newLinkText: string;
97
+ /**
98
+ * Field names, help (`<key>.help`) and option names for the Settings tab, keyed as the
99
+ * schema in `inspector/schema.ts` names them; merged key by key.
100
+ */
101
+ readonly inspectorLabels: Readonly<Record<string, string>>;
102
+ /** @deprecated The Settings tab no longer splits attributes from style. */
44
103
  readonly attributes: string;
104
+ /** @deprecated The Settings tab no longer splits attributes from style. */
45
105
  readonly style: string;
46
106
  readonly rteFont: string;
47
107
  readonly rteSize: string;
@@ -97,8 +157,8 @@ interface EditorLabels {
97
157
  }
98
158
  declare const DEFAULT_LABELS: EditorLabels;
99
159
  /**
100
- * Overrides on top of the defaults. `toolLabels` merges rather than replaces, so a host
101
- * renaming one step does not lose the other eight.
160
+ * Overrides on top of the defaults. The maps merge rather than replace, so a host renaming
161
+ * one step does not lose the other eight.
102
162
  */
103
163
  declare function mergeLabels(overrides?: Partial<EditorLabels>): EditorLabels;
104
164
 
@@ -237,7 +297,10 @@ type Props$1 = {
237
297
  * `{"error": "..."}` body, otherwise `labels.documentSaveFailed`.
238
298
  */
239
299
  onBeforeSend: () => Promise<void>;
240
- /** After the agent's turn finishes (refresh the editor and comments). */
300
+ /**
301
+ * After the agent's turn finishes — refresh the comments. The canvas reloads itself when the
302
+ * turn ends, so calling `reloadFromDb` here only fetches the document a second time.
303
+ */
241
304
  onAgentFinish: () => void;
242
305
  /** After each single agent edit (mutating tool call) — live reload. */
243
306
  onLiveUpdate: () => void;
package/dist/index.d.ts CHANGED
@@ -14,8 +14,10 @@ import { UIMessage, ChatTransport } from 'ai';
14
14
  * keep existing hosts working unchanged, and a host overrides only the keys it cares about.
15
15
  *
16
16
  * Flat and shallow-merged on purpose. A nested dictionary reads better and merges worse —
17
- * overriding one key inside a group would silently drop its siblings. `toolLabels` is the
18
- * single nested map, and it is merged key by key for exactly that reason.
17
+ * overriding one key inside a group would silently drop its siblings. The only nested maps
18
+ * are the ones keyed by an id (`toolLabels`, `blockLabels`, `elementNames`,
19
+ * `inspectorLabels`), and those are
20
+ * merged key by key for exactly that reason.
19
21
  *
20
22
  * Values that interpolate are functions rather than templates with placeholders, so the
21
23
  * translator controls word order instead of the format string.
@@ -38,10 +40,68 @@ interface EditorLabels {
38
40
  readonly exportMjml: string;
39
41
  /** `kind` is already upper-cased ("MJML", "HTML"). */
40
42
  readonly copied: (kind: string) => string;
43
+ readonly tabBlocks: string;
44
+ readonly tabSettings: string;
45
+ readonly tabLayers: string;
41
46
  readonly searchBlocks: string;
47
+ readonly noBlocksMatch: string;
48
+ readonly blockCategoryLayout: string;
49
+ readonly blockCategoryContent: string;
50
+ /** Keyed by grapesjs-mjml block id (`mj-1-column`, `mj-social-group`, …); merged key by key. */
51
+ readonly blockLabels: Readonly<Record<string, string>>;
52
+ /** Keyed by MJML tag, for the breadcrumb; merged key by key. */
53
+ readonly elementNames: Readonly<Record<string, string>>;
42
54
  readonly expandAll: string;
43
55
  readonly selectAnElement: string;
56
+ readonly settingsEmpty: string;
57
+ readonly emailSettings: string;
58
+ readonly loadingEditor: string;
59
+ readonly commentOnElement: string;
60
+ readonly groupContent: string;
61
+ readonly groupLayout: string;
62
+ readonly groupSpacing: string;
63
+ readonly groupStyle: string;
64
+ readonly groupAdvanced: string;
65
+ readonly otherAttributes: string;
66
+ readonly removeAttribute: string;
67
+ readonly resetToDefault: string;
68
+ readonly selectParent: string;
69
+ readonly duplicate: string;
70
+ readonly deleteElement: string;
71
+ readonly multipleSelected: (count: number) => string;
72
+ readonly editEachSide: string;
73
+ readonly increase: string;
74
+ readonly decrease: string;
75
+ /** The unit a length is in, on the button that changes it. */
76
+ readonly changeUnit: (unit: string) => string;
77
+ /** How a length without a unit (a line-height multiplier) shows its unit. */
78
+ readonly noUnit: string;
79
+ readonly sidesVertical: string;
80
+ readonly sidesHorizontal: string;
81
+ readonly sideTop: string;
82
+ readonly sideRight: string;
83
+ readonly sideBottom: string;
84
+ readonly sideLeft: string;
85
+ readonly linkTypeProfile: string;
86
+ readonly linkTypeShare: string;
87
+ readonly allScreenSizes: string;
88
+ readonly columnWidths: string;
89
+ /** A section's columns, by their proportions ("1:2"). */
90
+ readonly columnRatio: (ratio: string) => string;
91
+ readonly socialNetworks: string;
92
+ readonly addNetwork: string;
93
+ readonly navbarLinks: string;
94
+ readonly addLink: string;
95
+ /** The text a new navigation link starts with. */
96
+ readonly newLinkText: string;
97
+ /**
98
+ * Field names, help (`<key>.help`) and option names for the Settings tab, keyed as the
99
+ * schema in `inspector/schema.ts` names them; merged key by key.
100
+ */
101
+ readonly inspectorLabels: Readonly<Record<string, string>>;
102
+ /** @deprecated The Settings tab no longer splits attributes from style. */
44
103
  readonly attributes: string;
104
+ /** @deprecated The Settings tab no longer splits attributes from style. */
45
105
  readonly style: string;
46
106
  readonly rteFont: string;
47
107
  readonly rteSize: string;
@@ -97,8 +157,8 @@ interface EditorLabels {
97
157
  }
98
158
  declare const DEFAULT_LABELS: EditorLabels;
99
159
  /**
100
- * Overrides on top of the defaults. `toolLabels` merges rather than replaces, so a host
101
- * renaming one step does not lose the other eight.
160
+ * Overrides on top of the defaults. The maps merge rather than replace, so a host renaming
161
+ * one step does not lose the other eight.
102
162
  */
103
163
  declare function mergeLabels(overrides?: Partial<EditorLabels>): EditorLabels;
104
164
 
@@ -237,7 +297,10 @@ type Props$1 = {
237
297
  * `{"error": "..."}` body, otherwise `labels.documentSaveFailed`.
238
298
  */
239
299
  onBeforeSend: () => Promise<void>;
240
- /** After the agent's turn finishes (refresh the editor and comments). */
300
+ /**
301
+ * After the agent's turn finishes — refresh the comments. The canvas reloads itself when the
302
+ * turn ends, so calling `reloadFromDb` here only fetches the document a second time.
303
+ */
241
304
  onAgentFinish: () => void;
242
305
  /** After each single agent edit (mutating tool call) — live reload. */
243
306
  onLiveUpdate: () => void;
package/dist/index.js CHANGED
@@ -12,7 +12,7 @@ import {
12
12
  useDocumentStore,
13
13
  useImageLibrary,
14
14
  useLabels
15
- } from "./chunk-W3HCLTFJ.js";
15
+ } from "./chunk-FTEJNUJL.js";
16
16
  import "./chunk-V6RR4VRD.js";
17
17
  export {
18
18
  CanvasComments,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mjml-agent-editor/editor",
3
- "version": "0.1.16",
3
+ "version": "0.2.0",
4
4
  "description": "React MJML editor with an agent chat panel and canvas comments.",
5
5
  "keywords": [
6
6
  "mjml",
@@ -79,15 +79,16 @@
79
79
  "react-dom": "^19"
80
80
  },
81
81
  "devDependencies": {
82
- "@types/react": "^19",
83
- "@types/react-dom": "^19",
84
- "ai": "^6.0.230",
82
+ "@types/react": "^19.2.17",
83
+ "@types/react-dom": "^19.2.3",
84
+ "ai": "^6.0.238",
85
85
  "jsdom": "^26.1.0",
86
+ "mjml": "^4.18.0",
86
87
  "react": "19.2.4",
87
88
  "react-dom": "19.2.4",
88
- "tsup": "^8.3.5",
89
- "typescript": "^5.7.2",
90
- "vitest": "^2.1.8"
89
+ "tsup": "^8.5.1",
90
+ "typescript": "^5.9.3",
91
+ "vitest": "^2.1.9"
91
92
  },
92
93
  "scripts": {
93
94
  "build": "tsup",
@@ -189,92 +189,73 @@
189
189
  display: none;
190
190
  }
191
191
 
192
- /* ── Form fields (style/traits) ──────────────────────────────────────────── */
193
- .editor-dark .gjs-field,
194
- .editor-dark .gjs-sm-field,
195
- .editor-dark .gjs-clm-field {
196
- background-color: var(--mjml-editor-panel-elevated);
197
- border: 1px solid var(--mjml-editor-border);
198
- border-radius: 6px;
199
- color: var(--mjml-editor-fg);
192
+ /* ── Layers: rows named by content, with an icon for each kind ─────────────── */
193
+ .editor-dark .gjs-layer {
194
+ font-weight: 400;
195
+ font-size: 12px;
200
196
  }
201
- .editor-dark .gjs-field input,
202
- .editor-dark .gjs-field select,
203
- .editor-dark .gjs-field textarea,
204
- .editor-dark .gjs-sm-field input,
205
- .editor-dark .gjs-clm-field input {
206
- color: var(--mjml-editor-fg);
197
+ .editor-dark .gjs-layer-item {
198
+ padding: 4px 8px;
199
+ border-bottom: none;
200
+ background-color: transparent;
201
+ }
202
+ .editor-dark .gjs-layer-title {
203
+ color: var(--mjml-editor-neutral);
207
204
  }
208
- .editor-dark .gjs-field-arrow-u,
209
- .editor-dark .gjs-field-arrow-d {
210
- border-bottom-color: var(--mjml-editor-fg-subtle);
211
- border-top-color: var(--mjml-editor-fg-subtle);
205
+ .editor-dark .gjs-layer-title-c,
206
+ .editor-dark .gjs-layer-title-inn {
207
+ min-width: 0;
212
208
  }
213
-
214
- /* Unified manager typography (traits + styles) */
215
- .editor-dark .gjs-sm-label,
216
- .editor-dark .gjs-trt-trait .gjs-label,
217
- .editor-dark .gjs-label {
218
- font-size: 11px;
219
- font-weight: 500;
220
- line-height: 1.4;
221
- letter-spacing: normal;
222
- text-transform: none;
209
+ .editor-dark .gjs-layer__icon {
210
+ flex-shrink: 0;
211
+ width: 14px;
212
+ height: 14px;
213
+ padding-left: 0;
223
214
  color: var(--mjml-editor-fg-subtle);
224
215
  }
225
- .editor-dark .gjs-sm-properties,
226
- .editor-dark .gjs-traits-c {
227
- padding: 6px 12px;
216
+ /* GrapesJS fills its icons; these are drawn with strokes. */
217
+ .editor-dark .gjs-layer__icon svg {
218
+ display: block;
219
+ width: 14px;
220
+ height: 14px;
221
+ fill: none;
222
+ stroke: currentColor;
228
223
  }
229
- .editor-dark .gjs-trt-trait {
230
- padding: 4px 0;
231
- }
232
- .editor-dark .gjs-sm-property {
233
- margin-bottom: 6px;
234
- padding: 0;
224
+ .editor-dark .gjs-layer-name {
225
+ max-width: none;
226
+ min-width: 0;
227
+ overflow: hidden;
228
+ text-overflow: ellipsis;
235
229
  }
236
- .editor-dark .gjs-field,
237
- .editor-dark .gjs-sm-field {
238
- min-height: 28px;
239
- font-size: 12px;
230
+ .editor-dark .gjs-layer-count {
231
+ font-size: 10px;
232
+ color: var(--mjml-editor-fg-faint);
240
233
  }
241
- .editor-dark .gjs-field input,
242
- .editor-dark .gjs-field select,
243
- .editor-dark .gjs-field textarea,
244
- .editor-dark .gjs-sm-field input,
245
- .editor-dark .gjs-sm-field select {
246
- font-size: 12px;
234
+ /* How many it holds matters while they are out of sight. */
235
+ .editor-dark .gjs-layer.open > .gjs-layer-item .gjs-layer-count {
236
+ visibility: hidden;
247
237
  }
248
-
249
- /* Sector headers */
250
- .editor-dark .gjs-sm-sector-title,
251
- .editor-dark .gjs-trt-header {
252
- padding: 8px 10px;
253
- background-color: var(--mjml-editor-panel-sunken);
254
- color: var(--mjml-editor-neutral);
255
- border-bottom: 1px solid var(--mjml-editor-border);
256
- font-size: 11px;
257
- font-weight: 600;
258
- text-transform: uppercase;
259
- letter-spacing: 0.04em;
238
+ .editor-dark .gjs-layer-move {
239
+ opacity: 0;
240
+ color: var(--mjml-editor-fg-subtle);
260
241
  }
261
- .editor-dark .gjs-sm-sector,
262
- .editor-dark .gjs-trt-trait {
263
- border-bottom: 1px solid var(--mjml-editor-panel-elevated);
242
+ .editor-dark .gjs-layer-item:hover .gjs-layer-move {
243
+ opacity: 1;
264
244
  }
265
-
266
- /* Layers */
267
- .editor-dark .gjs-layer-title {
268
- color: var(--mjml-editor-neutral);
245
+ .editor-dark .gjs-layer.gjs-hovered > .gjs-layer-item {
246
+ background-color: var(--mjml-editor-panel-elevated);
269
247
  }
270
248
  .editor-dark .gjs-layer.gjs-selected > .gjs-layer-item {
271
249
  background-color: color-mix(in srgb, var(--mjml-editor-accent) 22%, transparent);
272
250
  }
251
+ .editor-dark .gjs-layer.gjs-selected > .gjs-layer-item .gjs-layer__icon {
252
+ color: var(--mjml-editor-fg);
253
+ }
273
254
 
274
- /* Selector bar (component classes) */
275
- .editor-dark .gjs-clm-tags {
276
- background-color: var(--mjml-editor-panel-elevated);
277
- color: var(--mjml-editor-neutral);
255
+ /* The canvas badge's icon is one of the same stroked icons. */
256
+ :root .gjs-badge__icon svg {
257
+ fill: none;
258
+ stroke: currentColor;
278
259
  }
279
260
 
280
261
  /* ── Drop placeholder (was green) → violet ───────────────────────────────── */
@@ -428,13 +409,3 @@
428
409
  height: 12px;
429
410
  border-width: 2px;
430
411
  }
431
-
432
- /* Image properties take the full row: a thumbnail at half the sidebar is too small to judge. */
433
- .editor-dark .gjs-sm-property.gjs-sm-file {
434
- width: 100%;
435
- flex-basis: 100%;
436
- }
437
- .editor-dark .gjs-sm-property.gjs-sm-file .gjs-fields > * {
438
- flex: 1 1 auto;
439
- width: 100%;
440
- }