Haunted — это лёгкая библиотека для создания веб-компонентов на базе стандартов Web Components с использованием реактивного подхода, вдохновлённого React Hooks. Одной из ключевых возможностей для построения масштабируемых интерфейсов является темизация компонентов. Темизация позволяет создавать единый стиль приложения и обеспечивать его динамическое изменение без переписывания логики компонентов.
В Haunted темизация может быть реализована несколькими способами:
Через CSS-переменные Наиболее гибкий и
современный подход. Компоненты используют переменные CSS для цветовой
схемы, шрифтов и размеров, а родительский элемент или :root
задаёт их значения.
import { html, component } from 'haunted';
const Button = ({ label }) => html`
<button class="btn">${label}</button>
<style>
.btn {
background-color: var(--btn-bg, #007bff);
color: var(--btn-color, #fff);
border: none;
padding: 0.5em 1em;
border-radius: 4px;
cursor: pointer;
transition: background-color 0.3s;
}
.btn:hover {
background-color: var(--btn-bg-hover, #0056b3);
}
</style>
`;
customElements.define('my-button', component(Button));
Здесь ключевой момент — гибкость через переменные CSS. Их можно менять на уровне документа или контейнера:
:root {
--btn-bg: #28a745;
--btn-color: #fff;
--btn-bg-hover: #218838;
}
Это позволяет динамически менять тему всего приложения без изменения компонентов.
Использование контекста (Context API) Haunted
предоставляет встроенный механизм контекста через provide и
useContext. Контекст удобен для передачи темы глубоко
вложенным компонентам.
import { provide, useContext } from 'haunted';
const ThemeContext = Symbol('ThemeContext');
const ThemeProvider = ({ theme, children }) => {
provide(ThemeContext, theme);
return html`${children}`;
};
const ThemedButton = () => {
const theme = useContext(ThemeContext);
return html`
<button style="background: ${theme.primary}; color: ${theme.text}">
Themed Button
</button>
`;
};
В этом подходе изменения темы требуют обновления контекста, что автоматически приведёт к перерисовке всех потребителей контекста.
Прямое внедрение стилей через свойства
компонентов Каждый компонент может принимать объект стилей
через свойства, например styles или theme. Это
удобно для случаев, когда необходимо настроить тему локально.
const Card = ({ title, content, styles = {} }) => html`
<div style="background: ${styles.bg || '#fff'}; color: ${styles.color || '#000'}; padding: 1em; border-radius: 8px;">
<h3>${title}</h3>
<p>${content}</p>
</div>
`;
Такой способ подходит для компонентов, которые должны быть максимально настраиваемыми на уровне родителя.
Для реализации динамической смены темы чаще всего используется сочетание CSS-переменных и контекста. При изменении темы в контексте переменные CSS обновляются, что автоматически отражается на всех компонентах.
const darkTheme = {
'--bg-color': '#121212',
'--text-color': '#ffffff',
'--btn-bg': '#1f1f1f',
'--btn-color': '#ffffff'
};
const applyTheme = theme => {
Object.entries(theme).forEach(([key, value]) => {
document.documentElement.style.setProperty(key, value);
});
});
applyTheme(darkTheme);
После вызова applyTheme(darkTheme) все компоненты,
использующие соответствующие CSS-переменные, изменят стиль без
дополнительной логики внутри них.
Часто проекты используют несколько заранее определённых тем, например
light и dark. Их удобно хранить в виде
объектов:
const themes = {
light: {
'--bg-color': '#ffffff',
'--text-color': '#000000',
'--btn-bg': '#007bff',
'--btn-color': '#ffffff'
},
dark: {
'--bg-color': '#121212',
'--text-color': '#ffffff',
'--btn-bg': '#1f1f1f',
'--btn-color': '#ffffff'
}
};
Смена темы сводится к вызову applyTheme(themes.dark) или
applyTheme(themes.light).