npm package: @komalioruganti/feature-flag-component
Description: A React component library for feature flag management with Can/Feature components
Latest version: 1.0.0

# Feature Flag Component Library

A powerful React component library for feature flags and permission-based rendering using Zustand for state management.

## Features

- **Feature Component**: Declarative feature flag rendering with `Feature` component
- **Can Component**: Permission-based rendering with `Can` component
- **Flexible API**: Support for single, OR (any), and AND (all) logic
- **Type-Safe**: Full TypeScript support with complete type definitions
- **Zustand Store**: Efficient state management with minimal boilerplate
- **Lightweight**: Minimal dependencies (React, Zustand)

## Installation

```bash
npm install @myorg/feature-flag-component
# or
yarn add @myorg/feature-flag-component
# or
pnpm add @myorg/feature-flag-component
```

## Quick Start

### Feature Component (Feature Flags)

```tsx
import { Feature, FeatureFlag, useFeatures } from '@myorg/feature-flag-component';

function App() {
  const { setEnabledFeatures } = useFeatures();

  // Initialize features
  useEffect(() => {
    setEnabledFeatures([FeatureFlag.TICKETING, FeatureFlag.BETA_DASHBOARD]);
  }, []);

  return (
    <>
      {/* Single feature check */}
      <Feature is={FeatureFlag.TICKETING}>
        <TicketingModule />
      </Feature>

      {/* String support */}
      <Feature is="beta-dashboard">
        <BetaDashboard />
      </Feature>

      {/* Any of multiple features (OR logic) */}
      <Feature isAny={[FeatureFlag.ASSET_MANAGEMENT, FeatureFlag.VENDOR_MANAGEMENT]}>
        <AssetVendorMenu />
      </Feature>

      {/* All features required (AND logic) */}
      <Feature isAll={[FeatureFlag.TICKETING, FeatureFlag.SERVICE_CATALOG]}>
        <AdvancedTicketing />
      </Feature>

      {/* With fallback */}
      <Feature is={FeatureFlag.PORTAL_CUSTOMIZATION} fallback={<UpgradePrompt />}>
        <PortalCustomizer />
      </Feature>

      {/* Inverse logic - NOT */}
      <Feature is={FeatureFlag.LEGACY_UI} not>
        <NewUI />
      </Feature>
    </>
  );
}
```

### Can Component (Permissions)

```tsx
import { Can, useCan } from '@myorg/feature-flag-component';

function Dashboard() {
  const { setPermissions, defineAbility } = useCan();

  useEffect(() => {
    // Set basic permissions
    setPermissions(['view-dashboard', 'edit-profile']);

    // Define custom ability checker with context
    defineAbility('edit-post', (context) => {
      return context?.userId === context?.postOwnerId;
    });
  }, []);

  return (
    <>
      {/* Simple permission check */}
      <Can ability="edit-profile">
        <EditProfileButton />
      </Can>

      {/* Any of multiple permissions (OR logic) */}
      <Can abilityAny={['edit-posts', 'edit-comments']}>
        <ContentModeration />
      </Can>

      {/* All permissions required (AND logic) */}
      <Can abilityAll={['edit-posts', 'delete-posts']}>
        <AdminPanel />
      </Can>

      {/* With context for custom checks */}
      <Can ability="edit-post" context={{ userId: 1, postOwnerId: 1 }}>
        <EditButton />
      </Can>

      {/* With fallback */}
      <Can ability="delete-users" fallback={<PermissionDenied />}>
        <DeleteUserButton />
      </Can>

      {/* Inverse logic - NOT */}
      <Can ability="is-admin" not>
        <UserDashboard />
      </Can>
    </>
  );
}
```

## API Reference

### Feature Component

```tsx
interface FeatureProps {
  is?: FeatureFlag | string;           // Single feature check
  isAny?: (FeatureFlag | string)[];     // OR logic - any feature
  isAll?: (FeatureFlag | string)[];     // AND logic - all features
  children: ReactNode;                  // Content to render when enabled
  fallback?: ReactNode;                 // Content when disabled (default: null)
  not?: boolean;                        // Invert the check (default: false)
}
```

### Can Component

```tsx
interface CanProps {
  ability?: string;            // Single ability check
  abilityAny?: string[];       // OR logic - any ability
  abilityAll?: string[];       // AND logic - all abilities
  children: ReactNode;         // Content to render when allowed
  fallback?: ReactNode;        // Content when denied (default: null)
  context?: any;               // Context for ability checker
  not?: boolean;               // Invert the check (default: false)
}
```

### useFeatures Hook

```tsx
const {
  enabledFeatures,      // Set<string> of enabled features
  hasFeature,           // (feature: string | FeatureFlag) => boolean
  hasAnyFeature,        // (features: (string | FeatureFlag)[]) => boolean
  hasAllFeatures,       // (features: (string | FeatureFlag)[]) => boolean
  setEnabledFeatures,   // (features: (string | FeatureFlag)[]) => void
  enableFeature,        // (feature: string | FeatureFlag) => void
  disableFeature,       // (feature: string | FeatureFlag) => void
  toggleFeature,        // (feature: string | FeatureFlag) => void
} = useFeatures();
```

### useCan Hook

```tsx
const {
  permissions,        // Set<string> of granted permissions
  abilities,          // Map<string, (context?) => boolean>
  can,                // (ability: string, resource?: string, context?: any) => boolean
  setPermissions,     // (permissions: string[]) => void
  addPermission,      // (permission: string) => void
  removePermission,   // (permission: string) => void
  defineAbility,      // (ability: string, checker: (context?) => boolean) => void
} = useCan();
```

### FeatureFlag Enum

```tsx
export enum FeatureFlag {
  TICKETING = 'ticketing',
  ASSET_MANAGEMENT = 'asset-management',
  VENDOR_MANAGEMENT = 'vendor-management',
  SERVICE_CATALOG = 'service-catalog',
  PORTAL_CUSTOMIZATION = 'portal-customization',
  BETA_DASHBOARD = 'beta-dashboard',
}
```

## Exports

### Direct Exports
```tsx
import {
  Feature,
  Can,
  useFeatures,
  useCan,
  useFeaturesStore,
  useCanStore,
  FeatureFlag,
} from '@myorg/feature-flag-component';
```

### Components Only
```tsx
import { Feature, Can } from '@myorg/feature-flag-component/components';
```

### Hooks Only
```tsx
import { useFeatures, useCan } from '@myorg/feature-flag-component/hooks';
```

## State Persistence

To persist feature flags or permissions across sessions, integrate with your storage solution:

```tsx
import { useFeatures } from '@myorg/feature-flag-component';

function App() {
  const { setEnabledFeatures } = useFeatures();

  useEffect(() => {
    // Load from localStorage
    const saved = localStorage.getItem('features');
    if (saved) {
      setEnabledFeatures(JSON.parse(saved));
    }
  }, []);
}
```

## Best Practices

1. **Initialize on App Load**: Set features/permissions in your root component
2. **Use Enums**: Prefer `FeatureFlag` enum over strings for type safety
3. **Context for Complex Logic**: Use `context` prop in `Can` for dynamic permission checks
4. **Fallback Content**: Always provide fallback UI for disabled features
5. **Separate Concerns**: Use `Feature` for product features, `Can` for permissions

## License

MIT

## Contributing

Contributions are welcome! Please feel free to submit a Pull Request.