@webeach/react-x
v0.1.0
Published
Extended React JSX syntax for conditional classes, inline styles, and CSS variables
Downloads
4
Maintainers
Readme
💎 Особенности
- 🎨 Условные CSS-классы — добавляйте классы через
class:имяКлассас поддержкой CSS Modules - 💅 Inline-стили как пропсы — задавайте стили через
style:свойство - 🔧 CSS-переменные — передавайте CSS custom properties через
var:имяПеременной - 📋 classList — массив классов вместо конкатенации строк
- 🏷️ Все HTML/SVG теги — готовые компоненты
x.div,x.span,x.svgи т.д. - 🔄 HOC для компонентов — оборачивайте свои компоненты через
x(Component) - 📝 Полная типизация — TypeScript из коробки
📦 Установка
npm install @webeach/react-xили
pnpm install @webeach/react-xили
yarn add @webeach/react-x🚀 Быстрый старт
import { x } from '@webeach/react-x';
function App() {
const isActive = true;
const isDisabled = false;
return (
<x.div
class:container={true}
class:active={isActive}
class:disabled={isDisabled}
style:padding="20px"
style:backgroundColor="#f0f0f0"
var:primaryColor="#007bff"
>
Привет, мир!
</x.div>
);
}Результат в DOM:
<div
class="container active"
style="padding: 20px; background-color: #f0f0f0; --primaryColor: #007bff;"
>
Привет, мир!
</div>🛠 API
Объект x
Главный экспорт библиотеки. Работает двумя способами:
1. Как коллекция расширенных HTML/SVG тегов
import { x } from '@webeach/react-x';
// HTML теги
<x.div>...</x.div>
<x.span>...</x.span>
<x.button>...</x.button>
<x.input />
<x.form>...</x.form>
// SVG теги
<x.svg>...</x.svg>
<x.path />
<x.circle />
<x.rect />Поддерживаются все стандартные HTML и SVG теги.
2. Как HOC для оборачивания компонентов
import { x } from '@webeach/react-x';
// Ваш компонент
const ButtonInternal = ({ className, style, children, ...props }) => (
<button className={className} style={style} {...props}>
{children}
</button>
);
// Расширенный компонент
const Button = x(Button);
// Использование
<Button
class:primary
class:large={size === 'large'}
style:borderRadius="8px"
var:btnColor="blue"
>
Нажми меня
</Button>Условные CSS-классы: class:
Добавляйте CSS-классы условно через пропсы с префиксом class:.
<x.div
class:visible={isVisible} // добавится если isVisible === true
class:hidden={!isVisible} // добавится если isVisible === false
class:active={isActive}
class:error={hasError}
class:my-custom-class // можно использовать kebab-case
>
Контент
</x.div>Поддерживаемые типы значений:
boolean—trueдобавляет класс,falseне добавляетstring— используется как алиас (имя класса из значения, а не из ключа)null | undefined— класс не добавляется
Использование с CSS Modules
Передавайте строку для использования с CSS Modules — значение становится именем класса:
import styles from './Button.module.css';
<x.button
class:base={styles.button} // добавит класс из styles.button
class:primary={styles.primary} // добавит класс из styles.primary
class:disabled={isDisabled && styles.disabled} // условно
>
Нажми меня
</x.button>Если styles.button = "Button_button__x7f2s", результат:
<button class="Button_button__x7f2s Button_primary__a3bc1">
Нажми меня
</button>Важно: При передаче строки используется значение как имя класса, а не ключ после class:.
Массив классов: classList
Альтернативный способ передачи нескольких классов через массив:
const classes = ['card', 'card-primary', isLarge && 'card-large'];
<x.div classList={classes}>
Контент
</x.div>Falsy элементы массива автоматически фильтруются.
Можно комбинировать с className и class::
<x.div
className="base-class"
classList={['additional', 'classes']}
class:conditional
>
Все три способа работают вместе
</x.div>
// Результат: class="base-class additional classes conditional"Inline-стили: style:
Задавайте CSS-свойства напрямую через пропсы с префиксом style:.
<x.div
style:display="flex"
style:justifyContent="center"
style:alignItems="center"
style:gap="10px"
style:padding="20px"
style:backgroundColor="#f5f5f5"
style:borderRadius="8px"
>
Flex контейнер
</x.div>Преимущества:
- Автодополнение в IDE для имён CSS-свойств
- Типизация значений
- Чистый синтаксис без вложенных объектов
Можно комбинировать с обычным style:
<x.div
style={{ margin: '10px' }}
style:padding="20px"
style:color="red"
>
Стили объединяются
</x.div>CSS-переменные: var:
Передавайте CSS custom properties (переменные) через пропсы с префиксом var:.
<x.div
var:primaryColor="#007bff"
var:secondaryColor="#6c757d"
var:spacing="16px"
var:columns={3}
>
<x.span style:color="var(--primaryColor)">
Текст основным цветом
</x.span>
</x.div>Результат в DOM:
<div style="--primaryColor: #007bff; --secondaryColor: #6c757d; --spacing: 16px; --columns: 3;">
<span style="color: var(--primaryColor);">
Текст основным цветом
</span>
</div>Поддерживаемые типы значений:
string—var:color="red"number—var:columns={3}null— для сброса переменной
Типизация CSS-переменных
Можно типизировать доступные CSS-переменные для компонента:
import { ReactNode } from 'react';
import { x } from '@webeach/react-x';
// Определяем тип переменных
type ThemeVars = {
primaryColor: string;
secondaryColor: string;
spacing: number;
};
// Типизированный компонент
const ThemedBox = x<{ children: ReactNode }, ThemeVars>(
({ children, className, style }) => (
<div className={className} style={style}>
{children}
</div>
)
);
// Теперь IDE подсказывает доступные переменные
<ThemedBox
var:primaryColor="blue" // ✓ автодополнение работает
var:secondaryColor="gray" // ✓
var:spacing={16} // ✓
var:unknownVar="value" // ✗ ошибка TypeScript
>
Контент
</ThemedBox>📥 Примеры использования
Кнопка с вариантами
import { ReactNode } from 'react';
import { x } from '@webeach/react-x';
type ButtonProps = {
variant?: 'primary' | 'secondary' | 'danger';
size?: 'small' | 'medium' | 'large';
disabled?: boolean;
children: ReactNode;
};
function Button({ variant = 'primary', size = 'medium', disabled, children }: ButtonProps) {
return (
<x.button
class:btn
class:btn-primary={variant === 'primary'}
class:btn-secondary={variant === 'secondary'}
class:btn-danger={variant === 'danger'}
class:btn-sm={size === 'small'}
class:btn-lg={size === 'large'}
class:disabled={disabled}
disabled={disabled}
>
{children}
</x.button>
);
}Кнопка с CSS Modules
import { ReactNode } from 'react';
import { x } from '@webeach/react-x';
import styles from './Button.module.css';
type ButtonProps = {
variant?: 'primary' | 'secondary';
disabled?: boolean;
children: ReactNode;
};
function Button({ variant = 'primary', disabled, children }: ButtonProps) {
return (
<x.button
class:base={styles.button}
class:variant={variant === 'primary' ? styles.primary : styles.secondary}
class:disabled={disabled && styles.disabled}
disabled={disabled}
>
{children}
</x.button>
);
}Карточка с темой
import { x } from '@webeach/react-x';
function Card({ title, children, accentColor = '#007bff' }) {
return (
<x.article
class:card
var:accentColor={accentColor}
style:borderLeft="4px solid var(--accentColor)"
style:padding="20px"
style:borderRadius="8px"
style:boxShadow="0 2px 8px rgb(0 0 0 / 0.1)"
>
<x.h2 style:color="var(--accentColor)" style:marginTop="0">
{title}
</x.h2>
{children}
</x.article>
);
}Адаптивная сетка
import { x } from '@webeach/react-x';
function Grid({ columns = 3, gap = '16px', children }) {
return (
<x.div
style:display="grid"
style:gridTemplateColumns={`repeat(${columns}, 1fr)`}
style:gap={gap}
>
{children}
</x.div>
);
}SVG иконка
import { x } from '@webeach/react-x';
function Icon({ size = 24, color = 'currentColor' }) {
return (
<x.svg
var:iconSize={`${size}px`}
var:iconColor={color}
style:width="var(--iconSize)"
style:height="var(--iconSize)"
viewBox="0 0 24 24"
fill="none"
stroke="var(--iconColor)"
strokeWidth="2"
>
<x.path d="M12 2L2 7l10 5 10-5-10-5z" />
<x.path d="M2 17l10 5 10-5" />
<x.path d="M2 12l10 5 10-5" />
</x.svg>
);
}📐 Экспортируемые типы
import type { XClassProps, XStyleProps, XVarProps } from '@webeach/react-x';XClassProps— типы для пропсовclass:*XStyleProps— типы для пропсовstyle:*(на основеCSSProperties)XVarProps<T>— типы для пропсовvar:*с опциональной типизацией переменных
⚖️ Сравнение с альтернативами
| Возможность | react-x | clsx/classnames | styled-components |
|------------------|--------------------------|--------------------------|---------------------------|
| Условные классы | class:active={bool} | clsx({ active: bool }) | ${bool && 'active'} |
| CSS Modules | class:x={styles.class} | clsx(styles.class) | ❌ |
| Inline стили | style:padding="10px" | ❌ | Встроено |
| CSS переменные | var:color="red" | ❌ | ${props => props.color} |
| TypeScript | ✅ Полный | ✅ | ✅ |
| Runtime overhead | Минимальный | Минимальный | CSS-in-JS |
| Размер бандла | ~2KB | ~1KB | ~15KB |
🧩 Зависимости
Библиотека не имеет внешних зависимостей (Zero dependencies).
🔖 Выпуск новой версии
Релизы обрабатываются автоматически с помощью semantic-release.
Перед публикацией новой версии убедись, что:
- Все изменения закоммичены и запушены в ветку
main. - Сообщения коммитов соответствуют формату Conventional Commits:
feat: ...— для новых фичfix: ...— для исправлений баговchore: ...,refactor: ...и другие типы — по необходимости
- Версионирование определяется автоматически на основе типа коммитов (
patch,minor,major).
👨💻 Автор
Разработка и поддержка: Руслан Мартынов
Если у тебя есть предложения или найден баг, открывай issue или отправляй pull request.
📄 Лицензия
Этот пакет распространяется под лицензией MIT.
