Темизация
01

AuraProvider

Ставит те четыре атрибута data-*, на которых держится вся таблица токенов, и отдаёт текущие значения вместе с сеттерами. Переопределения токенов идут через vars инлайновыми кастомными свойствами (CSSOM), поэтому строгая CSP на style-src не нарушается.

чистая разметка — библиотеки на странице нет
отрендерил aura-react
отрендерил aura-react
отрендерил aura-react
отрендерил aura-react
This subtree is pinned by its own provider: dark / iris

Код

index.html
<!-- Компонент-провайдер не нужен: четыре оси — это атрибуты на корне, и все токены ниже
     пересчитываются от них. -->
<html data-theme="dark" data-accent="iris" data-corner="rounded" data-density="comfortable">
  <button class="aura-btn aura-btn--primary">Now iris, on a dark canvas</button>
</html>

<script>
  // Смена темы — это одна запись атрибута: ни перерисовки, ни контекста.
  document.documentElement.setAttribute('data-accent', 'sunset');
</script>
Demo.tsx
import { AuraProvider, Button, Card, Stack, Typography, useAura } from '@ilomee/aura-react';

function ThemeReadout() {
  const { theme, accent, setTheme } = useAura();
  return (
    <Stack gap={3}>
      <Typography variant="caption" tone="muted">
        This subtree is pinned by its own provider: {theme} / {accent}
      </Typography>
      <Button variant="primary" onClick={() => setTheme(theme === 'light' ? 'dark' : 'light')}>
        Toggle just this card
      </Button>
    </Stack>
  );
}

export default function Demo() {
  // Провайдер ограничивает темизацию поддеревом — страница вокруг не меняется.
  return (
    <AuraProvider defaultTheme="dark" defaultAccent="iris">
      <Card elevation="raised">
        <ThemeReadout />
      </Card>
    </AuraProvider>
  );
}

useAura() возвращает { theme, accent, corner, density, setTheme, setAccent, setCorner, setDensity } и бросает исключение вне провайдера.

Demo.vue
<script setup lang="ts">
import { ref } from 'vue';
import { AuraProvider, Button } from '@ilomee/aura-vue';

const theme = ref<'light' | 'dark'>('light');
</script>

<template>
  <AuraProvider v-model:theme="theme" default-accent="iris">
    <Button variant="primary">Themed</Button>
  </AuraProvider>
</template>

Все четыре оси поддерживают v-model — симметричнее, чем в React, где нет колбэков для corner и density. useAura() доступен через экспортируемый AuraInjectionKey.

Demo.svelte
<script lang="ts">
  import { AuraProvider, Button } from '@ilomee/aura-svelte';

  let theme = $state<'light' | 'dark'>('light');
</script>

<AuraProvider bind:theme accent="iris">
  <Button variant="primary">Themed</Button>
</AuraProvider>

useAura() возвращает { theme, accent, corner, density, setTheme, setAccent, setCorner, setDensity }. Сеттеры пишут через bindable-пропсы, поэтому bind:theme у вызывающего тоже видит изменение.

Используется как [auraTheme] — директива, которую вы вешаете на свой элемент.

demo.component.ts
import { inject } from '@angular/core';
import { AuraTheme, AuraThemeService, AuraButton } from '@ilomee/aura-angular';

@Component({
  standalone: true,
  imports: [AuraTheme, AuraButton],
  // Непривязанные оси следуют за сервисом, поэтому setTheme() ниже перекрашивает поддерево.
  template: `
    <div auraTheme>
      <button auraButton variant="primary" (click)="toggle()">Themed</button>
    </div>
  `,
})
export class DemoComponent {
  private readonly svc = inject(AuraThemeService);

  toggle(): void {
    this.svc.theme.set(this.svc.theme() === 'light' ? 'dark' : 'light');
  }
}

Директива плюс AuraThemeService на сигналах, предоставленный в корне. Каждая ось следует за сервисом, пока вы не привяжете соответствующий вход — тогда она фиксируется; и каждая сообщает о своём изменении, так что [(theme)] пишет обратно.

Пропсы

У чистой разметки нет пропсов — классы ниже и есть весь API. Четыре пакета не делают ничего сверх того, что проставляют вам те же самые классы.
ИмяТипПо умолчаниюПримечания
theme'light' | 'dark'Управляемое значение.
defaultTheme'light' | 'dark''light'
onThemeChange(t: Theme) => void
accentAccentОдин из 10 акцентов.
defaultAccentAccent'aqua'
onAccentChange(a: Accent) => void
corner'rounded' | 'sharp' | 'pill'
defaultCorner'rounded' | 'sharp' | 'pill''rounded'
onCornerChange(c: Corner) => void
density'comfortable' | 'compact'
defaultDensity'comfortable' | 'compact''comfortable'
onDensityChange(d: Density) => void
varsRecord<`--${string}`, string>Переопределения токенов, навешиваемые на обёртку.
as'div' | 'section' | 'main''div'
ИмяТипПо умолчаниюПримечания
themeдвустороннийThemeДвусторонняя привязка через v-model:theme.
accentдвустороннийAccent
cornerдвустороннийCorner
densityдвустороннийDensity
defaultThemeTheme'light'
defaultAccentAccent'aqua'
defaultCornerCorner'rounded'
defaultDensityDensity'comfortable'
varsRecord<string, string>
asstring'div'
update:themeсобытие(t: Theme) => void
update:accentсобытие(a: Accent) => void
update:cornerсобытие(c: Corner) => void
update:densityсобытие(d: Density) => void
ИмяТипПо умолчаниюПримечания
themeдвустороннийTheme'light'$bindable.
accentдвустороннийAccent'aqua'
cornerдвустороннийCorner'rounded'
densityдвустороннийDensity'comfortable'
varsRecord<string, string>
as'div' | 'section' | 'main''div'
ИмяТипПо умолчаниюПримечания
themeдвустороннийThemeНе задавайте — и ось будет следовать за AuraThemeService.
accentдвустороннийAccentНе задавайте — и ось будет следовать за AuraThemeService.
cornerдвустороннийCornerНе задавайте — и ось будет следовать за AuraThemeService.
densityдвустороннийDensityНе задавайте — и ось будет следовать за AuraThemeService.
varsRecord<string, string>Переопределения токенов, записываемые на хост как кастомные свойства.
themeChangeсобытие(t: Theme) => void
accentChangeсобытие(a: Accent) => void
cornerChangeсобытие(c: Corner) => void
densityChangeсобытие(d: Density) => void

Какие классы отдаёт

Все фреймворки отдают одни и те же классы — именно поэтому четыре библиотеки выглядят одинаково. Их можно использовать напрямую, вообще без библиотеки компонентов.

КлассРольПримечания
[data-theme]базаОбязательный. Без него модификатор не работает.
[data-accent]базаОбязательный. Без него модификатор не работает.
[data-corner]базаОбязательный. Без него модификатор не работает.
[data-density]базаОбязательный. Без него модификатор не работает.