Problem/Motivation

Inside "EXTENDING.md", "1. Adding a style from a plugin YAML definition":
- The heading is quite misleading. The example doesn't show how to add "a style from a plugin YAML defintion", but it shows how to use the module's alter hook to provide a style group.
- Furthermore Step 2 is not possible. Providing the same config_object "canvas_builder.settings" is not possible and won't magically merge the old schema object with the new provided one. It will simply throw an error instead.

Fixing this isn't easy. Third party modules would need to manually inject their settings inside canvas_builder through install or alter hooks and even then schema errors will appear, as the newly added configs don't have a schema defined in canvas_builder.

I'd generally recommend to rework the current approach. The module already provides a "canvas_builder.plugins.yml", which defines the group.
So why not allow other modules to provide their own "*.plugin.ymls", to provide their own custom groups? (I would rename them to "*.canvas_builder_styles.yml" though). This would need a PluginManager using YamlDiscovery.
And instead of only providing the static children "wrapper" in the group definitions we could add the actual possible values there as well! This way we wouldn't need to fight with the drupal schema / config.

Other modules like UI Styles do this quite similiar.

Another approach would could be that third party modules could provide two seperate ymls "*.canvas_builder_style_defintions.yml" and "*.canvas_builder_style_options.yml" (or values). One would provide the group definitions and one would provide the possible values.

We should still keep / add the existing hooks and alter hooks to optionally provide / alter existing defintions / options.

Let's discuss this, so we can have a great extension DX! 😊

Steps to reproduce

Proposed resolution

Remaining tasks

User interface changes

API changes

Data model changes

Comments

grevil created an issue. See original summary.

aaronchristian’s picture

I like this approach, okay let me take this one away and see what we can come up with!

aaronchristian’s picture

Assigned: Unassigned » aaronchristian

  • aaronchristian committed 58ab5cac on 1.0.x
    docs: correct EXTENDING.md style-extension guidance (#3615431)
    
    Section...
aaronchristian’s picture

I added gitlab pages, the EXTENDING doc can be found here; https://canvas-builder-87eae9.pages.drupalcode.org/EXTENDING/

aaronchristian’s picture

Status: Active » Needs review
anybody’s picture

Issue summary: View changes

@aaronchristian thank you very much!

One main point I very much like about @grevils suggestion is using the yml plugin discovery and using .yml's by default for extension. The hook is helpful, but very technical and complicated for themes. The way UI Styles does it is great!

Did you already look into that? Or should Grevil explain the idea more in detail?

Maybe you have even better ideas, but the *.canvas_builder_?.yml approach is very appealing in my eyes!

anybody’s picture

Status: Needs review » Needs work

Setting this to NW for further discussion as of #7

anybody’s picture

Title: Providing your own custom group defintions is not correctly documented and could need a rework » Improve custom style definition DX using YamlDiscovery
aaronchristian’s picture

Thanks for pushing on this. You're right that the docs fix wasn't the real fix, just a nice way to access them.... that said, I've had a proper look and agree that YamlDiscovery is the better approach.

I'll use *.canvas_builder_styles.yml as you suggested, and include themes too. That gives themes a simple way to add their own colour and spacing options without needing PHP. The existing hooks can stay and still run last, so nothing that's already working should change. You're also right about the settings_key issue. The approach I originally suggested won't work since Drupal replaces the existing definition instead of combining them. I'm thinking we keep the simple case inline in the YAML, with settings_key available when those options need to be editable through config.

The other thing I found is that FrameworkProfileManager will need to know about these new definitions too. Otherwise profile switching could remove them, and Tailwind could miss the classes. I'd rather handle that as part of this instead of leaving a gotcha behind. I'd also keep this as one YAML file for now. Splitting the definitions and options feels like extra bloat IMO, but let me know your thoughts!

anybody’s picture

Great, thank you so much for your positive feedback @aaronchristian. I think it's super important to provide the best UX we can. I've asked @thomas.frobieter to review this, thinking he's super experienced in this.

thomas.frobieter’s picture

Assigned: aaronchristian » thomas.frobieter
Status: Needs work » Needs review

I also think that a single YML file should be enough. Let's test it and refine if necessary. I'm going to try it out today!

BTW, the best implementation I've seen so far in this regard is the UI Suite Layout Options module: https://www.drupal.org/docs/contributed-modules/layout-options/how-to-use-it#s-option-definitions-section Maybe we can pick up a few ideas from there.

thomas.frobieter’s picture

Assigned: thomas.frobieter » Unassigned
Status: Needs review » Needs work

Oh, sorry, that was a misunderstanding—I thought it was already implemented in DEV.

aaronchristian’s picture

I think i have something working @thomas.frobieter, should have it on dev shortly!

Will update the ticket here, thanks for the example too, very helpful.

aaronchristian’s picture

Hey @grevil, @anybody, @thomas.frobieter, this is now implemented and shipped on 1.0.x.

The main change is a new StyleDefinitionDiscovery service using core's YamlDiscovery to find {provider}.canvas_builder_styles.yml files in enabled modules and themes. Definitions are deep-merged in order: canvas_builder.plugins.yml -> modules -> themes.

There are also two simple ways to override an existing definition when needed:

some_key:
  remove: true

some_other_key:
  replace: [...]

The existing hook_canvas_builder_styles() / _alter() hooks still run afterwards, so the dynamic/computed use case is still covered.

For example, a theme can now add a custom CTA style without any PHP:

# mytheme.canvas_builder_styles.yml
cta_callout_plugin:
  enabled: true
  type: group
  label: CTA Callout
  form_group: style
  children:
    cta_callout:
      label: CTA Callout style
      style: select
      settings_key: cta_callout_classes
      viewport_scoped: true

With values like:

cta_callout_classes:
  - label: Info
    classes:
      mobile: cta-callout--info
  - label: Warning
    classes:
      mobile: cta-callout--warning
  - label: Danger
    classes:
      mobile: cta-callout--danger

The viewport_scoped bit came out of testing this example. It’s useful for variants where you only want one class active at each breakpoint, rather than combining the values.

The profile-switching concern from #10 is covered too. Custom settings_key values aren't affected by framework/profile changes.

I've added the examples and details to docs/EXTENDING.md as well.

https://canvas-builder-87eae9.pages.drupalcode.org/EXTENDING/#1a-style-definitions-via-providercanvas_builder_stylesyml

aaronchristian’s picture

You could use drush to seed the values in as well if you had a script, or just add them to the backend settings form, then export your config after.

\Drupal::configFactory()
  ->getEditable('canvas_builder.settings')
  ->set('cta_callout_classes', [
    ['label' => 'Info', 'classes' => ['mobile' => 'cta-callout--info']],
    ['label' => 'Warning', 'classes' => ['mobile' => 'cta-callout--warning']],
    ['label' => 'Danger', 'classes' => ['mobile' => 'cta-callout--danger']],
  ])
  ->save();

Canvas Plugin

Canvas BE Form

aaronchristian’s picture

Status: Needs work » Needs review
thomas.frobieter’s picture

Status: Needs review » Reviewed & tested by the community

I did some basic testing with x.canvas_builder_styles.yml and everything worked as expected.

I was able to add a custom plugin, merge further options into existing plugins, remove existing Canvas Builder plugins, and replace individual values.

Replace is also great for altering the order/weight of the default plugins.

In my opinion, that's more than enough. Great work again!