1.0.0 • Published 1 month ago

@shield-acl/react v1.0.0

Weekly downloads
-
License
MIT
Repository
github
Last release
1 month ago

@shield-acl/react

Características

  • 🎨 Componentes Declarativos: Can, Cannot, CanAny, CanAll para renderização condicional
  • 🪝 Hooks Modernos: useCan, usePermissions, useACL e muitos outros
  • Performance Otimizada: Memoização inteligente e re-renders mínimos
  • 🎯 TypeScript First: Totalmente tipado com IntelliSense completo
  • 🔄 React 19 Ready: Compatível com React 16.8+ até React 19
  • 🧩 Extensível: Sistema de componentes e hooks customizáveis

Instalação

npm install @shield-acl/react @shield-acl/core
# ou
yarn add @shield-acl/react @shield-acl/core
# ou
pnpm add @shield-acl/react @shield-acl/core

Uso Rápido

1. Setup do Provider

import { ACL } from '@shield-acl/core'
import { ACLProvider } from '@shield-acl/react'

// Criar instância do ACL
const acl = new ACL()

// Definir roles
acl.defineRole({
  name: 'admin',
  permissions: [{ action: '*', resource: '*' }]
})

acl.defineRole({
  name: 'user',
  permissions: [
    { action: 'read', resource: 'posts' },
    { action: 'create', resource: 'posts' }
  ]
})

// Wrap sua aplicação
function App() {
  const [user] = useState({
    id: 1,
    roles: ['user']
  })

  return (
    <ACLProvider acl={acl} user={user}>
      <YourApp />
    </ACLProvider>
  )
}

2. Componentes de Renderização Condicional

import { Can, Cannot, CanAny, CanAll } from '@shield-acl/react'

function PostList() {
  return (
    <div>
      {/* Renderiza apenas se pode ler posts */}
      <Can action="read" resource="posts">
        <PostGrid />
      </Can>

      {/* Renderiza se NÃO pode deletar */}
      <Cannot action="delete" resource="posts">
        <p>Você não tem permissão para deletar posts</p>
      </Cannot>

      {/* Renderiza se tem QUALQUER uma das permissões */}
      <CanAny permissions={[
        { action: 'create', resource: 'posts' },
        { action: 'edit', resource: 'posts' }
      ]}>
        <EditButton />
      </CanAny>

      {/* Renderiza se tem TODAS as permissões */}
      <CanAll permissions={[
        { action: 'read', resource: 'users' },
        { action: 'manage', resource: 'roles' }
      ]}>
        <AdminPanel />
      </CanAll>
    </div>
  )
}

3. Hooks

import { useCan, usePermissions, useACL } from '@shield-acl/react'

function PostEditor({ post }) {
  // Hook básico
  const canEdit = useCan('edit', 'posts', {
    resource: { authorId: post.authorId }
  })

  // Múltiplas permissões
  const permissions = usePermissions()
  const canModerate = permissions.some(p => 
    p.action === 'moderate' && p.resource === 'posts'
  )

  // Acesso direto ao ACL
  const { engine, user } = useACL()

  if (!canEdit) {
    return <p>Sem permissão para editar</p>
  }

  return <Editor post={post} />
}

API Completa

Componentes

<Can>

Renderiza children apenas se o usuário tem a permissão.

<Can 
  action="edit" 
  resource="posts" 
  context={{ authorId: userId }}
  fallback={<NoPermission />}
>
  <EditForm />
</Can>

<Cannot>

Renderiza children apenas se o usuário NÃO tem a permissão.

<Cannot action="delete" resource="posts">
  <p>Você não pode deletar posts</p>
</Cannot>

<CanAny>

Renderiza se o usuário tem QUALQUER uma das permissões.

<CanAny permissions={[
  { action: 'create', resource: 'posts' },
  { action: 'edit', resource: 'posts' }
]}>
  <ActionButton />
</CanAny>

<CanAll>

Renderiza se o usuário tem TODAS as permissões.

<CanAll permissions={[
  { action: 'read', resource: 'analytics' },
  { action: 'export', resource: 'reports' }
]}>
  <ExportButton />
</CanAll>

Hooks Principais

useCan(action, resource?, context?)

Verifica uma permissão específica.

const canDelete = useCan('delete', 'posts')
const canEdit = useCan('edit', 'posts', { resource: post })

usePermissions()

Retorna todas as permissões do usuário atual.

const permissions = usePermissions()
const isAdmin = permissions.some(p => p.action === '*')

useACL()

Acesso direto ao engine ACL e usuário.

const { engine, user, setUser } = useACL()

useEvaluate(action, resource?, context?)

Retorna resultado detalhado da avaliação.

const result = useEvaluate('publish', 'posts')
// { allowed: true, reason: 'Matched role permission', matchedRule: {...} }

Hooks Avançados

useCanMultiple(permissions)

Verifica múltiplas permissões de uma vez.

const results = useCanMultiple([
  { action: 'read', resource: 'posts' },
  { action: 'create', resource: 'comments' }
])
// { 'read:posts': true, 'create:comments': false }

useCanAny(permissions)

Verifica se tem QUALQUER uma das permissões.

const canEditContent = useCanAny([
  { action: 'edit', resource: 'posts' },
  { action: 'edit', resource: 'pages' }
])

useCanAll(permissions)

Verifica se tem TODAS as permissões.

const isFullAdmin = useCanAll([
  { action: 'manage', resource: 'users' },
  { action: 'manage', resource: 'roles' }
])

useRoleHierarchy()

Obtém a hierarquia completa de roles do usuário.

const hierarchy = useRoleHierarchy()
// ['user', 'moderator', 'admin']

usePermissionChange(callback, dependencies)

Monitora mudanças nas permissões.

usePermissionChange(() => {
  console.log('Permissões mudaram!')
}, ['posts'])

Componentes Utilitários

HOC withCan

const ProtectedButton = withCan(Button, {
  action: 'delete',
  resource: 'posts',
  fallback: <DisabledButton />
})

PermissionClass

<PermissionClass
  action="publish"
  resource="posts"
  className="can-publish"
  deniedClassName="cannot-publish"
>
  <article className="post">...</article>
</PermissionClass>

Performance

Memoização Automática

Todos os hooks são otimizados com memoização:

// Só re-renderiza se o resultado mudar
const canEdit = useCan('edit', 'posts')

// Context é memoizado profundamente
const canDelete = useCan('delete', 'posts', {
  resource: { id: post.id, authorId: post.authorId }
})

Batch Updates

Mudanças no usuário ou permissões são batched:

// Uma única re-renderização
setUser({
  ...user,
  roles: ['admin'],
  permissions: [...]
})

Testes

# Rodar testes
pnpm test

# Coverage
pnpm test:coverage

# Watch mode
pnpm test:watch

Documentação Adicional

Compatibilidade

  • React 16.8+ (precisa de hooks)
  • React 17.x
  • React 18.x
  • React 19.x (totalmente compatível)
  • TypeScript 4.5+

Licença

MIT © Anderson D. Rosa