Theming

Dark Mode, die Farbpalette, Design-Tokens und die Schrift Rubik.

Dark Mode

Es gibt keinen Theme-Provider und keinen globalen Schalter. Jede Komponente hat eine boolesche Property dark und zeichnet sich mit der dunklen Palette, wenn sie gesetzt ist:

<tuix-text dark>Auf dunkler Fläche</tuix-text>
<tuix-paper elevation="2" dark>
    <tuix-button variant="secondary" dark>Abbrechen</tuix-button>
</tuix-paper>

Die Anwendung entscheidet und reicht es durch. In den Tuix-Frontends ist das ein Context, der zusätzlich data-theme auf <html> schreibt, damit CSS auf Seitenebene auf denselben Zustand reagieren kann:

const { isDarkMode } = useDarkModeContext()
 
return <TuixButton dark={isDarkMode}>Speichern</TuixButton>

dark wird nicht über das DOM vererbt. Eine Komponente in einem dunklen tuix-paper bleibt hell, solange sie nicht selbst dark bekommt.

Farbpalette

Zwei Enums halten die Palette, eines pro Theme. Die Namen sind dieselben, eine Komponente kann die Map also über ihr dark-Flag wählen:

import { DarkPalette, Palette } from 'tuix-webcomponents'
 
const border = isDark ? DarkPalette.NEUTRAL_200 : Palette.NEUTRAL_200
TokenHellDunkel
PRIMARY_50#F2F3FA#F4F5FB
PRIMARY_100#E3E5F4#E3E5F4
PRIMARY_200#C7CAE8#C7CAE8
PRIMARY_300#AAAFE0#AAAFE0
PRIMARY_400#8B90D2#8B90D2
MAIN#585A9D#6F73B8
DARK_MAIN#6F73B8#6F73B8
PRIMARY_600#4E508E#5C60A4
PRIMARY_700#404277#4A4E8E
PRIMARY_800#32345F#32355F
PRIMARY_900#22233F#181A32
PRIMARY_950#1F1E33#1F1E33
SECONDARY#BBADFF#BBADFF
WHITE#FFFFFF#FFFFFF
BLACK#121212#0F1117
NEUTRAL_200#FAFAFA#C9C8D3
NEUTRAL_600#b6b6b6#8A8894
SUCCESS#439F6E#6BC49D
SUCCESS_50#F1F9F5#F1F9F5
VALIDATION#FFB82E#F5C66A
VALIDATION_50#FFFBF4#FFFBF4
VALIDATION_200#FFEAC1#FFEAC1
ERROR#F93232#FF7A7A
ERROR_50#FFF5F5#FFF5F5
ERROR_200#FFD8D8#FFD8D8
SECTION_BG#FAFAFA#0E0E0E
DISABLED_BG#EBEAF4Keine
STROKE_GREY#E1E0E7#32355F
SHADOWrgba(66, 79, 101, 0.16)Keine

DarkPalette hat acht zusätzliche Tokens ohne helles Gegenstück.

ELEVATION_1 … ELEVATION_4 (#141722, #181C29, #1D2131, #23273A) stehen einer Anwendung zur Verfügung, die eigene dunkle Flächen stapelt; tuix-paper berechnet seine dunklen Hintergründe selbst und liest sie nicht, deshalb ist seine Elevation-Tabelle der Bezug für eine verschachtelte Fläche.

CSS Custom Properties

Dieselbe Palette gibt es als Stylesheet, damit auch CSS ausserhalb von TypeScript sie nutzen kann:

import 'tuix-webcomponents/dist/assets/tuix-styles.css'

Es legt beide Paletten gleichzeitig auf :root, benannt nach dem Enum-Schlüssel in Kleinbuchstaben:

.invoice-total {
    color: var(--tuix-light-color-main);
    border-bottom: 1px solid var(--tuix-light-color-neutral-200);
}
 
:root[data-theme='dark'] .invoice-total {
    color: var(--tuix-dark-color-main);
}

Das Stylesheet deklariert ausschliesslich Variablen und stylt nie ein Element; die Reihenfolge der Imports spielt daher keine Rolle.

Schriften

Die Komponenten setzen auf Rubik, ausgeliefert vom Tuix-CDN als je ein variabler Schnitt pro Stil. Das Stylesheet mit den Design-Tokens importiert sie, dieses Stylesheet einzubinden genügt also:

import 'tuix-webcomponents/dist/assets/tuix-styles.css'

Ein @import wird erst geholt, wenn das Stylesheet selbst geparst ist. Der Link im Head des Dokuments startet die Anfrage früher, so macht es diese Dokumentation:

<link rel="preconnect" href="https://hccdn.tuix.ch" />
<link rel="stylesheet" href="https://hccdn.tuix.ch/rubik_d444e2375d.css" />

Rubik lässt sich statt über das CDN auch über die Font-Pipeline des Frameworks ausliefern.

Elevation und Flächen

tuix-paper ist das Flächen-Primitiv: es trägt die Hintergrundfarbe, den Schatten und die Eckenrundung. Inhalt gehört besser in ein tuix-paper als in eine nachgebaute Karte, damit Hell und Dunkel konsistent bleiben. Siehe tuix-paper.

Breakpoints

Die Komponenten wechseln das Layout bei zwei Breiten, exportiert als ScreenSizes:

NameWertWirkung
ScreenSizes.TABLET1280Engeres Padding bei Button und Icon-Button, kleinere Button-Icons
ScreenSizes.MOBILE640Engstes Padding, tuix-table rendert Karten, tuix-modal wird vollbreit
import { ScreenSizes } from 'tuix-webcomponents'
 
const isMobile = window.matchMedia(`(max-width:${ScreenSizes.MOBILE}px)`).matches

Auf dieser Seite