React UI Components

@devcraft-ts/abac-admin-react-ui

Pre-built UI components for ABAC Policy Administration - batteries included. Built on @devcraft-ts/abac-admin-react which leverages abac-engine for policy evaluation.

Built on abac-engine

These pre-built UI components provide a complete admin interface for managing ABAC policies powered by abac-engine. They use the same hooks and services as the headless React package, with beautiful, accessible UI out of the box. Learn more →

Ready-Made

Production-ready components out of the box

Customizable

Built with Tailwind CSS and Radix UI

Beautiful

Modern, accessible, and responsive design

Theme Support

Full dark/light theme support included

Type-Safe

Full TypeScript support with abac-engine types

✅ When to Use This Package

  • • You want a ready-made admin UI with theme support
  • • You need to get up and running quickly
  • • You're okay with an opinionated design
  • • You want to prototype or build MVPs fast
  • • You need dark/light mode support

❌ When NOT to Use This Package

  • • You need full design control
  • • You have an existing design system
  • • You want to minimize bundle size
  • • Use @devcraft-ts/abac-admin-react instead

Installation

npm install @devcraft-ts/abac-admin-react-ui

# Includes dependencies
# - @devcraft-ts/abac-admin-core
# - @devcraft-ts/abac-admin-react
# - Radix UI components
# - Tailwind CSS utilities

# Peer dependencies
npm install react react-dom

Quick Start

Basic Usage

import { ABACProvider, PolicyList } from '@devcraft-ts/abac-admin-react-ui';
import '@devcraft-ts/abac-admin-react-ui/styles.css';

function App() {
  return (
    <ABACProvider config={{ baseURL: '/api/abac' }}>
      <div className="p-6">
        <PolicyList
          onCreate={() => console.log('Create policy')}
          onEdit={(id) => console.log('Edit policy', id)}
          onDelete={(id) => console.log('Delete policy', id)}
        />
      </div>
    </ABACProvider>
  );
}

With Next.js App Router

"use client";

import { ABACProvider, PolicyList } from '@devcraft-ts/abac-admin-react-ui';
import '@devcraft-ts/abac-admin-react-ui/styles.css';

export default function PoliciesPage() {
  return (
    <ABACProvider config={{ baseURL: '/api/abac' }}>
      <div className="container mx-auto py-8">
        <PolicyList />
      </div>
    </ABACProvider>
  );
}

Components

PolicyList

Displays a table of policies with search, filtering, and CRUD actions.

import { PolicyList } from '@devcraft-ts/abac-admin-react-ui';

<PolicyList
  onCreate={() => setShowCreateDialog(true)}
  onEdit={(id) => router.push(`/policies/${id}/edit`)}
  onDelete={(id) => handleDelete(id)}
  onView={(id) => router.push(`/policies/${id}`)}
/>

// Props:
interface PolicyListProps {
  onCreate?: () => void;              // Called when create button is clicked
  onEdit?: (policyId: string) => void; // Called when edit button is clicked
  onDelete?: (policyId: string) => void; // Called after successful deletion
  onView?: (policyId: string) => void;  // Called when a row is clicked
}

UI Primitives

All primitive UI components are also exported for building custom interfaces.

Button

<Button variant="primary" size="md">
  Click me
</Button>

// Variants: primary, secondary,
//   destructive, outline, ghost
// Sizes: sm, md, lg

Input

<Input
  label="Policy ID"
  placeholder="Enter ID"
  error={errors.policyId}
  helperText="Unique identifier"
  required
/>

Badge

<Badge variant="success">Active</Badge>
<Badge variant="error">Inactive</Badge>
<Badge variant="info">v1.0.0</Badge>

// Variants: default, success,
//   error, warning, info

Card

<Card>
  <CardHeader>
    <CardTitle>Title</CardTitle>
  </CardHeader>
  <CardContent>
    Content here
  </CardContent>
</Card>

Dialog

import {
  Dialog,
  DialogTrigger,
  DialogContent,
  DialogHeader,
  DialogTitle,
  DialogDescription,
  DialogFooter
} from '@devcraft-ts/abac-admin-react-ui';

<Dialog open={isOpen} onOpenChange={setIsOpen}>
  <DialogTrigger asChild>
    <Button>Open Dialog</Button>
  </DialogTrigger>
  <DialogContent>
    <DialogHeader>
      <DialogTitle>Create Policy</DialogTitle>
      <DialogDescription>
        Fill in the details to create a new policy.
      </DialogDescription>
    </DialogHeader>
    {/* Form content */}
    <DialogFooter>
      <Button variant="outline" onClick={() => setIsOpen(false)}>
        Cancel
      </Button>
      <Button onClick={handleSubmit}>Create</Button>
    </DialogFooter>
  </DialogContent>
</Dialog>

Styling & Theming

Using the Default Theme

Import the CSS file in your app to use the default theme.

// app/layout.tsx or _app.tsx
import '@devcraft-ts/abac-admin-react-ui/styles.css';

Customizing the Theme

Override CSS variables to customize colors and styling.

/* custom-theme.css */
:root {
  /* Primary color */
  --primary: 221.2 83.2% 53.3%;
  --primary-foreground: 210 40% 98%;

  /* Secondary color */
  --secondary: 210 40% 96.1%;
  --secondary-foreground: 222.2 47.4% 11.2%;

  /* Destructive (error) color */
  --destructive: 0 84.2% 60.2%;
  --destructive-foreground: 210 40% 98%;

  /* Border radius */
  --radius: 0.5rem;
}

/* Dark mode */
.dark {
  --primary: 217.2 91.2% 59.8%;
  --primary-foreground: 222.2 47.4% 11.2%;
  /* ... other dark mode variables */
}

Using with Your Own Tailwind Config

// tailwind.config.js
module.exports = {
  content: [
    './src/**/*.{js,ts,jsx,tsx}',
    './node_modules/@devcraft-ts/abac-admin-react-ui/dist/**/*.js',
  ],
  // ... rest of your config
}

Utilities

Formatting Utilities

import {
  formatDate,
  truncate,
  getEffectColor,
  getStatusColor,
  cn
} from '@devcraft-ts/abac-admin-react-ui';

// Format dates
formatDate(new Date()); // "Jan 1, 2024, 12:00 PM"

// Truncate strings
truncate("Very long text here...", 20); // "Very long text he..."

// Get badge colors
getEffectColor("PERMIT"); // "abac-badge-success"
getStatusColor(true); // "abac-badge-success"

// className utility
<div className={cn(
  'base-class',
  isActive && 'active-class',
  'another-class'
)} />

Complete Example

Full Policy Management Page

"use client";

import { useState } from 'react';
import {
  ABACProvider,
  PolicyList,
  Dialog,
  DialogContent,
  DialogHeader,
  DialogTitle,
  Button
} from '@devcraft-ts/abac-admin-react-ui';
import '@devcraft-ts/abac-admin-react-ui/styles.css';

export default function PoliciesPage() {
  const [showCreate, setShowCreate] = useState(false);
  const [selectedPolicy, setSelectedPolicy] = useState<string | null>(null);

  return (
    <ABACProvider config={{ baseURL: '/api/abac' }}>
      <div className="container mx-auto py-8">
        <div className="mb-6">
          <h1 className="text-3xl font-bold text-gray-900 dark:text-white">
            Policies
          </h1>
          <p className="text-gray-600 dark:text-gray-400 mt-2">
            Manage your ABAC policies
          </p>
        </div>

        <PolicyList
          onCreate={() => setShowCreate(true)}
          onEdit={(id) => setSelectedPolicy(id)}
          onView={(id) => console.log('View policy', id)}
        />

        <Dialog open={showCreate} onOpenChange={setShowCreate}>
          <DialogContent>
            <DialogHeader>
              <DialogTitle>Create New Policy</DialogTitle>
            </DialogHeader>
            {/* Your create form here */}
            <Button onClick={() => setShowCreate(false)}>
              Create Policy
            </Button>
          </DialogContent>
        </Dialog>
      </div>
    </ABACProvider>
  );
}

Best Practices

Use with ABACProvider

Always wrap your components in ABACProvider for proper state management.

Import CSS Once

Import the CSS file at the root of your app to ensure consistent styling.

Handle Actions

Provide callbacks for user actions to integrate with your app's routing and state.

Customize Thoughtfully

Override CSS variables instead of completely replacing styles for easier maintenance.

Next Steps