@owizzo/ozora
v2.0.0
Published
ozora is a React UI library for developing modern and fast business applications. ozora is a product of owizzo GmbH.
Downloads
723
Readme

A React component library by owizzo GmbH – built with TypeScript and TailwindCSS.
Designed to provide reusable, accessible, and customizable UI components.
🚀 Installation
Install the library:
npm install @owizzo/ozora
# or
yarn add @owizzo/ozoraEnsure the consumer project has React and Tailwind installed:
npm install react react-dom
# Tailwind is a peer dependency; install it in the consumer project (devDependencies):
npm install -D tailwindcss@^4 postcss autoprefixer⚠️ Important: Tailwind v4 is a peer dependency
ozora uses Tailwind utility classes (in className) but does not ship a compiled Tailwind stylesheet. The consumer must set up Tailwind in their build pipeline so utilities are generated and not removed by Purge/Content scanning.
✅ Configuring TailwindCSS in the consumer project
To correctly generate CSS for Ozora components, the consumer must include Ozora’s compiled files in Tailwind’s content scanning.
Option A — Using tailwind.config.cjs
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./src/**/*.{js,jsx,ts,tsx}', // consumer app source
'./node_modules/@owizzo/ozora/dist/**/*.{js,jsx,ts,tsx}' // Ozora compiled components
],
theme: { extend: {} },
plugins: [],
}Option B — CSS-first approach
/* src/styles/tailwind.css */
@import "tailwindcss";
/* Import Ozora theme */
@import "@owizzo/ozora/index.css";
@source "../../node_modules/@owizzo/ozora";
:root {
--ozora-primary: #0065b2; /* default blue-500 */
--ozora-secondary: #75bf42; /* default orange-500 */
--ozora-background: #f0f1f2; /* default gray-100 */
--ozora-text: #111827; /* default gray-900 */
}Notes:
- Ensure the path in
@sourceis relative to the CSS file. - Restart Tailwind after modifying config or source to regenerate CSS.
⚡ Usage
import { Button } from '@owizzo/ozora/components';
export default function App() {
return (
<div className="p-4">
<Button label="Click me!" />
</div>
);
}🤖 Agent-Komponenten
Ozora enthält einen Komponentensatz für Agenten-Oberflächen, der am Core-Domain-Architekturkonzept ausgerichtet ist: Run-Ansicht, Freigaben, Tool-Katalog und Zugangsdaten.
import { RunTimeline, RunStatusBadge, RunControls, RunCostSummary } from '@owizzo/ozora';
import { useRunStream } from '@owizzo/ozora/hooks';
export function RunView({ runId }: { runId: string }) {
const { steps, status, currentRequest, totals, connect } = useRunStream({
streamUrl: `/api/runs/${runId}/stream`,
});
useEffect(() => { connect(); }, [connect]);
return (
<>
<div className="flex items-center gap-3">
<RunStatusBadge status={status ?? 'pending'} />
<RunControls
status={status ?? 'pending'}
onPause={() => fetch(`/api/runs/${runId}/pause`, { method: 'POST' })}
onResume={() => fetch(`/api/runs/${runId}/resume`, { method: 'POST' })}
onCancel={() => fetch(`/api/runs/${runId}/cancel`, { method: 'POST' })}
/>
</div>
<RunTimeline steps={steps} showCost />
<RunCostSummary {...totals} compact />
</>
);
}useRunStream faltet den Eventstrom zu Steps zusammen: Text-Deltas werden pro
Step zu einer Nachricht akkumuliert, parallele Tool-Aufrufe behalten über
triggeredByStepId ihren Batch-Bezug, und der Run-Status wird ausschließlich
aus status_change-Events übernommen.
Streaming läuft über den BFF
EventSource kann keine eigenen Header setzen. Der Stream muss deshalb
same-origin über einen Proxy laufen, der die Session prüft und serverseitig
gegen die Agent API weiterleitet:
Browser → /api/runs/{id}/stream (prüft Session-Cookie)
→ GET {CORE_API}/runs/{id}/stream (Service-Token)Ein direkter Aufruf der Core Domain mit Bearer-Token funktioniert nicht.
🧭 Navigation
Ozora ist an keinen Router gebunden. Komponenten mit Navigation (SideBar)
fragen einen Context ab:
import { OzoraNavigationProvider } from '@owizzo/ozora/navigation';
import { useRouter, usePathname } from 'next/navigation';
const router = useRouter();
const pathname = usePathname();
<OzoraNavigationProvider value={{ pathname, navigate: router.push }}>
{children}
</OzoraNavigationProvider>Ohne Provider fällt Ozora auf window.location zurück — das funktioniert,
löst aber einen vollständigen Seitenwechsel aus.
🎨 Theming
Design-Tokens liegen auf zwei Ebenen: --ozora-* sind die Werte, die eine
Anwendung überschreibt, daraus werden die Tailwind-Farben abgeleitet.
:root {
--ozora-primary: #0765AA;
--ozora-secondary: #58A55E;
}Dark Mode wird über [data-ozora-theme="dark"] aktiviert, nicht über
prefers-color-scheme allein — die Anwendung behält die Kontrolle.
Stand: Die semantischen Tokens (
success,warning,danger,info,surface,border) sind vollständig definiert, aber noch nicht in allen Bestandskomponenten verdrahtet. Theming greift derzeit zuverlässig aufprimaryundsecondary.
🧪 Entwicklung
npm run dev # tsup im Watch-Modus
npm run storybook # Storybook auf Port 6006
npm run test # Vitest
npm run test:watch
npm run typecheck # tsc --noEmit
npm run build⬆️ Migration von 1.5
Version 2.0 richtet die Agent-Komponenten am Core-Domain-Vertrag aus und
entfernt die react-router-dom-Abhängigkeit. Details und Umstellungsschritte:
siehe MIGRATION.md.
📜 License
MIT © 2026 owizzo GmbH
