From 0a02332df8b7056738fc7add9c715242cf049cf4 Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Thu, 22 Aug 2024 18:15:15 +0400 Subject: [PATCH 1/6] Allow to pass custom mjml to `mjml-code-to-html` command --- src/commands/index.ts | 18 ++--- src/index.ts | 159 ++++++------------------------------------ src/types.ts | 133 +++++++++++++++++++++++++++++++++++ 3 files changed, 164 insertions(+), 146 deletions(-) create mode 100644 src/types.ts diff --git a/src/commands/index.ts b/src/commands/index.ts index 0b4dca0..1590a73 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -1,5 +1,5 @@ import type { Editor } from 'grapesjs'; -import { RequiredPluginOptions } from '..'; +import { CommandOptionsMjmlToHtml, RequiredPluginOptions } from '..'; import { mjmlConvert } from '../components/utils'; import openExportMjml from './openExportMjml'; import openImportMjml from './openImportMjml'; @@ -17,12 +17,13 @@ export default (editor: Editor, opts: RequiredPluginOptions) => { const cmdOpenExport = opts.overwriteExport ? 'export-template' : cmdExportMjml; Commands.add(cmdGetMjml, () => { - return `${opts.preMjml}${editor.getHtml().trim()}${opts.postMjml}`; + return `${opts.preMjml}${editor.getHtml().trim()}${opts.postMjml}`; }); - Commands.add(cmdGetMjmlToHtml, (ed, _, opt) => { - const mjml = Commands.run(cmdGetMjml); - return mjmlConvert(opts.mjmlParser, mjml, opts.fonts, opt); + Commands.add(cmdGetMjmlToHtml, (ed: any, _: any, opt: CommandOptionsMjmlToHtml = {}) => { + const { mjml, ...rest } = opt; + const mjmlToParse = mjml || Commands.run(cmdGetMjml); + return mjmlConvert(opts.mjmlParser, mjmlToParse, opts.fonts, rest); }); openExportMjml(editor, opts, cmdOpenExport); @@ -30,16 +31,15 @@ export default (editor: Editor, opts: RequiredPluginOptions) => { // Device commands Commands.add(cmdDeviceDesktop, { - run: ed => ed.setDevice('Desktop'), + run: (ed) => ed.setDevice('Desktop'), stop: () => {}, }); Commands.add(cmdDeviceTablet, { - run: ed => ed.setDevice('Tablet'), + run: (ed) => ed.setDevice('Tablet'), stop: () => {}, }); Commands.add(cmdDeviceMobile, { - run: ed => ed.setDevice('Mobile portrait'), + run: (ed) => ed.setDevice('Mobile portrait'), stop: () => {}, }); - }; diff --git a/src/index.ts b/src/index.ts index 8c17574..4667b95 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,144 +1,35 @@ -import type { Editor, Plugin } from 'grapesjs'; +import type { Plugin } from 'grapesjs'; import loadBlocks from './blocks'; -import loadComponents, { ComponentPluginOptions } from './components'; -import mjml2html, { MjmlParser } from './components/parser'; import loadCommands from './commands'; +import loadComponents from './components'; +import mjml2html from './components/parser'; +import en from './locale/en'; import loadPanels from './panels'; import loadStyle from './style'; -import en from './locale/en'; - -export type PluginOptions = { - /** - * Which blocks to add. - * @default (all) - */ - blocks?: string[]; - - /** - * Add custom block options, based on block id. - * @default (blockId) => ({}) - * @example (blockId) => (blockId === 'mj-hero' ? { attributes: {...} } : {}) - */ - block?: (blockId: string) => ({}); - - /** - * Code viewer theme. - * @default 'hopscotch' - */ - codeViewerTheme?: string; - - /** - * Add custom MJML components - * - * @default [] - */ - customComponents?: ((editor: Editor, componentOptions: ComponentPluginOptions) => void)[], - - /** - * Placeholder MJML template for the import modal - * @default '' - */ - importPlaceholder?: string; - - /** - * Image placeholder source for mj-image block - * @default '' - */ - imagePlaceholderSrc?: string; - - /** - * Custom MJML parser. - * @default mjml-browser instance - */ - mjmlParser?: MjmlParser; - - /** - * Overwrite default export command - * @default true - */ - overwriteExport?: boolean; - - /** - * String before the MJML in export code - * @default '' - */ - preMjml?: string; +import { PluginOptions } from './types'; - /** - * String after the MJML in export code - * @default '' - */ - postMjml?: string; - - /** - * Clean all previous blocks if true - * @default true - */ - resetBlocks?: boolean; - - /** - * Reset the Style Manager and add new properties for MJML - * @default true - */ - resetStyleManager?: boolean; - - /** - * Clean all previous devices and set a new one for mobile - * @default true - */ - resetDevices?: boolean; - - /** - * Hide the default selector manager - * @default true - */ - hideSelector?: boolean; - - /** - * Experimental: use XML parser instead of HTML. - * This should allow importing void MJML elements (without closing tags) like . - * @default false - * @experimental - */ - useXmlParser?: boolean; - - /** - * Column padding (this way it's easier to select columns) - * @default '10px 0' - */ - columnsPadding?: string; - - /** - * I18n object containing languages, [more info](https://grapesjs.com/docs/modules/I18n.html#configuration). - * @default {} - */ - i18n?: Record; - - /** - * Custom fonts on exported HTML header, [more info](https://github.com/mjmlio/mjml#inside-nodejs). - * @default {} - * @example - * { - * Montserrat: 'https://fonts.googleapis.com/css?family=Montserrat', - * 'Open Sans': 'https://fonts.googleapis.com/css?family=Open+Sans' - * } - */ - fonts?: Record; - - /** - * Load custom preset theme. - * @default true - */ - useCustomTheme?: boolean; -}; +export * from './types'; export type RequiredPluginOptions = Required; const plugin: Plugin = (editor, opt = {}) => { const opts: RequiredPluginOptions = { blocks: [ - 'mj-1-column', 'mj-2-columns', 'mj-3-columns', 'mj-text', 'mj-button', 'mj-image', 'mj-divider', 'mj-social-group', - 'mj-social-element', 'mj-spacer', 'mj-navbar', 'mj-navbar-link', 'mj-hero', 'mj-wrapper', 'mj-raw' + 'mj-1-column', + 'mj-2-columns', + 'mj-3-columns', + 'mj-text', + 'mj-button', + 'mj-image', + 'mj-divider', + 'mj-social-group', + 'mj-social-element', + 'mj-spacer', + 'mj-navbar', + 'mj-navbar-link', + 'mj-hero', + 'mj-wrapper', + 'mj-raw', ], block: () => ({}), codeViewerTheme: 'hopscotch', @@ -226,13 +117,7 @@ const plugin: Plugin = (editor, opt = {}) => { ...opts.i18n, }); - [ - loadBlocks, - loadComponents, - loadCommands, - loadPanels, - loadStyle, - ].forEach(module => module(editor, opts)); + [loadBlocks, loadComponents, loadCommands, loadPanels, loadStyle].forEach((module) => module(editor, opts)); }; export default plugin; diff --git a/src/types.ts b/src/types.ts new file mode 100644 index 0000000..599637b --- /dev/null +++ b/src/types.ts @@ -0,0 +1,133 @@ +import type { Editor } from 'grapesjs'; +import type { MJMLParsingOptions } from 'mjml-core'; +import { ComponentPluginOptions } from './components'; +import { MjmlParser } from './components/parser'; + +export interface CommandOptionsMjmlToHtml extends MJMLParsingOptions { + mjml?: string; +} + +export type PluginOptions = { + /** + * Which blocks to add. + * @default (all) + */ + blocks?: string[]; + + /** + * Add custom block options, based on block id. + * @default (blockId) => ({}) + * @example (blockId) => (blockId === 'mj-hero' ? { attributes: {...} } : {}) + */ + block?: (blockId: string) => {}; + + /** + * Code viewer theme. + * @default 'hopscotch' + */ + codeViewerTheme?: string; + + /** + * Add custom MJML components + * + * @default [] + */ + customComponents?: ((editor: Editor, componentOptions: ComponentPluginOptions) => void)[]; + + /** + * Placeholder MJML template for the import modal + * @default '' + */ + importPlaceholder?: string; + + /** + * Image placeholder source for mj-image block + * @default '' + */ + imagePlaceholderSrc?: string; + + /** + * Custom MJML parser. + * @default mjml-browser instance + */ + mjmlParser?: MjmlParser; + + /** + * Overwrite default export command + * @default true + */ + overwriteExport?: boolean; + + /** + * String before the MJML in export code + * @default '' + */ + preMjml?: string; + + /** + * String after the MJML in export code + * @default '' + */ + postMjml?: string; + + /** + * Clean all previous blocks if true + * @default true + */ + resetBlocks?: boolean; + + /** + * Reset the Style Manager and add new properties for MJML + * @default true + */ + resetStyleManager?: boolean; + + /** + * Clean all previous devices and set a new one for mobile + * @default true + */ + resetDevices?: boolean; + + /** + * Hide the default selector manager + * @default true + */ + hideSelector?: boolean; + + /** + * Experimental: use XML parser instead of HTML. + * This should allow importing void MJML elements (without closing tags) like . + * @default false + * @experimental + */ + useXmlParser?: boolean; + + /** + * Column padding (this way it's easier to select columns) + * @default '10px 0' + */ + columnsPadding?: string; + + /** + * I18n object containing languages, [more info](https://grapesjs.com/docs/modules/I18n.html#configuration). + * @default {} + */ + i18n?: Record; + + /** + * Custom fonts on exported HTML header, [more info](https://github.com/mjmlio/mjml#inside-nodejs). + * @default {} + * @example + * { + * Montserrat: 'https://fonts.googleapis.com/css?family=Montserrat', + * 'Open Sans': 'https://fonts.googleapis.com/css?family=Open+Sans' + * } + */ + fonts?: Record; + + /** + * Load custom preset theme. + * @default true + */ + useCustomTheme?: boolean; +}; From e180965c9065fc727f9d220baf990cc180647003 Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Thu, 22 Aug 2024 18:37:52 +0400 Subject: [PATCH 2/6] Up TS --- src/commands/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/commands/index.ts b/src/commands/index.ts index 1590a73..6638e3c 100644 --- a/src/commands/index.ts +++ b/src/commands/index.ts @@ -20,8 +20,8 @@ export default (editor: Editor, opts: RequiredPluginOptions) => { return `${opts.preMjml}${editor.getHtml().trim()}${opts.postMjml}`; }); - Commands.add(cmdGetMjmlToHtml, (ed: any, _: any, opt: CommandOptionsMjmlToHtml = {}) => { - const { mjml, ...rest } = opt; + Commands.add(cmdGetMjmlToHtml, (ed, _, opt) => { + const { mjml, ...rest } = (opt || {}) as CommandOptionsMjmlToHtml; const mjmlToParse = mjml || Commands.run(cmdGetMjml); return mjmlConvert(opts.mjmlParser, mjmlToParse, opts.fonts, rest); }); From 0b896a9c1fba9d656bdf9a36ff46b41912a1d8a1 Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Fri, 23 Aug 2024 13:41:33 +0400 Subject: [PATCH 3/6] Provide postRender to render functions. Closes #273 --- src/components/Column.ts | 42 +++++++++++++++++++++++++------------ src/components/NavBar.ts | 17 +++++++++------ src/components/index.ts | 45 +++++++++++++++++----------------------- 3 files changed, 59 insertions(+), 45 deletions(-) diff --git a/src/components/Column.ts b/src/components/Column.ts index c0ff086..607d54d 100644 --- a/src/components/Column.ts +++ b/src/components/Column.ts @@ -4,7 +4,6 @@ import { ComponentPluginOptions } from '.'; import { componentsToQuery, getName, isComponentType, mjmlConvert } from './utils'; import { type as typeSection } from './Section'; - export const type = 'mj-column'; export default (editor: Editor, { opt, coreMjmlModel, coreMjmlView, sandboxEl }: ComponentPluginOptions) => { @@ -18,14 +17,27 @@ export default (editor: Editor, { opt, coreMjmlModel, coreMjmlView, sandboxEl }: name: getName(editor, 'column'), draggable: componentsToQuery(typeSection), stylable: [ - 'background-color', 'vertical-align', 'width', - 'border-radius', 'border-top-left-radius', 'border-top-right-radius', 'border-bottom-left-radius', 'border-bottom-right-radius', - 'border', 'border-width', 'border-style', 'border-color', - 'padding', 'padding-top', 'padding-left', 'padding-right', 'padding-bottom', + 'background-color', + 'vertical-align', + 'width', + 'border-radius', + 'border-top-left-radius', + 'border-top-right-radius', + 'border-bottom-left-radius', + 'border-bottom-right-radius', + 'border', + 'border-width', + 'border-style', + 'border-color', + 'padding', + 'padding-top', + 'padding-left', + 'padding-right', + 'padding-bottom', ], 'style-default': { - 'vertical-align': 'top' - } + 'vertical-align': 'top', + }, }, }, @@ -39,8 +51,12 @@ export default (editor: Editor, { opt, coreMjmlModel, coreMjmlView, sandboxEl }: getTemplateFromMjml() { const mjmlTmpl = this.getMjmlTemplate(); const innerMjml = this.getInnerMjmlTemplate(); - const htmlOutput = mjmlConvert(opt.mjmlParser, `${mjmlTmpl.start} - ${innerMjml.start}${innerMjml.end}${mjmlTmpl.end}`, opt.fonts); + const htmlOutput = mjmlConvert( + opt.mjmlParser, + `${mjmlTmpl.start} + ${innerMjml.start}${innerMjml.end}${mjmlTmpl.end}`, + opt.fonts, + ); const html = htmlOutput.html; // I need styles for responsive columns @@ -51,7 +67,6 @@ export default (editor: Editor, { opt, coreMjmlModel, coreMjmlView, sandboxEl }: styles.push(item.innerHTML); }); - const content = html.replace(//, ''); const start = content.indexOf('') + 6; const end = content.indexOf(''); @@ -70,7 +85,7 @@ export default (editor: Editor, { opt, coreMjmlModel, coreMjmlView, sandboxEl }: return { attributes, content: componentEl.innerHTML, - style: styles.join(' ') + style: styles.join(' '), }; }, @@ -86,6 +101,7 @@ export default (editor: Editor, { opt, coreMjmlModel, coreMjmlView, sandboxEl }: // In case mjmlResult.attributes removes necessary stuff this.updateStatus(); + this.postRender(); return this; }, @@ -95,8 +111,8 @@ export default (editor: Editor, { opt, coreMjmlModel, coreMjmlView, sandboxEl }: const modelStyle = model.get('style') || {}; const stylable = model.get('stylable') as string[]; const styles = Object.keys(modelStyle) - .filter(prop => stylable.indexOf(prop) > -1) - .map(prop => `${prop}:${modelStyle[prop]};`); + .filter((prop) => stylable.indexOf(prop) > -1) + .map((prop) => `${prop}:${modelStyle[prop]};`); const styleResult = `${attributes.style} ${styles.join(' ')} ${el.getAttribute('style')}`; el.setAttribute('style', styleResult); // #290 Fix double borders diff --git a/src/components/NavBar.ts b/src/components/NavBar.ts index c559901..b473ffa 100644 --- a/src/components/NavBar.ts +++ b/src/components/NavBar.ts @@ -31,8 +31,8 @@ export default (editor: Editor, { opt, coreMjmlModel, coreMjmlView, sandboxEl }: options: [ { value: 'hamburger', name: 'ON' }, { value: '', name: 'OFF' }, - ] - } + ], + }, ], }, }, @@ -52,8 +52,12 @@ export default (editor: Editor, { opt, coreMjmlModel, coreMjmlView, sandboxEl }: getTemplateFromMjml() { const mjmlTmpl = this.getMjmlTemplate(); const innerMjml = this.getInnerMjmlTemplate(); - const htmlOutput = mjmlConvert(opt.mjmlParser, `${mjmlTmpl.start} - ${innerMjml.start}${innerMjml.end}${mjmlTmpl.end}`, opt.fonts); + const htmlOutput = mjmlConvert( + opt.mjmlParser, + `${mjmlTmpl.start} + ${innerMjml.start}${innerMjml.end}${mjmlTmpl.end}`, + opt.fonts, + ); const html = htmlOutput.html; // I need styles for hamburger @@ -64,7 +68,6 @@ export default (editor: Editor, { opt, coreMjmlModel, coreMjmlView, sandboxEl }: styles.push(item.innerHTML); }); - const content = html.replace(//, ''); const start = content.indexOf('') + 6; const end = content.indexOf(''); @@ -83,7 +86,7 @@ export default (editor: Editor, { opt, coreMjmlModel, coreMjmlView, sandboxEl }: return { attributes, content: componentEl.innerHTML, - style: styles.join(' ') + style: styles.join(' '), }; }, @@ -96,6 +99,8 @@ export default (editor: Editor, { opt, coreMjmlModel, coreMjmlView, sandboxEl }: this.getChildrenContainer().innerHTML = this.model.get('content')!; this.renderChildren(); this.renderStyle(); + this.postRender(); + return this; }, diff --git a/src/components/index.ts b/src/components/index.ts index 74c1102..4b92d64 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -33,16 +33,15 @@ export type ComponentPluginOptions = { coreMjmlView: any; opt: Required; sandboxEl: HTMLDivElement; - componentsToQuery: typeof componentsToQuery, -} + componentsToQuery: typeof componentsToQuery; +}; export default (editor: Editor, opt: RequiredPluginOptions) => { - const { Components } = editor; + const { Components } = editor; // @ts-ignore const ComponentsView = Components.ComponentsView; const sandboxEl = document.createElement('div'); - // MJML Core model let coreMjmlModel = { init() { @@ -71,7 +70,6 @@ export default (editor: Editor, opt: RequiredPluginOptions) => { this.set('attributes', style, opts); }, - getMjmlAttributes() { const attr = this.get('attributes') || {}; delete attr.style; @@ -80,7 +78,6 @@ export default (editor: Editor, opt: RequiredPluginOptions) => { return attr; }, - /** * This will avoid rendering default attributes * @return {Object} @@ -102,7 +99,6 @@ export default (editor: Editor, opt: RequiredPluginOptions) => { return attr; }, - /** * Have to change a few things for the MJML's xml (no id, style, class) */ @@ -135,10 +131,9 @@ export default (editor: Editor, opt: RequiredPluginOptions) => { isHidden() { return this.getStyle().display === 'none'; - } + }, } as any; - /** * MJML Core View. * MJML is designed to compile from a valid MJML document therefore any time we update some component @@ -168,7 +163,6 @@ export default (editor: Editor, opt: RequiredPluginOptions) => { this.debouncedRender = debounce(this.render.bind(this), 0); }, - rerender() { this.render(null, null, {}, 1); }, @@ -194,8 +188,7 @@ export default (editor: Editor, opt: RequiredPluginOptions) => { for (let prop in attr) { const val = attr[prop]; - strAttr += typeof val !== 'undefined' && val !== '' ? - ' ' + prop + '="' + val + '"' : ''; + strAttr += typeof val !== 'undefined' && val !== '' ? ' ' + prop + '="' + val + '"' : ''; } return { @@ -228,7 +221,6 @@ export default (editor: Editor, opt: RequiredPluginOptions) => { return this.getTemplateFromEl(sandboxEl); }, - /** * Render children components * @private @@ -239,12 +231,14 @@ export default (editor: Editor, opt: RequiredPluginOptions) => { // This trick will help perfs by caching children if (!appendChildren) { - this.childrenView = this.childrenView || new ComponentsView({ - collection: this.model.get('components'), - // @ts-ignore - config: this.config, - componentTypes: this.opts.componentTypes, - }); + this.childrenView = + this.childrenView || + new ComponentsView({ + collection: this.model.get('components'), + // @ts-ignore + config: this.config, + componentTypes: this.opts.componentTypes, + }); this.childNodes = this.childrenView.render(container).el.childNodes; } else { this.childrenView.parentEl = container; @@ -268,20 +262,20 @@ export default (editor: Editor, opt: RequiredPluginOptions) => { this.checkVisibility(); }, - render(p: any, c: any, opts: any, appendChildren: boolean) { this.renderAttributes(); this.el.innerHTML = this.getTemplateFromMjml(); this.renderChildren(appendChildren); this.childNodes = this.getChildrenContainer().childNodes; this.renderStyle(); + this.postRender(); return this; - } + }, } as any; // MJML Internal view (for elements inside mj-columns) - const compOpts = { coreMjmlModel, coreMjmlView, opt, sandboxEl, componentsToQuery}; + const compOpts = { coreMjmlModel, coreMjmlView, opt, sandboxEl, componentsToQuery }; // Avoid the tag from the default wrapper editor.Components.addType('wrapper', { @@ -291,8 +285,8 @@ export default (editor: Editor, opt: RequiredPluginOptions) => { }, toHTML(opts: any) { return this.getInnerHTML(opts)!; - } - } + }, + }, }); [ @@ -317,6 +311,5 @@ export default (editor: Editor, opt: RequiredPluginOptions) => { loadHero, loadRaw, ...opt.customComponents, - ] - .forEach(module => module(editor, compOpts)); + ].forEach((module) => module(editor, compOpts)); }; From bc640a1395f45bfa3697b71b265853ee33fd5ba5 Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Fri, 23 Aug 2024 14:14:15 +0400 Subject: [PATCH 4/6] Skip `fonts` usage from README as it's not complete. Ref #284 --- README.md | 41 ----------------------------------------- 1 file changed, 41 deletions(-) diff --git a/README.md b/README.md index 5cee922..2f3a8a5 100644 --- a/README.md +++ b/README.md @@ -40,7 +40,6 @@ Supported MJML components (using default mjml-browser parser): |`block`|Add custom block options, based on block id.|`(blockId) => ({})`| |`codeViewerTheme`|Code viewer theme.|`hopscotch`| |`customComponents`|List of components which will be added to default one |`[]` | -|`fonts`|Custom fonts on exported HTML header [more info](https://github.com/mjmlio/mjml#inside-nodejs)|`{}`| |`importPlaceholder`|Placeholder MJML template for the import modal|`''`| |`imagePlaceholderSrc`|Image placeholder source|`'https://via.placeholder.com/350x250/78c5d6/fff'`| |`i18n`|I18n object containing language [more info](https://grapesjs.com/docs/modules/I18n.html#configuration)|`{}`| @@ -141,46 +140,6 @@ grapesJS.init({ }); ``` -#### fonts usage: - -```js -import 'grapesjs/dist/css/grapes.min.css' -import grapesJS from 'grapesjs' -import grapesJSMJML from 'grapesjs-mjml' - -const editor = grapesJS.init({ - fromElement: true, - container: '#gjs', - plugins: [grapesJSMJML], - pluginsOpts: { - [grapesJSMJML]: { - // The font imports are included on HTML when fonts are used on the template - fonts: { - Montserrat: 'https://fonts.googleapis.com/css?family=Montserrat', - 'Open Sans': 'https://fonts.googleapis.com/css?family=Open+Sans' - } - } - }, -}); - -// add custom fonts options on editor's font list -editor.on('load', () => { - const styleManager = editor.StyleManager; - const fontProperty = styleManager.getProperty('typography', 'font-family'); - - const list = []; - // empty list - fontProperty.set('list', list); - - // custom list - list.push(fontProperty.addOption({value: 'Montserrat, sans-serif', name: 'Montserrat'})); - list.push(fontProperty.addOption({value: 'Open Sans, sans-serif', name: 'Open Sans'})); - fontProperty.set('list', list); - - styleManager.render(); -}); -``` - ### Using Independent mjml-browser Build In case, you have your own version of MJML with custom or extended components, it is possible From 459c059bb73a20dc7792c2cdfa020eea05c1cb21 Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Fri, 23 Aug 2024 19:41:03 +0400 Subject: [PATCH 5/6] Prevent auto value for the image width. Closes #339 #344 --- src/components/Image.ts | 36 ++++++++++++++++++++++++++++++------ src/components/index.ts | 10 +++++++--- 2 files changed, 37 insertions(+), 9 deletions(-) diff --git a/src/components/Image.ts b/src/components/Image.ts index 57ee274..5c89ffa 100644 --- a/src/components/Image.ts +++ b/src/components/Image.ts @@ -20,22 +20,46 @@ export default (editor: Editor, { coreMjmlModel, coreMjmlView }: ComponentPlugin name: getName(editor, 'image'), draggable: componentsToQuery([typeSection, typeColumn, typeHero]), stylable: [ - 'width', 'height', - 'padding', 'padding-top', 'padding-left', 'padding-right', 'padding-bottom', - 'border-radius', 'border-top-left-radius', 'border-top-right-radius', 'border-bottom-left-radius', 'border-bottom-right-radius', - 'border', 'border-width', 'border-style', 'border-color', - 'container-background-color', 'align', + 'width', + 'height', + 'padding', + 'padding-top', + 'padding-left', + 'padding-right', + 'padding-bottom', + 'border-radius', + 'border-top-left-radius', + 'border-top-right-radius', + 'border-bottom-left-radius', + 'border-bottom-right-radius', + 'border', + 'border-width', + 'border-style', + 'border-color', + 'container-background-color', + 'align', ], 'style-default': { 'padding-top': '10px', 'padding-bottom': '10px', 'padding-right': '25px', 'padding-left': '25px', - 'align': 'center', + align: 'center', }, traits: ['href', 'rel', 'alt', 'title'], void: false, }, + + getStylesToAttributes() { + const style = coreMjmlModel.getStylesToAttributes.call(this); + + // Fix #339 + if (style.width === 'auto') { + delete style.width; + } + + return style; + }, }, view: { diff --git a/src/components/index.ts b/src/components/index.ts index 4b92d64..5cd9a33 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -64,10 +64,14 @@ export default (editor: Editor, opt: RequiredPluginOptions) => { this.setStyle(this.get('attributes'), opts); }, - handleStyleChange(m: any, v: any, opts: any) { - const style = this.getStyle(); + getStylesToAttributes() { + const style = this.getStyle() || {}; delete style.__p; - this.set('attributes', style, opts); + return style; + }, + + handleStyleChange(m: any, v: any, opts: any) { + this.set('attributes', this.getStylesToAttributes(), opts); }, getMjmlAttributes() { From 2034e3d56fab75d07149800a23ea8225f55dd935 Mon Sep 17 00:00:00 2001 From: Artur Arseniev Date: Fri, 23 Aug 2024 20:01:47 +0400 Subject: [PATCH 6/6] Up TS PluginOptions --- src/components/index.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/components/index.ts b/src/components/index.ts index 5cd9a33..8362a62 100644 --- a/src/components/index.ts +++ b/src/components/index.ts @@ -1,4 +1,4 @@ -import type { Editor, PluginOptions } from 'grapesjs'; +import type { Editor } from 'grapesjs'; import { mjmlConvert, debounce, componentsToQuery } from './utils'; import loadMjml from './mjml'; import loadHead from './Head'; @@ -20,7 +20,7 @@ import loadNavBar from './NavBar'; import loadNavBarLink from './NavBarLink'; import loadHero from './Hero'; import loadRaw from './Raw'; -import { RequiredPluginOptions } from '..'; +import { RequiredPluginOptions, PluginOptions } from '..'; export type ComponentPluginOptions = { /**