thomasloven / lovelace-card-mod

🔹 Add CSS styles to (almost) any lovelace card
MIT License
1.05k stars 169 forks source link

card-mod more-info styles applied to shadow-root elements only applied on second load of more-info dialog #301

Closed u8915055 closed 9 months ago

u8915055 commented 9 months ago

My Home Assistant version: 2023.9.3

My lovelace configuration method (GUI or yaml): yaml

What I am doing: applying theme customizations to more-info through a custom theme ive created What I expected to happen: i expect that all modifications will work all the time What happened instead: I find that some modifications, specifically the ones applied to any elements in a shadow-root require a more-info dialog to be loaded twice to take effect Minimal steps to reproduce: make changes to theme as stated below, reload theme through service call, bring up more-info dialog (using button within custom:button-card call). As you can see with the 5 modifications to the more-info dialog below, the first three will take effect after reloading themes and always be displayed (basically hiding some more-info dialog elements), but the last two which i created to hide the 'attributes' box only actually works after calling it twice after a page refresh. If i refresh the page and call the more-info, it will show the attributes box, but if i close that more-info and load it again, it will be gone and will always be gone until i refresh the page again. The only difference i can see is that the two mods that require the second load were applied to a shadow-root element.

# The least amount of code possible to reproduce my error
  card-mod-theme: "tom-theme"
  # Header
  card-mod-root-yaml: |
    .: |
      app-header {
        display: none;
        height: 0px;
      }
  card-mod-more-info-yaml: |
    .: |
      ha-dialog-header {
        padding: 0px;
      }

      ha-dialog-header > ha-icon-button[slot="actionItems"]:nth-of-type(2) {
        display: none;
      }

      ha-dialog-header > ha-button-menu {
        display: none;
      }

    ha-dialog-header$: |
      section.header-title {
        display: none;
      }

    ha-more-info-info$:
      more-info-light$: |
        div:nth-of-type(2) {
          display:none;
        }
# End of code

Error messages from the browser console: None.

By putting an X in the boxes ([]) below, I indicate that I:

u8915055 commented 9 months ago

I should also add the following. I am loading the card-mod resource in my configuration.yaml

  themes: !include_dir_merge_named themes
  extra_module_url:
    - /local/custom-icons.js
    - /hacsfiles/lovelace-card-mod/card-mod.js

This is the call within the button card to bring up the 'more-info' dialog:

  half_switch_settings:
    custom_fields:
      settings_button:
        card:
          type: custom:button-card
          entity: >
            [[[ return entity === undefined || variables.entity_id; ]]]
          show_name: false
          show_icon: true
          icon: mdi:tune-vertical-variant
          size: 20px
          tap_action: 
            action: more-info.    <---- right here, is a button-card embedded in another button-card
          styles:
            card:
              - background-color: transparent
              - box-shadow: none
              - border: none
              - height: 36px
              - width: 32px
              - position: absolute
              - right: 6px
              - bottom: 16px
              - border-radius: 0px
            icon:
              - border-radius: 15px 2px 2px 15px
              - padding: 0px 4px 0px 8px
              - color: '#bbb'
              #- background-color: '#555'
              - background: transparent
u8915055 commented 9 months ago

Did a little more investigating. So it seems when i look at the DOM using google chrome 'inspect', i see that the block for any CSS changes in my theme that involve opening the shadow-root only show up in the DOM on the second time i load the more-info popup.

So of the five modfications that I added to my theme above, you'll see the bottom two involve me entering the shadow-root of the element. With those particular modifications, the two of them, they will only take effect after loading the more-info pop up element for the second time after a refresh of the page. So if i refresh the browser and load the more-info popup, those two elements will not show up. If i close the more-info and load it again, those elements will show (inside the shadow-root ofcourse) and the desired effects take place. And they will continue to take place every time i load the more-info dialog UNTIL such time that i refresh the browser page.. then i have to again load it a second time to get them to show. Hope this helps.

oh, and i hope i got all my terminology right. happy to clarify.. this is not my day job :)

u8915055 commented 9 months ago

Ok, so im going to answer my own inquiry. its a race condition. As it turns out from reading other issues, the shadow-root is not setup by the time that card-mod tries to make the style changes. That's why if you load the element the second time (in my case the more-info dialog) the style is applied.

The way ive been able to fix this is to use a separate javascript module that is loaded in through the configuration.yaml file and will make the change to the more-info elements from there. This is the javascript that im using that seems to work.

  customElements.whenDefined('ha-expansion-panel').then(() => {
    const AttributesBadge = customElements.get('ha-expansion-panel');
    const { html, css } = AttributesBadge.prototype;

    // defined added style
    const newStyle = css`
    div.top {display:none;}`;

    const newStyles = [].concat(AttributesBadge.styles, newStyle);
    Object.defineProperty(AttributesBadge, 'styles',        {value: newStyles, configurable: true, enumerable: false});
    Object.defineProperty(AttributesBadge, 'elementStyles', {value: newStyles, configurable: true, enumerable: false});
  });

Just save that as a .js file, put it into your 'www' folder and link to it under your configuration.yaml file like this:

frontend:
  themes: !include_dir_merge_named themes
  extra_module_url:
    - /local/my-resources/fix-more-info.js

Its now working every time. hope this helps... Im sure this javascript trick can help with other areas that you want to change using card-mod but the same race condition exists.