vuetifyjs / nuxt-module

Zero-config Nuxt Module for Vuetify
https://nuxt.vuetifyjs.com/
MIT License
223 stars 22 forks source link

[Question || Feature request]How to override class in virtual component from layer? #281

Open lna1989 opened 1 month ago

lna1989 commented 1 month ago

The project consists of three layers. First layer VBtn defaults:

VBtn: {
      class: ['first-layer'],
    },

Second layer VBtn defaults:

VBtn: {
      class: ['second-layer'],
    },

In project layer VBtn defaults:

VBtn: {
      class: ['project-layer'],
    },

Example: https://stackblitz.com/edit/nuxt-starter-dk197v?file=layers%2Ffirst%2Fvuetify.config.ts,layers%2Fsecond%2Fvuetify.config.ts,vuetify.config.ts,pages%2Findex.vue

Actual result: image And this is normal, since there is an interlayer gluing of classes.

Question: How can I undo the gluing of styles towards rewriting at the project or second layer level?

Additional info: In nuxt.config.ts the arrow function is used to overwrite the layer values, I tried it, but it didn't work in vuetify.config.ts

userquin commented 1 month ago

There are a lot of options, the module will merge layers using defu, since the entry is an array the merge will not replace the value (we should add a custom handler to defu here: https://github.com/vuetifyjs/nuxt-module/blob/main/src/utils/layers.ts#L65).

We had similar problem with some other options like merging icon sets: you can check #214 and #217 (https://github.com/vuetifyjs/nuxt-module/blob/main/src/utils/layers.ts#L85C11-L85C21)

lna1989 commented 1 month ago

Thanks for the quick response!

Can we add a rule, if the value is an arrow function, () => ['project-layer'], then overwrite the value, and not merge with the previous ones?

Now I'm bypassing this point by writing the class value in the project with a string, but such an entry will be inconvenient, for example, when writing the value for style with a string.

userquin commented 1 month ago

Merging options is not easy, Nuxt will merge configured layers (I'll check the layer.ts module here, maybe we can simplify the logic) and the module requires merging again for custom vuetify:registerModule Nuxt hook.

We need to dedupe some options, some options should be fine others no, detecting all the options we need to dedupe would require a lot of work, we can do it progresivelly.

EDIT: your use case requires deduping, some other users may want to merge classes (with your same configuration)

userquin commented 1 month ago

Maybe we can add a new hook to dedupe options before resolving the configuration (providing merged configuration and the layers configuration, similar to https://github.com/vuetifyjs/nuxt-module/blob/main/src/utils/layers.ts#L85C11-L85C21).

For example, adding before returning here: https://github.com/vuetifyjs/nuxt-module/blob/d8a21b075fbd2e600ea53c965b71f52dd5ab79de/src/utils/layers.ts#L69

await nuxt.callHook('vuetify:dedupeOptions', {  configuration, moduleOptions })
userquin commented 1 month ago

@lna1989 looks like we can use a merger function to override the value instead merging: this will require to change a lot of types.

// In project layer VBtn defaults
VBtn: {
  class: () => ['project-layer'],
}
userquin commented 1 month ago

@lna1989 since we have this:

type DefaultsInstance = undefined | {
    [key: string]: undefined | Record<string, unknown>;
    global?: Record<string, unknown>;
};
type DefaultsOptions = Partial<DefaultsInstance>;

can you try using previous code in your app? The VBtn class should result in ['project-layer']

lna1989 commented 1 month ago

@userquin I have already been there, I have not achieved the expected result, but now I will try again.

lna1989 commented 1 month ago

@userquin When using the arrow function, no additional class appears.

defaults: {
    VBtn: {
      variant: 'outlined',
      class: () => ['project-layer'],
    },
  },

Result:

<button type="button" class="v-btn v-theme--light text-error v-btn--density-default v-btn--size-default v-btn--variant-outlined" style=""><!--[--><span class="v-btn__overlay"></span><span class="v-btn__underlay"></span><!--]--><!----><span class="v-btn__content" data-no-activator=""><!--[--><!--[--> VBtn <!--]--><!--]--></span><!----><!----></button>