@emporix/component-library
v1.4.0
Published
A React component library for Emporix projects
Readme
Emporix Component Library
A modern React component library built with TypeScript, Vite, and SCSS modules.
Features
- 🚀 Modern Stack: Built with Vite, TypeScript, and React 18
- 🎨 Styled Components: SCSS modules for component styling
- 📚 Storybook: Interactive component documentation
- 🧪 Testing: Comprehensive test suite with Vitest and React Testing Library
- 📦 Library Build: Optimized for npm package distribution
- 🔄 CI/CD: Automated testing and publishing pipeline
- 🎨 CSS Variables: Global theming system with CSS custom properties
Quick Start
Installation
npm install @emporix/component-libraryUsage
Important: Import the library styles in your app so component layout and appearance stay consistent. If you skip this step, components may be unstyled or layout may break.
Method 1: Import styles in your main CSS file (Recommended)
/* In your main CSS file (e.g., index.css, App.css) */
@import '@emporix/component-library/styles';import { PrimaryButton } from '@emporix/component-library'
const MyComponent = () => {
return (
<PrimaryButton onClick={() => console.log('Clicked!')}>
Click me
</PrimaryButton>
)
}Method 2: Import styles in your main JavaScript/TypeScript file
import { PrimaryButton } from '@emporix/component-library'
import '@emporix/component-library/styles'
const MyComponent = () => {
return (
<PrimaryButton onClick={() => console.log('Clicked!')}>
Click me
</PrimaryButton>
)
}Method 3: Copy CSS file manually (Fallback)
If the above methods don't work, copy the CSS file from node_modules/@emporix/component-library/dist/style.css to your project and import it directly.
Components
PrimaryButton
A simple, focused button component for primary actions.
import { PrimaryButton } from '@emporix/component-library'
// Basic usage
<PrimaryButton>Click me</PrimaryButton>
// With disabled state
<PrimaryButton disabled>Disabled Button</PrimaryButton>
// With click handler
<PrimaryButton onClick={() => alert('Confirmed!')}>
Confirm Action
</PrimaryButton>Props
| Prop | Type | Default | Description | | ----------- | ---------- | ------- | -------------------------- | | children | ReactNode | - | Button content | | disabled | boolean | false | Whether button is disabled | | onClick | () => void | - | Click handler | | className | string | - | Additional CSS class | | data-testid | string | - | Test ID for testing |
InputText
A text input with optional label and tooltip. Hover and focus styles match the Dropdown component.
import { InputText } from '@emporix/component-library'
// With label and info tooltip
<InputText
label="Id"
tooltip="Unique identifier for this record"
placeholder="Enter id"
/>
// Required field
<InputText label="Name" required placeholder="Enter name" />
// Disabled
<InputText label="Id" placeholder="Enter id" disabled />Props
| Prop | Type | Default | Description |
| ----------- | --------- | ------- | -------------------------------------------- |
| label | ReactNode | - | Label text above the input |
| tooltip | string | - | If set, shows info icon with this tooltip |
| required | boolean | false | Shows asterisk on label |
| inputId | string | - | id for the input (for label association) |
| disabled | boolean | false | Whether the input is disabled |
| className | string | - | Additional CSS class for the root |
| data-testid | string | - | Test ID for root and input (suffix -input) |
All standard HTML input attributes (placeholder, value, onChange, etc.) are supported.
SelectButton
Choose single or multiple options using buttons. API inspired by PrimeReact SelectButton. Selected state uses project primary colors.
import { SelectButton } from '@emporix/component-library'
const options = [
{ label: 'Off', value: 'off' },
{ label: 'On', value: 'on' },
]
// Single selection
<SelectButton
value={value}
onChange={(e) => setValue(e.value)}
options={options}
/>
// Multiple selection
<SelectButton
value={selected}
onChange={(e) => setSelected(e.value)}
options={options}
multiple
/>Props
| Prop | Type | Default | Description | | -------------- | ------------------------ | ------- | --------------------------------------- | | value | unknown | - | Selected value (or array when multiple) | | onChange | (e: ChangeEvent) => void | - | Callback when selection changes | | options | T[] | - | Array of options | | optionLabel | string | "label" | Property name for option label | | optionValue | string | "value" | Property name for option value | | optionDisabled | string | - | Property name for disabled flag | | multiple | boolean | false | Allow multiple selection | | itemTemplate | (option) => ReactNode | - | Custom render for each option | | disabled | boolean | false | Disable the whole component | | invalid | boolean | false | Validation invalid state | | className | string | - | Additional CSS class | | data-testid | string | - | Test ID for root and option buttons |
Tabs
A flexible tabs component for organizing content into multiple panels.
import { Tabs, TabItem } from '@emporix/component-library'
const tabs: TabItem[] = [
{
id: 'tab1',
label: 'First Tab',
content: <div>First tab content</div>,
},
{
id: 'tab2',
label: 'Second Tab',
content: <div>Second tab content</div>,
},
]
// Basic usage
<Tabs
tabs={tabs}
activeTabId="tab1"
onTabChange={(tabId) => setActiveTab(tabId)}
/>
// With custom styling and test ID
<Tabs
tabs={tabs}
activeTabId="tab1"
onTabChange={(tabId) => setActiveTab(tabId)}
className="custom-tabs"
data-testid="my-tabs"
/>Props
| Prop | Type | Default | Description | | ----------- | ----------------------- | ------- | ------------------------------ | | tabs | TabItem[] | - | Array of tab items | | activeTabId | string | - | ID of the currently active tab | | onTabChange | (tabId: string) => void | - | Callback when tab is changed | | className | string | - | Additional CSS class | | data-testid | string | - | Test ID for testing |
TabItem Interface
| Prop | Type | Description | | ------- | --------- | ------------------------------ | | id | string | Unique identifier for the tab | | label | string | Display label for the tab | | content | ReactNode | Content to display when active |
Theming with CSS Variables
The component library uses CSS variables for easy theming. You can customize the appearance by overriding these variables:
:root {
--color-primary: #your-primary-color;
--color-primary-hover: #your-primary-hover-color;
--border-radius-md: 0.5rem;
--font-size-lg: 1.2rem;
/* ... other variables */
}Available CSS Variables
The component library provides a minimal set of CSS variables that are actually used in the codebase. These variables are primarily used for the showcase page styling and can be customized for theming.
Colors
--color-primary: #007bff;
--color-primary-hover: #0056b3;
--color-dark: #343a40;Text Colors
--color-text-primary: #212529;
--color-text-secondary: #6c757d;Background Colors
--color-bg-primary: #ffffff;
--color-bg-secondary: #f8f9fa;Border Colors
--color-border-light: #e9ecef;Focus Ring
Reusable focus outline for inputs, dropdowns, SelectButton, etc. Override to change focus appearance globally.
--focus-ring-box-shadow: 0 0 0 2px rgba(38, 101, 183, 0.35);Spacing
--spacing-sm: 0.5rem; /* 8px */
--spacing-md: 1rem; /* 16px */
--spacing-lg: 1.5rem; /* 24px */
--spacing-xl: 3rem; /* 48px */Border Radius
--border-radius-sm: 0.25rem; /* 4px */
--border-radius-md: 0.375rem; /* 6px */
--border-radius-lg: 0.5rem; /* 8px */Typography
Font Sizes:
--font-size-sm: 0.875rem; /* 14px */
--font-size-base: 0.875rem; /* 14px */
--font-size-lg: 1.125rem; /* 18px */Font Weights:
--font-weight-normal: 400;
--font-weight-medium: 500;
--font-weight-semibold: 600;
--font-weight-bold: 700;Line Height:
--line-height-base: 1rem;Theming Examples
Basic Theming
:root {
--color-primary: #your-brand-color;
--color-primary-hover: #your-brand-hover-color;
--border-radius-md: 0.5rem;
--font-size-lg: 1.2rem;
}Dark Theme
:root {
--color-bg-primary: #1a1a1a;
--color-bg-secondary: #2d2d2d;
--color-text-primary: #ffffff;
--color-text-secondary: #cccccc;
--color-border-light: #404040;
}Custom Component Styling
.my-custom-component {
padding: var(--spacing-md);
border-radius: var(--border-radius-lg);
background-color: var(--color-bg-primary);
color: var(--color-text-primary);
border: 1px solid var(--color-border-light);
}Development
Prerequisites
- Node.js 18+
- npm or yarn
Setup
# Clone the repository
git clone <repository-url>
cd component-library
# Install dependencies
npm install
# Start development server
npm run dev
# Start Storybook
npm run storybookAvailable Scripts
npm run dev- Start development server with showcasenpm run build- Build the development versionnpm run build:lib- Build the library for distributionnpm run test- Run testsnpm run test:ui- Run tests with UInpm run test:coverage- Run tests with coveragenpm run storybook- Start Storybooknpm run build-storybook- Build Storybooknpm run lint- Run ESLintnpm run lint:fix- Fix ESLint issuesnpm run type-check- Run TypeScript type checkingnpm run format- Format code with Prettiernpm run format:check- Check code formatting
Testing
The library includes comprehensive tests using Vitest and React Testing Library.
# Run all tests
npm test
# Run tests with coverage
npm run test:coverage
# Run tests with UI
npm run test:uiStorybook
Interactive component documentation is available in Storybook.
# Start Storybook
npm run storybook
# Build Storybook
npm run build-storybookBuilding for Distribution
The library is built using Vite with optimized settings for npm distribution.
# Build the library
npm run build:libThe build output includes:
- ES modules (
index.es.js) - UMD bundle (
index.umd.js) - TypeScript declarations (
index.d.ts) - CSS styles (
styles.css)
Code Formatting
This project uses Prettier for consistent code formatting. The configuration is defined in .prettierrc.
# Format all files
npm run format
# Check if files are formatted correctly
npm run format:checkThe project also includes pre-commit hooks that automatically format staged files before commits.
Contributing
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add some amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
Development Guidelines
- Follow TypeScript best practices
- Write tests for new components
- Add Storybook stories for components
- Follow the existing code style
- Update documentation as needed
- Use arrow functions for React components (enforced by ESLint)
- Avoid using
React.FCtype annotation (redundant with modern TypeScript) - Use CSS variables for all styling values
- Follow the established naming conventions for CSS classes
Troubleshooting
Import Issues
If you encounter import errors like "Failed to resolve entry for package", ensure:
- The package is properly installed:
npm install @emporix/component-library - You're using the correct import syntax:
import { PrimaryButton } from '@emporix/component-library' import '@emporix/component-library/styles' - Your bundler supports ES modules and the package.json exports field
Styling Issues
If the PrimaryButton component appears unstyled or you get "styles not found" errors:
Try Method 1 (Recommended): Import styles in your main CSS file:
@import '@emporix/component-library/styles';Try Method 2: Import styles in your main JavaScript/TypeScript file:
import '@emporix/component-library/styles'If both methods fail: Copy the CSS file manually:
- Copy
node_modules/@emporix/component-library/dist/style.cssto your project - Import it in your main CSS file:
@import './path/to/style.css';
- Copy
Check your bundler configuration: Ensure your bundler (Vite, Webpack, etc.) is configured to handle CSS imports from node_modules
Verify the CSS classes: The component uses SCSS modules with hashed class names (e.g.,
_primaryButton_1d0ha_1,_primaryButtonDisabled_1d0ha_53) and CSS variables for theming
TypeScript Issues
If TypeScript can't find types, make sure:
- The
@types/reactpackage is installed - Your
tsconfig.jsonincludes the library innode_modules
Bundler-Specific Notes
Vite
All methods should work with Vite. Method 1 (CSS import) is recommended.
Webpack
Method 1 and Method 2 should work. If you encounter issues, try Method 3.
Create React App
Method 1 and Method 2 should work. If you encounter issues, try Method 3.
Next.js
Method 1 (CSS import) is recommended. Import the CSS in your _app.tsx or _app.js file.
License
MIT License - see LICENSE file for details.
Support
For support and questions, please open an issue in the repository.
