@ereiblein/cl-protoapp-components-react
v1.2.3
Published
ClassLink Protoapp Components Library - Reusable React components
Maintainers
Readme
ClassLink Protoapp Components - React
A React component library for ClassLink applications, converted from the Angular version. Built with TypeScript, Vite, and CSS Modules.
Installation
npm install @ereiblein/cl-protoapp-components-reactRequirements
This library requires the following peer dependencies:
- React ^18.0.0
- React DOM ^18.0.0
You also need to include the ClassLink CSS Framework and Font Awesome in your application:
<!-- Add to your index.html -->
<link rel="stylesheet" href="https://cdn.classlink.com/production/framework/stylesheets/clsheet-basic.css" />
<link rel="stylesheet" href="https://cdn.classlink.com/production/framework/stylesheets/clsheet-material.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.1/css/all.min.css" />Usage
Import Components
import {
Field,
Dropdown,
Table,
PageHeader,
NavMenu,
NavMenuClassic
} from '@erreib/cl-protoapp-components';
import '@erreib/cl-protoapp-components/style.css';Interactive Examples
For interactive component examples and documentation, run Storybook locally:
npm run storybookStorybook provides live examples of all components with their complete API documentation and interactive controls.
Basic Examples
Field Component
import { useState } from 'react';
import { Field } from '@erreib/cl-protoapp-components';
function MyComponent() {
const [value, setValue] = useState('');
return (
<Field
value={value}
onChange={setValue}
icon="fa-search"
placeholder="Search..."
/>
);
}Dropdown Component
import { useState } from 'react';
import { Dropdown, DropdownOption } from '@erreib/cl-protoapp-components';
function MyComponent() {
const [value, setValue] = useState('');
const options: DropdownOption[] = [
{ label: 'Option 1', value: 'opt1' },
{ label: 'Option 2', value: 'opt2' },
{ label: 'Option 3', value: 'opt3' }
];
return (
<Dropdown
value={value}
onChange={setValue}
options={options}
placeholder="Select an option..."
/>
);
}Table Component
import { Table, TableColumn, DropdownOption } from '@erreib/cl-protoapp-components';
function MyComponent() {
const data = [
{ name: 'John Doe', status: 'active', age: 30 },
{ name: 'Jane Smith', status: 'inactive', age: 25 }
];
const statusOptions: DropdownOption[] = [
{ label: 'Active', value: 'active' },
{ label: 'Inactive', value: 'inactive' }
];
const columns: TableColumn[] = [
{ key: 'name', label: 'Name', filterType: 'text', sortable: true },
{ key: 'status', label: 'Status', filterType: 'dropdown', filterOptions: statusOptions, sortable: true },
{ key: 'age', label: 'Age', sortable: true }
];
return (
<Table
columns={columns}
data={data}
pageSize={10}
/>
);
}PageHeader Component
import { PageHeader } from '@erreib/cl-protoapp-components';
import { useNavigate } from 'react-router-dom';
function MyPage() {
const navigate = useNavigate();
return (
<PageHeader
title="Applications"
icon="fa-th"
parentTitle="Dashboard"
parentRoute="/dashboard"
onNavigate={(route) => navigate(route)}
/>
);
}With Subtitle:
<PageHeader
title="Applications"
icon="fa-th"
parentTitle="Dashboard"
parentRoute="/dashboard"
subTitle="All Applications"
onNavigate={(route) => navigate(route)}
/>Without Navigation:
<PageHeader
title="Dashboard"
icon="fa-home"
/>NavMenu Component (Vertical Sidebar)
import { NavMenu, NavMenuItem } from '@erreib/cl-protoapp-components';
import { useNavigate } from 'react-router-dom';
function MyApp() {
const navigate = useNavigate();
const menuItems: NavMenuItem[] = [
{ label: 'Dashboard', icon: 'fa-home', route: '/dashboard' },
{ label: 'Applications', icon: 'fa-th', route: '/applications', badge: '5' },
{
label: 'Settings',
icon: 'fa-cog',
route: '/settings',
hasDropdown: true,
subItems: [
{ label: 'General', route: '/settings/general' },
{ label: 'Security', route: '/settings/security' }
]
}
];
return (
<NavMenu
menuItems={menuItems}
userProfile={{ name: 'John Doe', role: 'Admin' }}
logoPath="/logo.svg"
logoText="My App"
logoRoute="/"
activeRoute={window.location.pathname}
onNavigate={(route) => navigate(route)}
/>
);
}NavMenu CSS Variables for Main Content Spacing
The NavMenu component exposes CSS custom properties that automatically update based on the menu's collapsed state. Use these variables to adjust your main content area spacing without manually calculating widths.
Available CSS Variables:
--nav-menu-width: Current width (280px when expanded, 70px when collapsed)--nav-menu-width-expanded: Always 280px--nav-menu-width-collapsed: Always 70px
Example Usage:
/* In your application's CSS */
.main-content {
margin-left: var(--nav-menu-width, 280px);
transition: margin-left 0.3s ease;
}
/* Or using padding */
.page-container {
padding-left: var(--nav-menu-width, 280px);
transition: padding-left 0.3s ease;
}
/* For specific states */
.content-expanded {
margin-left: var(--nav-menu-width-expanded, 280px);
}
.content-collapsed {
margin-left: var(--nav-menu-width-collapsed, 70px);
}React/JSX Example:
function App() {
return (
<>
<NavMenu {...navMenuProps} />
<main style={{ marginLeft: 'var(--nav-menu-width, 280px)', transition: 'margin-left 0.3s ease' }}>
<h1>Main Content</h1>
<p>This content automatically adjusts when the menu collapses or expands.</p>
</main>
</>
);
}The CSS variables are set on the <nav> element, so they're available throughout your application. The transition will smoothly animate your main content when the menu collapses or expands.
NavMenuClassic Component (Horizontal Top Bar)
import { NavMenuClassic, NavMenuItem } from '@erreib/cl-protoapp-components';
import { useNavigate } from 'react-router-dom';
function MyApp() {
const navigate = useNavigate();
const menuItems: NavMenuItem[] = [
{ label: 'Home', icon: 'fa-home', route: '/' },
{ label: 'About', icon: 'fa-info-circle', route: '/about' },
{
label: 'Services',
icon: 'fa-briefcase',
route: '/services',
hasDropdown: true,
subItems: [
{ label: 'Consulting', route: '/services/consulting' },
{ label: 'Development', route: '/services/development' }
]
}
];
const userDropdownItems = [
{ label: 'Profile', route: '/profile' },
{ label: 'Settings', route: '/settings' },
{ label: 'Logout', route: '/logout' }
];
return (
<NavMenuClassic
menuItems={menuItems}
userDropdownItems={userDropdownItems}
logoPath="/logo-white.svg"
logoText="My App"
logoRoute="/"
activeRoute={window.location.pathname}
onNavigate={(route) => navigate(route)}
onUserAction={(route) => navigate(route)}
/>
);
}Component Props
Field
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| value | string | '' | The current input value |
| onChange | (value: string) => void | - | Callback fired when value changes |
| icon | string | - | Font Awesome icon class (without 'fas' prefix) |
| placeholder | string | - | Placeholder text |
| disabled | boolean | false | Whether the field is disabled |
| className | string | - | Additional CSS classes |
Dropdown
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| value | string | '' | The currently selected value |
| onChange | (value: string) => void | - | Callback fired when selection changes |
| options | DropdownOption[] | [] | Array of options to display |
| icon | string | - | Font Awesome icon class |
| placeholder | string | 'Select...' | Placeholder text |
| disabled | boolean | false | Whether the dropdown is disabled |
| className | string | - | Additional CSS classes |
Table
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| columns | TableColumn[] | [] | Array of column definitions |
| data | any[] | [] | Array of data objects to display |
| pageSize | number | 10 | Number of items per page (0 to disable pagination) |
| externalFiltering | boolean | false | Whether filtering should be handled externally |
| externalSorting | boolean | false | Whether sorting should be handled externally |
| onFilterChange | (filters: Record<string, string>) => void | - | Callback fired when filter values change |
| onSortChange | (sortState: SortState) => void | - | Callback fired when sort state changes |
| onPageChange | (page: number) => void | - | Callback fired when the current page changes |
| className | string | - | Additional CSS classes |
PageHeader
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| title | string | - | The main page title (required) |
| icon | string | 'fa-cloud' | Font Awesome icon class (e.g., 'fa-home', 'fa-cog') |
| parentTitle | string | - | Parent page title for breadcrumb navigation |
| parentRoute | string | - | Route path to the parent page |
| subTitle | string | - | Subtitle shown in breadcrumb (overrides title if provided) |
| onNavigate | (route: string) => void | - | Callback when breadcrumb link is clicked |
| className | string | - | Additional CSS classes |
NavMenu
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| menuItems | NavMenuItem[] | [] | Array of navigation menu items |
| userProfile | UserProfile | - | User profile information |
| logoPath | string | '/cl-logo.svg' | Path to the logo image |
| logoAlt | string | 'ClassLink' | Alt text for the logo |
| logoText | string | 'ClassLink' | Text displayed next to the logo |
| logoRoute | string | - | Route for the logo link (optional) |
| activeRoute | string | '' | Current active route |
| onNavigate | (route: string) => void | - | Callback fired when a navigation item is clicked |
| LinkComponent | React.ComponentType<any> | - | Optional custom Link component (e.g., React Router Link) |
| className | string | - | Additional CSS classes |
NavMenuClassic
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| menuItems | NavMenuItem[] | - | Array of navigation menu items (uses defaults if not provided) |
| logoPath | string | '/images/cl-logo-white.svg' | Path to the logo image |
| logoAlt | string | 'Logo' | Alt text for the logo |
| logoText | string | 'Partner Portal' | Text displayed next to the logo |
| logoRoute | string | - | Route for the logo link (optional) |
| userIcon | string | 'fa-user' | Font Awesome icon class for the user icon |
| userDropdownItems | NavSubMenuItem[] | - | Optional dropdown items for the user icon |
| activeRoute | string | '' | Current active route |
| onNavigate | (route: string) => void | - | Callback fired when a navigation item is clicked |
| onUserAction | (route: string) => void | - | Callback fired when a user dropdown item is clicked |
| LinkComponent | React.ComponentType<any> | - | Optional custom Link component |
| className | string | - | Additional CSS classes |
Development
Build Library
npm run buildStart Storybook
npm run storybookPublishing
Publish to GitLab Private Registry
# Requires GITLAB_NPM_TOKEN environment variable
npm run publish:lib # Patch version (1.0.0 → 1.0.1)
npm run publish:lib:minor # Minor version (1.0.0 → 1.1.0)
npm run publish:lib:major # Major version (1.0.0 → 2.0.0)Publish to Public npm Registry
# Requires authentication with npmjs.org (npm login)
npm run publish:npm # Patch version (1.0.0 → 1.0.1)
npm run publish:npm:minor # Minor version (1.0.0 → 1.1.0)
npm run publish:npm:major # Major version (1.0.0 → 2.0.0)Note: Before publishing to npm, make sure you're logged in:
npm login
# Or if using a token:
npm config set //registry.npmjs.org/:_authToken YOUR_NPM_TOKENLicense
Private package for internal use.
