Issue #5990Opened July 4, 2024by ihatov081 reactions

BUG: When you delete a component, duplicate classes between components will be deleted.

Question

GrapesJS version

  • I confirm to use the latest version of GrapesJS

What browser are you using?

Chrome 126.0.6478.127(Windows)

Reproducible demo link

https://jsfiddle.net/t06s4oLb/8/

Describe the bug

How to reproduce the bug?

  1. Add section1 to canvas
  2. Add section2 to canvas under section1
  3. remove section2 from canvas.
  4. The style of section1 will be broken.

https://github.com/GrapesJS/grapesjs/assets/14024165/097dbe62-d8d3-4270-930d-5668ef10c2df

What is the expected behavior?

I would like it to not be deleted even if separate components have the same class.

What is the current behavior? The reason is that both section1 and section2 have .flex classes, and if you delete section2 from canvas, the .flex css will be deleted from gjs-css-rules.

Code of Conduct

  • I agree to follow this project's Code of Conduct

Answers (3)

ihatov08July 4, 20240 reactions

As a temporary workaround, styles for each component are prefixed with id.

import { html as hero1html, css as hero1css } from './data/hero-1';
import { html as content1html, css as content1css } from './data/content-1';
const sources = [
  {
    id: 'hero-1',
    name: 'Hero 1',
    category: 'Hero',
    html: hero1html,
    css: hero1css,
    class: 'bg-gray-100 p-5',
  },
  {
    id: 'content-1',
    name: 'Content 1',
    category: 'Content',
    html: content1html,
    css: content1css,
    class: 'p-5',
  }
]

const escapeTailwindClasses = (str, id) => {
  return str.replace(/(\.[a-z0-9_-]+)(:\w+)/gi, (match, p1, p2) => {
    return `.${id}${p1.replace('.', '')}\\${p2}`;
  });
};

export const importBlocks = (editor, options = {}) => {
  const domc = editor.DomComponents;
  const blockManager = editor.BlockManager;
  sources.forEach(source => {
    const prefix = source.id + '-';
    const prefixedHtml = source.html.replace(/class="([^"]*)"/g, (match, className) => {
      return `class="${className.split(' ').map(cn => prefix + cn).join(' ')}"`;
    });

    const prefixedCss = source.css.replace(/\.([a-z0-9_-]+)(?=\s*[{,])/gi, (match, className) => {
      return '.' + prefix + className;
    });

    console.log(escapeTailwindClasses(prefixedCss, prefix))
    const prefixedClasses = source.class.split(' ').map(cn => prefix + cn).join(' ');
    domc.addType(source.id, {
      model: {
        defaults: {
          attributes: { class: prefixedClasses },
          components: prefixedHtml,
          styles: escapeTailwindClasses(prefixedCss, prefix),
        },
      },
    });
    blockManager.add(source.id, {
      category: source.category,
      id: source.id,
      label: source.name,
      content: {
        type: source.id,
      },
    });
  });
}
ihatov08July 5, 20240 reactions

@artf thank you for your reply. I would like to confirm #5968

Related Questions and Answers

Continue research with similar issue discussions.

Paid Plugins That Match This Issue

Curated by issue keywords and label relevance to help you ship faster.

View all plugins

Loading paid plugin recommendations...

Browse Plugin Categories

Jump directly to plugin category pages on the marketplace.