Rocketstyle
Dimension-based component styling system with theming, pseudo-states, and chainable API.
Rocketstyle is a dimension-based styling system for React. It wraps any component and adds named styling dimensions (states, sizes, variants), theme integration with light/dark mode, pseudo-state tracking, provider/consumer patterns, and a chainable configuration API.
Installation
npm install @vitus-labs/rocketstyleRequires @vitus-labs/core and a CSS engine connector (@vitus-labs/connector-styler).
Try It Live
This demo shows the dimension-based styling concept — select a state and size to see how styles compose:
function DimensionDemo() { const [state, setState] = React.useState('primary') const [size, setSize] = React.useState('md') const states = { primary: { backgroundColor: '#0d6efd', color: '#fff' }, secondary: { backgroundColor: '#6c757d', color: '#fff' }, danger: { backgroundColor: '#dc3545', color: '#fff' }, success: { backgroundColor: '#198754', color: '#fff' }, } const sizes = { sm: { fontSize: 12, padding: '6px 12px' }, md: { fontSize: 14, padding: '10px 20px' }, lg: { fontSize: 16, padding: '14px 28px' }, } const merged = { ...states[state], ...sizes[size] } return ( <div style={{ fontFamily: 'system-ui' }}> <div style={{ display: 'flex', gap: 16, marginBottom: 16, flexWrap: 'wrap' }}> <div style={{ display: 'flex', gap: 4, alignItems: 'center', fontSize: 13 }}> State: {Object.keys(states).map((s) => ( <button key={s} onClick={() => setState(s)} style={{ padding: '4px 10px', borderRadius: 4, fontSize: 12, cursor: 'pointer', border: state === s ? '2px solid #333' : '1px solid #ccc', background: state === s ? '#f0f0f0' : '#fff', }}>{s}</button> ))} </div> <div style={{ display: 'flex', gap: 4, alignItems: 'center', fontSize: 13 }}> Size: {Object.keys(sizes).map((s) => ( <button key={s} onClick={() => setSize(s)} style={{ padding: '4px 10px', borderRadius: 4, fontSize: 12, cursor: 'pointer', border: size === s ? '2px solid #333' : '1px solid #ccc', background: size === s ? '#f0f0f0' : '#fff', }}>{s}</button> ))} </div> </div> <button style={{ ...merged, border: 'none', borderRadius: 6, cursor: 'pointer', fontWeight: 500, transition: 'all 0.2s', }}> Button ({state} / {size}) </button> <pre style={{ marginTop: 12, padding: 12, borderRadius: 6, background: '#f8f9fa', fontSize: 12, lineHeight: 1.5, }}> {JSON.stringify(merged, null, 2)} </pre> </div> ) } render(<DimensionDemo />)
Quick Start
import { init } from '@vitus-labs/core'
import * as styler from '@vitus-labs/connector-styler'
import rocketstyle from '@vitus-labs/rocketstyle'
init(styler)
const Button = rocketstyle()({
name: 'Button',
component: 'button',
})
.theme((theme) => ({
fontFamily: theme.fontFamily?.base,
borderRadius: '4px',
}))
.states((theme) => ({
primary: {
backgroundColor: 'blue',
color: 'white',
},
secondary: {
backgroundColor: 'gray',
color: 'black',
},
}))
.sizes((theme) => ({
sm: { fontSize: '12px', padding: '4px 8px' },
md: { fontSize: '14px', padding: '8px 16px' },
lg: { fontSize: '16px', padding: '12px 24px' },
}))
.styles((css) => css`
cursor: pointer;
border: none;
font-family: ${({ $rocketstyle }) => $rocketstyle.fontFamily};
font-size: ${({ $rocketstyle }) => $rocketstyle.fontSize};
padding: ${({ $rocketstyle }) => $rocketstyle.padding};
background-color: ${({ $rocketstyle }) => $rocketstyle.backgroundColor};
color: ${({ $rocketstyle }) => $rocketstyle.color};
border-radius: ${({ $rocketstyle }) => $rocketstyle.borderRadius};
&:hover {
opacity: 0.9;
}
`)
// Usage — explicit prop syntax
<Button state="primary" size="lg">Click me</Button>
// Boolean shorthand (useBooleans enabled by default)
<Button primary lg>Click me</Button>Factory Function
The factory uses a curried call pattern:
rocketstyle(options?)(config)Options (First Call)
| Option | Type | Default | Description |
|---|---|---|---|
dimensions | Record<string, string | DimensionConfig> | See below | Custom dimension definitions |
useBooleans | boolean | true | Enable boolean shorthand props |
Config (Second Call)
| Option | Type | Description |
|---|---|---|
name | string | Required. Component display name |
component | ComponentType | string | Required. React component or HTML tag to wrap |
Default Dimensions
{
states: 'state', // Maps to `state` prop
sizes: 'size', // Maps to `size` prop
variants: 'variant', // Maps to `variant` prop
multiple: { // Multi-select dimension
propName: 'multiple',
multi: true // Accepts array values
}
}Custom Dimensions
Override the defaults entirely:
const Card = rocketstyle({
dimensions: {
colors: 'color',
shapes: {
propName: 'shape',
multi: true, // Allows array: shape={['rounded', 'elevated']}
},
},
})({
name: 'Card',
component: 'div',
})
.colors((theme) => ({
primary: { backgroundColor: 'blue' },
secondary: { backgroundColor: 'gray' },
}))
.shapes((theme) => ({
rounded: { borderRadius: '8px' },
elevated: { boxShadow: '0 2px 8px rgba(0,0,0,0.1)' },
}))Each custom dimension key becomes a chainable method automatically.
Validation
In development mode, the factory validates:
componentis providednameis provideddimensionsis not empty- Dimension names don't conflict with reserved keys
Throws a JSON-structured error if validation fails.
Reserved Dimension Names
These names cannot be used as dimension keys:
light, dark, theme, styles, compose, attrs,
provider, consumer, DEBUG, name, component,
inversed, passProps, styledRender Pipeline
When a rocketstyle component renders, it follows this sequence:
1. Ref handling — merge forwarded ref + internal $rocketstyleRef
2. Local context — read parent provider state via useLocalContext()
3. Theme resolution — get theme + mode from context, apply inversed flag
4. Base theme cache — WeakMap lookup → getThemeFromChain() if miss
5. Dimension themes — WeakMap lookup → getDimensionThemes() if miss
6. Mode resolution — resolve mode callbacks in base + dimension themes
7. Dimension map — build keysMap + keywords for boolean resolution
8. Props merge — { ...localCtx, ...props } (explicit props win)
9. Pseudo-state merge — combine context pseudo + explicit pseudo props
10. Styling attrs — resolve active dimension values from props
11. $rocketstyle — merge base theme + active dimension themes
12. Final props — strip reserved props, add $rocketstyle/$rocketstate
13. Render — <StyledComponent {...finalProps} />Steps 4-6 use WeakMap caching — the expensive theme computation runs only once per unique theme reference.
Boolean Shorthand
When useBooleans is enabled (default), dimension values can be used as boolean props:
// These are equivalent:
<Button state="primary" size="lg" />
<Button primary lg />Resolution Rules
- Explicit props take priority:
state="primary"always wins over booleansecondary - Boolean shorthand only activates when the explicit prop is not set
- For single-select dimensions, last boolean prop wins (props keys are reversed)
- For multi-select dimensions (
multi: true), all matching booleans are collected into an array - Standard HTML boolean attributes (disabled, checked, hidden, etc.) are excluded from shorthand matching
Disabling Boolean Shorthand
const Component = rocketstyle({
useBooleans: false,
})({
name: 'Component',
component: 'div',
})
// Only explicit prop syntax works:
<Component state="primary" />
// <Component primary /> would NOT workType Utilities
// Extract rocketstyle dimension props
type ButtonDimensions = typeof Button['$$rocketstyle']
// Extract original component props
type OriginProps = typeof Button['$$originTypes']
// Extract extended props from .attrs() chains
type ExtendedProps = typeof Button['$$extendedTypes']
// Get all combined props
type AllProps = typeof Button['$$types']
// Check if component is rocketstyle
import { isRocketComponent } from '@vitus-labs/rocketstyle'
isRocketComponent(Button) // trueStatic Properties
Every rocketstyle component has these properties:
| Property | Type | Description |
|---|---|---|
IS_ROCKETSTYLE | true | Marker for identification |
displayName | string | Component name from config |
meta | object | User-defined statics from .statics() |
getStaticDimensions | (theme) => DimensionInfo | Get dimension map for a theme |
getDefaultAttrs | (props, theme, mode) => attrs | Compute attrs without rendering |
$$rocketstyle | Type-only | Dimension props type |
$$originTypes | Type-only | Original component props type |
$$extendedTypes | Type-only | Extended props from .attrs() |
$$types | Type-only | All combined props type |
getStaticDimensions
Returns the dimension configuration resolved against a theme:
const info = Button.getStaticDimensions(theme)
// {
// dimensions: { state: { primary: true, secondary: true }, size: { sm: true, md: true, lg: true } },
// keywords: { state: true, primary: true, secondary: true, size: true, sm: true, md: true, lg: true },
// useBooleans: true,
// multiKeys: { multiple: true },
// }Debug Mode
Enable per-component debug logging:
const Button = rocketstyle()({
name: 'Button',
component: 'button',
}).config({ DEBUG: true })In development, this logs on every render:
- Component name
- Resolved
$rocketstylevalues - Resolved
$rocketstatevalues - Active dimension selections
- Theme mode
All components also get a data-rocketstyle attribute in development with the component name.
Exports
import rocketstyle, {
Provider,
context,
isRocketComponent,
} from '@vitus-labs/rocketstyle'
import type {
RocketStyleComponent,
RocketComponentType,
RocketProviderState,
ConsumerCtxCBValue,
ConsumerCtxCb,
ConsumerCb,
Dimensions,
DimensionValue,
DimensionCallbackParam,
ExtractDimensionProps,
DimensionProps,
ExtractDimensions,
StylesDefault,
StylesCb,
RocketStyleInterpolationProps,
ConfigAttrs,
AttrsCb,
ThemeCb,
ThemeModeCallback,
ThemeModeKeys,
GenericHoc,
ComposeParam,
DefaultProps,
IsRocketComponent,
ThemeMode,
TProvider,
IRocketStyleComponent,
Rocketstyle,
} from '@vitus-labs/rocketstyle'API Reference
Prop
Type
Prop
Type