siemens / ix

Siemens Industrial Experience is a design system for designers and developers, to consistently create the perfect digital experience for industrial software products.
https://ix.siemens.io/
MIT License
198 stars 67 forks source link

theme switching doesn't work if the theme class is not first in the classList #888

Open freed00m opened 11 months ago

freed00m commented 11 months ago

What happened?

If the class "theme-*" is not first in the body classList, then the theme switching is broken due to following matching

 :root .theme-brand-dark, :root body:not([class^="theme-"]) 

The offending character is ^

Reasoning is, that for many of us use different tooling or frameworks and we do not have full control over the order of classList in the body element.

Tools such as Storybook v7 are using classes to decorate the body of the stories and if we add theme switching, it does break when the classList for example

<body class="sb-show-main sb-main-padded dark theme-brand-dark">

Then using standard theme switch themeSwitcher.setTheme('theme-brand-light')

results in

but the matcher ` :root .theme-brand-dark, :root body:not([class^="theme-"]) ` still targets `` Temporary crazy workaround is to touch the classList and enforce the theme name be first looks like this. ```Typescript const bodyEl = document.querySelector('body') let myClassList = bodyEl?.classList.value.split(' ') if (isDarkBooleanFromUpsteram) { themeSwitcher.setTheme('theme-brand-dark') const bufferOfClasses: string[] = [] bodyEl?.classList.value.split(' ').forEach((x) => { if (x !== 'theme-brand-dark') { bufferOfClasses.push(x) bodyEl?.classList.remove(x) } }) bufferOfClasses.forEach((x) => { bodyEl?.classList.add(x) }) } else { themeSwitcher.setTheme('theme-brand-light') const bufferOfClasses: string[] = [] bodyEl?.classList.value.split(' ').forEach((x) => { if (x !== 'theme-brand-light') { bufferOfClasses.push(x) bodyEl?.classList.remove(x) } }) bufferOfClasses.forEach((x) => { bodyEl?.classList.add(x) }) } ``` ### What type of frontend frameware are you seeing the problem on? Angular ### Which version of iX do you use? v2 ### Code to produce this issue. ```shell To simple reproduce this issue, just create any app with ix design system with some classes that do not start with **theme-** and switch theme with the theme switcher.
ridvandmrc commented 11 months ago

How did you import the theme-brand-light.css file in your project?

freed00m commented 11 months ago

The same way you state in your documentation.

src/main.ts

import { enableProdMode } from '@angular/core'
import { platformBrowserDynamic } from '@angular/platform-browser-dynamic'
import { AppModule } from '@app/app.module'
import { environment } from '@env'

// mandatory ix loader for custom elements
import {
  applyPolyfills,
  defineCustomElements,
} from '@siemens/ix-brand-theme/loader'

applyPolyfills().then(() => defineCustomElements())

if (environment.production) {
  enableProdMode()
}

// convention: "Do include error handling in the bootstrapping logic."
platformBrowserDynamic()
  .bootstrapModule(AppModule)
  .catch((err) => console.error(err))

And at default styles src/styles.scss

...

@import '@siemens/ix-icons/dist/css/ix-icons.css';
@import '@siemens/ix/dist/siemens-ix/siemens-ix.css';

...
freed00m commented 11 months ago

It's very common that frameworks (Angular) modify body class.

For example I often end up <body class="ng-tns-0-2 theme-brand-light" which ng-tns-0-2 order is outside our control.

Breaks theme switching.

danielleroux commented 11 months ago

It's very common that frameworks (Angular) modify body class.

For example I often end up <body class="ng-tns-0-2 theme-brand-light" which ng-tns-0-2 order is outside our control.

Breaks theme switching.

Yep your right the css selector is wrong.