GrapesJS / grapesjs

Free and Open source Web Builder Framework. Next generation tool for building templates without coding
https://grapesjs.com
BSD 3-Clause "New" or "Revised" License
22.36k stars 4.05k forks source link

Changing CSS properties on a component with an existing class modifies that class instead of adding a new one #404

Closed thecodefish closed 6 years ago

thecodefish commented 7 years ago

You can see this in action on the demo (http://grapesjs.com/demo.html). Select one of the nav items ('Web' for example) - note that it has an existing class of menu-item. If you now change some of the properties, such as text alignment, it applies those changes to the menu-item class, which affects the other instances ('Template', 'Builder').

Is it possible to force GrapesJS to apply a new 'unique' class and apply the changes there - similar to how it works if you make changes to a component with no existing classes (c1234 for example)?

Ultimately I want any Style changes to only apply to the selected item - never to other instances of the same type.

Thanks

artf commented 7 years ago

I'd say you have 2 options:

  1. Just deselect the class, in this case, the style manager scope will change to the component and not the rule
  2. Add a new class to the component, instead of .menu-item rule you will get .menu-item.your-new-class
thecodefish commented 7 years ago

I would probably prefer some kind of config setting I could toggle off to change the behaviour, but I've managed to find a workaround. In my case all the content comes from our own system (no worry about external content etc), so I found all the instances where this was a problem and converted them into mini components - I then automatically add a unique class when the component is created.

I think that this would be nice to have as a config setting though, regardless. In our use case (and many others, I'm sure), the end users are unlikely to be HTML savvy and so having them deal with classes and selectors and the like is going to be confusing. We've actually hidden the css class selector panel from view, hence why I was looking for an automated solution.

artf commented 7 years ago

Exactly, how would you expect this config setting to work? I mean, just ignore classes in Style Manager and apply always the style on the component?

thecodefish commented 7 years ago

I was thinking that the behaviour could be something like this:

Default (current setup):

Toggled behaviour

artf commented 7 years ago

thanks @thecodefish I'll try to figure out the best way to do so

artf commented 6 years ago

Hi @thecodefish what do you think about this approach? https://codepen.io/artf/pen/jaaKvq

You will see there how to make selectors private (not stylable by the user) and the usage of the new avoidInlineStyle option which allows you to style components (not class selectors) without losing the responsivity and the use of states (eg. :hover)

sura2k commented 6 years ago

@artf I just started to use your IDE today. Thanks for making impossible possible.

I have the same concern that @thecodefish has and here is my suggestion. Give a simple dropdown with 2 fixed options as, Applies To : "Selected Item", "Selected Type"

By default (when select a component) it is set to "Selected Item". And when the component is initialized, create a random class and link it to "Selected Item" option and the common class is linked to "Selected Type".

Ex: menu-item

When "Selected Item" option is selected .menu-item -> unchecked .random -> checked image

When "Selected Type" option is selected .menu-item -> checked (no other classes other than user defined) image

User should not be able to check/uncheck factory made classes of "Applies To" options, but user should be able to add user's own classes by adding new classes as now. By this way, "Applies To" defines a factory setting.

I see one major concern which is now you have to have class config states for both the options "Selected Type" and "Selected Item" and that could effect to the whole IDE/system :(

This could be a very user friendly change if you can make it work. I was going to change it as I described, but since you are already up to it I though to wait for you answer. If it is not possible I will make the change an send you a pull request, but I'm not a frontend guy so code could be so ugly and hacky and will take some time and I'm going to hide the complete custom class selection area and so the concern I was thinking and mentioned above will go away - easy for me.

Thanks again!

artf commented 6 years ago

Hey @sura2k I think what you've described is basically the concept I've done here https://codepen.io/artf/pen/jaaKvq By default, all "factory classes" are not visible so when you select the component "Selected Item" is what you get. In the demo, with the last line, I've basically disabled the possibility to add new classes but if you remove it the user is able to create its own classes. By the way, I think your implementation could be made with a plugin (by making use of Selectors and CssComposer) so no need to have it inside the core

sura2k commented 6 years ago

Wow..nothing me to worry. It seems avoidInlineStylecovers all the logic I need except the UI part. @artf Is there a way to override/modify views using a plugin? (I ended up modifying ClassTagsView of core, couldn't find a way to plug a template)

artf commented 6 years ago

@sura2k unfortunately not everything is overridable (yet)

thecodefish commented 6 years ago

@artf I think your approach could work quite well (at least for my use case, where I've hidden the selector UI through CSS).

One thing I noticed with my current workaround - is the cid property persisted? I noticed some behaviour whereby if I manually created a class .c232 (for example), after saving/reloading the component list, I would end up with new cids and therefore .c232 .c137 (or the like). I worked around this as well but is this normal behaviour? Would we get the same issues with your update?

artf commented 6 years ago

not sure but I think this some related to forceClass option (which is true by default) https://github.com/artf/grapesjs/blob/dev/src/dom_components/model/Components.js#L77 try to disable it

tjb295 commented 5 years ago

Hi artf, I have a dilemma where I want the user to be able to view, add or remove the current classes on the element (since they will be bootstrap) but when they edit the styles I want them to only target the component not the classes. The solution presented above where the selectors are made private doesn't allow the user to view which classes are applied, I have been unable to figure out how to achieve this with the tools given. Is there any way I can achieve this?