@obinexusltd/obix-jsx-adapter
v0.1.0
Published
Core JSX factory and runtime for OBIX components — zero dependencies, zero overhead
Maintainers
Readme
@obinexusltd/obix-jsx-adapter
JSX Hyperscript Factory for OBIX Components
What Is This?
@obinexusltd/obix-jsx-adapter is the JSX compilation target for OBIX. It provides:
h()hyperscript factory — Converts JSX to OBIX component objectsFragmentsymbol — Groups components without a wrapper- Type helpers —
ComponentPropsOf,ComponentStateOf, etc. - Zero dependencies — Just JSX compilation, nothing else
The Bridge
JSX Input (React Spec)
↓ (TypeScript Compiler)
h() Function Calls
↓ (@obinexusltd/obix-jsx-adapter)
OBIX Data Objects
↓ (@obinexusltd/obix-jsx-components)
HTML/CSS/JS OutputInstallation
npm install @obinexusltd/obix-jsx-adapterQuick Start
Configure TypeScript
{
"compilerOptions": {
"jsx": "react",
"jsxFactory": "h",
"jsxFragmentFactory": "Fragment"
}
}Use It
/** @jsx h */
/** @jsxFrag Fragment */
import { h, Fragment } from '@obinexusltd/obix-jsx-adapter';
import { obixButton, obixInput } from '@obinexusltd/obix-jsx-components';
// JSX syntax (what you write)
const button = <obix-button label="Save" />;
// ↓ (Compiler converts to)
// Function calls (what's executed)
const button = h(obixButton, { label: "Save" });
// Result: Pure OBIX data object
// {
// name: 'Button',
// state: { label: 'Save', ... },
// actions: { ... },
// render: (state) => '<button>Save</button>',
// aria: { ... }
// }API
h(component, props, ...children)
Hyperscript factory that converts JSX elements to OBIX components.
function h<T extends ComponentFactory>(
component: T | typeof Fragment,
props: PropsFor<T> | null,
...children: (ObixComponent | string | null | undefined)[]
): ObixComponent | ObixComponent[]Parameters:
component— Factory function or Fragment symbolprops— Component configuration object (null for defaults)children— Child components or text (optional, spread)
Returns:
- Single
ObixComponentif component is a factory - Array of
ObixComponent[]if component is Fragment
Examples:
// Simple button
const btn = h(obixButton, { label: 'Save' });
// Button with children (form items)
const form = h(obixForm, { label: 'Login' },
h(obixInput, { name: 'email' }),
h(obixInput, { name: 'password' }),
h(obixButton, { label: 'Sign In' })
);
// Fragment (no wrapper)
const fragment = h(Fragment, null,
h(obixInput, { label: 'First' }),
h(obixInput, { label: 'Last' })
);Fragment
Symbol for grouping components without a wrapper element.
export const Fragment = Symbol.for('ObixFragment');
// Usage
const group = h(Fragment, null,
h(obixButton, { label: 'Button 1' }),
h(obixButton, { label: 'Button 2' })
);
// Returns: [button1, button2] (array, not wrapped)Type Helpers
Extract types from component factories.
// Get props type
type ButtonProps = ComponentPropsOf<typeof obixButton>;
// Get state type
type ButtonState = ComponentStateOf<typeof obixButton>;
// Get actions type
type ButtonActions = ComponentActionsOf<typeof obixButton>;Interface: ObixComponent<S, A>
Every component created by h() returns this shape:
interface ObixComponent<S = unknown, A = unknown> {
// Data
name: string; // 'Button', 'Input', 'Form', etc.
state: S; // Current component state
actions: A; // State-modifying functions
aria?: Record<string, any>; // ARIA attributes metadata
children?: ObixComponent[]; // Child components
// Methods
render: (state: S) => string; // Render state to HTML
lifecycle?: 'CREATED' | 'UPDATED' | 'HALTED' | 'DESTROYED';
revisions?: S[]; // State history (optional)
halt?: () => void; // Pause component (optional)
resume?: () => void; // Resume component (optional)
destroy?: () => void; // Cleanup (optional)
undo?: () => void; // Undo last state (optional)
}JSX Pragma Comment
For per-file JSX configuration:
/** @jsxRuntime classic */
/** @jsx h */
/** @jsxFrag Fragment */
import { h, Fragment } from '@obinexusltd/obix-jsx-adapter';
// JSX works here
function MyComponent() {
return <obix-button label="Click" />;
}How It Works
1. JSX Syntax (Input)
<obix-button label="Save" variant="primary" />2. TypeScript Compilation
The compiler transforms JSX to function calls:
h(obixButton, { label: "Save", variant: "primary" })3. Factory Execution
The h() function:
- Validates the component is a factory function
- Processes children (filters null, flattens arrays)
- Calls the factory with props
- Attaches children to component
- Returns OBIX component object
4. Component Object
{
name: 'Button',
state: {
label: 'Save',
variant: 'primary',
disabled: false,
loading: false,
// ... more state
},
actions: {
setLabel: (state, label) => ({ ...state, label }),
setDisabled: (state, disabled) => ({ ...state, disabled }),
// ... more actions
},
render: (state) => '<button>Save</button>',
aria: { label: 'Save' }
}5. Rendering
const html = button.render(button.state);
// "<button class="obix-button obix-button--primary">Save</button>"
document.getElementById('app').innerHTML = html;Key Features
✅ Zero Dependencies — No virtual DOM, no React runtime
✅ React Spec Compliant — Standard JSX compilation
✅ Type-Safe — Full TypeScript support
✅ Fragment Support — <>...</> syntax works
✅ Children Processing — Automatic null/undefined filtering
✅ XSS Protection — Built-in HTML escaping
✅ Tiny — 3-5 KB minified
Examples
Vanilla JavaScript
<script type="module">
import { h } from '@obinexusltd/obix-jsx-adapter';
import { obixButton } from '@obinexusltd/obix-jsx-components';
const button = h(obixButton, { label: 'Click me' });
document.getElementById('app').innerHTML = button.render(button.state);
</script>TypeScript with JSX
/** @jsx h */
import { h } from '@obinexusltd/obix-jsx-adapter';
import { obixForm, obixInput, obixButton } from '@obinexusltd/obix-jsx-components';
function LoginForm() {
return (
<obix-form label="Login">
<obix-input name="email" type="email" label="Email" required />
<obix-input name="password" type="password" label="Password" required />
<obix-button label="Sign In" variant="primary" />
</obix-form>
);
}Functional Programming
import { h, Fragment } from '@obinexusltd/obix-jsx-adapter';
import { obixButton } from '@obinexusltd/obix-jsx-components';
// Reusable component factory
const Counter = (props: { count: number }) => (
<obix-button label={`Count: ${props.count}`} variant="primary" />
);
// Compose
const buttons = h(Fragment, null,
Counter({ count: 0 }),
Counter({ count: 1 }),
Counter({ count: 2 })
);Integration Points
With TypeScript Compiler
- Configures
jsxFactory: "h" - Compiles JSX to function calls
- No runtime JSX parsing needed
With Component Factories
h()calls component factory functions- Factories return OBIX component objects
- No factory-specific logic in adapter
With DOP Adapter
- Not imported here (zero dependency)
- Adapters work on output objects
- Separate bridge in
obix-jsx-integration
Constraints (Non-Negotiable)
✅ Pure function — no side effects
✅ No DOM access — no document, window
✅ No framework imports — zero dependencies
✅ Immutable output — never mutates inputs
✅ Type-safe — all generics properly bound
✅ XSS-safe — escapes HTML in strings
Performance
| Operation | Time |
|-----------|------|
| h() call | <1ms |
| Render 100 components | <5ms |
| Compile JSX | Build-time (not runtime) |
| Bundle size | 3-5 KB minified |
Browser Support
| Browser | Version | |---------|---------| | Chrome | 90+ | | Firefox | 88+ | | Safari | 14+ | | Edge | 90+ | | Node.js (SSR) | 18+ |
Related Packages
@obinexusltd/obix-jsx-components— 30 component factories@obinexusltd/obix-jsx-integration— Paradigm adapters@obinexusltd/obix-component-runtime— Core runtime
License
MIT © 2026 Nnamdi Okpalan / OBINexus Computing
