@esportsplus/ui
v0.51.2
Published
A reactive component library built on compile-time template transformations. Provides typed, tree-shakeable UI components with integrated SCSS theming.
Downloads
5,133
Readme
@esportsplus/ui
A reactive component library built on compile-time template transformations. Provides typed, tree-shakeable UI components with integrated SCSS theming.
Installation
pnpm add @esportsplus/uiDependencies
@esportsplus/frontend- Tagged template literals with compile-time transforms and reactive state management@esportsplus/action- Response/error handling@esportsplus/utilities- Core utilities
Quick Start
import { button, form, input, select } from '@esportsplus/ui';
import { html } from '@esportsplus/frontend';
// Simple component
html`${button({}, 'Click Me')}`;
// Form with validation
html`
${form.action({
action: async ({ input: data }) => {
const result = await api.submit(data);
return result.ok ? { errors: [] } : { errors: result.errors };
}
}, html`
${input({ name: 'email', type: 'email' })}
${button({}, 'Submit')}
`)}
`;
// Select with reactive state
html`
${select({
options: { a: 'Option A', b: 'Option B' },
selected: 'a'
}, (state) => html`Selected: ${state.selected}`)}
`;Components
Form Controls
| Component | Description | Variants |
|-----------|-------------|----------|
| input | Text input with validation state | - |
| textarea | Multi-line text input | - |
| checkbox | Checkbox with label | - |
| radio | Radio button group | - |
| range | Range slider | - |
| select | Dropdown with custom options | - |
| switch | Toggle switch | - |
| form | Form wrapper | form.action, form.input |
Interactive
| Component | Description | Variants |
|-----------|-------------|----------|
| button | Standard button | button.hold |
| tooltip | Popup content | tooltip.menu, tooltip.onclick, tooltip.onhover |
| accordion | Collapsible sections | - |
| clipboard | Copy to clipboard | clipboard.onclick, clipboard.write |
| alert | Notifications | error, info, success types |
Display
| Component | Description |
|-----------|-------------|
| counter | Animated number with currency formatting |
| loader | Loading spinner |
| loading | Border loading indicator |
| typewriter | Animated typing effect |
| highlight | Viewport intersection highlight |
| ellipsis | Animated dots |
| icon | SVG sprite wrapper |
| number | Number formatting |
| truncate | Text truncation |
| json | JSON display |
Layout
| Component | Description |
|-----------|-------------|
| scrollbar | Custom scrollbar container |
| frame | Scrollable frame |
| sidebar | Side navigation |
| site | Site wrapper |
| overlay | Modal/overlay container |
Utility
| Component | Description |
|-----------|-------------|
| back | Back navigation link |
| root | Global event coordination (root.onclick) |
| template | Template factory helper |
Component Patterns
Factory Pattern
Components use template.factory() supporting flexible call signatures:
// No arguments
component()
// Attributes only
component({ class: 'custom' })
// Content only
component(html`<span>Content</span>`)
// Both
component({ class: 'custom' }, html`<span>Content</span>`)Reactive State
Components can accept and return reactive state:
import { reactive } from '@esportsplus/frontend';
let state = reactive({ active: false });
accordion({ state }, html`
${() => state.active ? 'Open' : 'Closed'}
`);Form Integration
form.action({
action: async ({ input, response }) => {
// input: parsed FormData with dot-notation support
// response: error handling utilities
return { errors: [] };
}
}, content);
// Input with error state
form.input(element, { error: 'Required field' });Styling
CSS Layers
Styles are organized into layers for proper cascade:
@layer normalize
@layer components
@layer themes
@layer css-utilitiesImporting Styles
// All component styles
@use '@esportsplus/ui/*.scss';
// Specific component
@use '@esportsplus/ui/button.scss';
// CSS utilities
@use '@esportsplus/ui/css-utilities.scss';
// Design tokens
@use '@esportsplus/ui/tokens.scss';
// Theme
@use '@esportsplus/ui/themes/dark/*.scss';Design Tokens
Located in tokens.scss:
- Colors:
--color-{name}-{300|400|500}(black, white, red, green, blue, purple, yellow, grey) - Sizing:
--size-{300-800}(12px-80px) - Spacing:
--spacing-{0-600} - Border:
--border-radius-{100-900},--border-width-{100-700} - Typography:
--font-size-*,--font-weight-*,--line-height-*
CSS Utilities
<!-- Layout -->
<div class="--flex --flex-center --gap-200">
<!-- Spacing -->
<div class="--margin-400 --padding-200">
<!-- Typography -->
<p class="--text-uppercase --color-grey-400">
<!-- States -->
<div class="--skeleton --disabled --hidden">Component Variables
Each component exposes CSS custom properties:
.ui-button {
--background: var(--color-blue-400);
--color: var(--color-white);
--border-radius: var(--border-radius-300);
--padding-horizontal: 16px;
--padding-vertical: 8px;
}Theming
// JavaScript
import '@esportsplus/ui/themes/dark';
// SCSS
@use '@esportsplus/ui/themes/dark/*.scss';Themes override component variables. Create custom themes by overriding CSS custom properties.
Build
pnpm build # Full build (SCSS + TypeScript)
pnpm build:vite # SCSS compilation only
pnpm build:ts # TypeScript compilation onlyOutput Structure
build/
├── components/
│ ├── {component}/
│ │ ├── index.js
│ │ ├── index.d.ts
│ │ └── scss/index.scss
│ └── index.js
├── css-utilities/
├── themes/
│ ├── dark/
│ └── light/
└── fonts/TypeScript
Full type safety with zero any types:
import type { Attributes } from '@esportsplus/frontend';
// Components are generic
template.factory<A extends Attributes, C>(fn);
// State types are explicit
type State = {
active: boolean;
error: string;
};Performance
- Compile-time transforms: Template expressions optimized at build
- Tree-shakeable: Import only what you use
- WeakMap caching: Memoized formatters and icons
- Object pooling: Reused queue structures
- RAF batching: Coalesced DOM updates
- CSS layers: Efficient cascade resolution
License
MIT
