@h-hemant-p/ui
v1.1.1
Published
Alphastry universal React component library — Core CSS, dark/light mode, NPM & Git Submodule distribution
Readme
@alphastry/ui — Shared React Component Library
Universal React components shared across all Alphastry products.
Pure Core CSS · Dark + Light mode · TypeScript · Git Submodule & NPM distribution.
Table of Contents
- Components
- Hooks
- Tech Stack
- Setup in a New Project (Submodule)
- Setup in a New Project (NPM)
- Running / Development
- Usage Examples
- Design Tokens
- Project Structure
- Adding a New Component
Components
| Component | Description | Class Names |
|-----------|-------------|-------------|
| Button | Primary, secondary, ghost, danger variants · loading state · left/right icon slots | .ui-button, .ui-button--* |
| Badge | Status labels — success, warning, danger, info, neutral, accent · dot indicator · dismissible | .ui-badge, .ui-badge--* |
| Spinner | Loading indicator — 5 sizes · overlay/full-screen mode · accessible aria-label | .ui-spinner, .ui-spinner--* |
| Input | Text input — label · error state · helper text · left/right icon slots · fully accessible | .ui-input-* |
| Modal | Dialog overlay — focus trap · scroll lock · keyboard navigation · Modal.Footer sub-component | .ui-modal-* |
| CountryCodeSelect | Searchable dial code dropdown selector with flags and search input | .ui-country-select, .ui-country-select__* |
| SearchableDropdown | Generic searchable option dropdown list with checks and custom labels | .ui-searchable-dropdown, .ui-searchable-dropdown__* |
| Switch | Modern rectangular toggle slide switch replacement for checkbox elements | .ui-switch, .ui-switch__* |
| Tabs | Tab navigation list with active pill state and optional icon slots | .ui-tabs, .ui-tabs__* |
| Card | Structured containment layout block with header, title, actions and body slots | .ui-card, .ui-card__* |
| Avatar | Squircle image/initials renderer with auto local-SVG fallback logic | .ui-avatar, .ui-avatar__* |
| Alert | Banner alerts with success, warning, error, info states and inline close action | .ui-alert, .ui-alert--* |
| Tooltip | Absolute bubble overlays positioned on top, bottom, left, right on hover | .ui-tooltip, .ui-tooltip__* |
| Progress | Quota limit metrics indicator bar with primary, success, warning, danger states | .ui-progress, .ui-progress__* |
| Pagination | Controls footer layout showing page numbers with standard SVG arrows | .ui-pagination, .ui-pagination__* |
| Skeleton | Animated pulsers for rectangles, lines, and circular skeleton placeholders | .ui-skeleton, .ui-skeleton--* |
| Textarea | Multi-line text field — label · helper text · error · fullWidth · fully accessible | .ui-textarea-* |
| Select | Native browser select — custom chevron arrow · label · error · helper · left icon slot | .ui-select-* |
Hooks
| Hook | Description |
|------|-------------|
| useClickOutside | Fires a callback when the user clicks outside a given ref element |
| useDebounce | Debounces a value update after a configurable delay (ms) |
Tech Stack
| Layer | Technology | Version |
|-------|-----------|---------|
| Language | TypeScript | ^5.5 |
| UI Library | React | ≥18.0 (peer dep) |
| Styling | Core CSS (Vanilla CSS) | — |
| CSS Variables | Custom design tokens (tokens.css) | — |
| Bundler | tsup | ^8.5 |
| Package Manager | npm (or pnpm) | — |
Setup in a New Project (Submodule)
If you are importing the library as a Git submodule, follow these steps:
Step 1 — Add as Git Submodule
Run this from the root of your frontend project:
git submodule add https://gitlab.com/alphastry/code-snippets/react-components.git submodules/react-components
git submodule update --init --recursiveStep 2 — Configure Vite Path Alias
In your vite.config.ts:
import path from 'path';
import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react';
export default defineConfig({
plugins: [react()],
resolve: {
alias: {
'@alphastry/ui': path.resolve(__dirname, './submodules/react-components/src/index.ts'),
},
},
});Step 3 — Configure TypeScript Path Mapping
In your tsconfig.json (or tsconfig.app.json):
{
"compilerOptions": {
"paths": {
"@alphastry/ui": ["./submodules/react-components/src/index.ts"],
"@alphastry/ui/*": ["./submodules/react-components/src/*"]
}
}
}Step 4 — Import Design Stylesheet
In your root CSS file (e.g. src/index.css):
/* Simply import the compiled CSS stylesheet once */
@import '../submodules/react-components/dist/index.css';Step 5 — Set the Theme on <html>
The components adapt dynamically to dark and light modes using the data-theme attribute:
// In main.tsx or your theme context:
document.documentElement.setAttribute('data-theme', 'dark');
// or
document.documentElement.setAttribute('data-theme', 'light');Setup in a New Project (NPM)
If you have installed the package from the NPM registry:
Step 1 — Install the package
npm install @h-hemant-p/uiStep 2 — Import the stylesheet
In your root layout or React entry point file (e.g., main.tsx or layout.tsx):
import '@h-hemant-p/ui/dist/index.css';Step 3 — Use the components
import { Button } from '@h-hemant-p/ui';Running / Development
To run typechecks and compile components locally:
# Install development dependencies
npm install
# Build JavaScript bundles (CJS, ESM, Types) and CSS sheets
npm run buildThe output assets will be created in the dist/ directory.
Usage Examples
## Usage Examples
```tsx
import { Button, Badge, Modal, Spinner, Input, CountryCodeSelect, SearchableDropdown, Switch, Tabs, Card, Avatar, Alert, Tooltip, Progress, Pagination, Skeleton, Textarea, Select, useDebounce, useClickOutside } from '@h-hemant-p/ui';
// ── Button ─────────────────────────────────────────────────
<Button variant="primary" size="md" onClick={save}>Save</Button>
<Button variant="danger" loading>Deleting...</Button>
<Button variant="ghost" leftIcon={<PlusIcon />}>Add item</Button>
<Button variant="secondary" rightIcon={<ArrowIcon />}>Next</Button>
// ── Badge ──────────────────────────────────────────────────
<Badge variant="success" dot>Active</Badge>
<Badge variant="danger" onDismiss={() => clearError()}>Error occurred</Badge>
<Badge variant="warning">Pending Review</Badge>
// ── Spinner ────────────────────────────────────────────────
<Spinner size="lg" label="Loading campaigns..." />
<Spinner overlay /> {/* full-screen blocking spinner */}
// ── Input ──────────────────────────────────────────────────
<Input label="Email" type="email" placeholder="[email protected]" />
<Input label="Search" leftIcon={<SearchIcon />} error="This field is required" />
<Input label="Password" type="password" helperText="At least 8 characters" />
// ── Modal ──────────────────────────────────────────────────
<Modal isOpen={open} onClose={() => setOpen(false)} title="Delete Campaign">
<p>This action cannot be undone.</p>
<Modal.Footer>
<Button variant="ghost" onClick={() => setOpen(false)}>Cancel</Button>
<Button variant="danger" onClick={handleDelete}>Delete</Button>
</Modal.Footer>
</Modal>
// ── CountryCodeSelect ──────────────────────────────────────
<CountryCodeSelect value={dialCode} onChange={(val) => setDialCode(val)} />
// ── SearchableDropdown ─────────────────────────────────────
<SearchableDropdown
options={[
{ value: 'session_1', label: 'WhatsBot Main', description: '+919999999999', status: 'connected' },
{ value: 'session_2', label: 'Support Line', description: '+18888888888', status: 'disconnected' }
]}
selectedId={selectedSession}
onChange={(val) => setSelectedSession(val)}
placeholder="-- Choose a session --"
/>
// ── Switch ─────────────────────────────────────────────────
<Switch
checked={warmupMode}
onChange={(val) => setWarmupMode(val)}
label="Warm-up Mode"
description="Gradually throttle message volume limits to avoid ban risks."
/>
// ── Tabs ───────────────────────────────────────────────────
<Tabs
tabs={[
{ id: 'campaigns', label: 'Campaigns' },
{ id: 'team', label: 'Team members' }
]}
activeTabId={activeTab}
onChange={(id) => setActiveTab(id)}
/>
// ── Card ───────────────────────────────────────────────────
<Card
title="Safety Settings"
subtitle="Initiate parameters for automated message warmups"
extra={<Badge variant="accent">Pro Mode</Badge>}
>
<p>Configure details for throttle delays and unsaved number protection logs.</p>
</Card>
// ── Avatar ─────────────────────────────────────────────────
<Avatar src={userPhoto} name="Hemant Prasad" size="md" />
<Avatar name="Support Agent" size="sm" /> {/* renders "SA" initials */}
// ── Alert ──────────────────────────────────────────────────
<Alert variant="warning" title="Agent Account Restricted">
Only workspace owners can configure timezones and trigger invite cards.
</Alert>
<Alert variant="success" onClose={() => dismiss()}>
Verification code sent successfully.
</Alert>
// ── Tooltip ────────────────────────────────────────────────
<Tooltip content="Switch Reply Modes between manual and AI" position="top">
<button>Info</button>
</Tooltip>
// ── Progress ───────────────────────────────────────────────
<Progress value={75} variant="success" height={10} />
<Progress value={20} variant="danger" />
// ── Pagination ─────────────────────────────────────────────
<Pagination
currentPage={currentPage}
totalPages={10}
onPageChange={(page) => setCurrentPage(page)}
/>
// ── Skeleton ───────────────────────────────────────────────
<Skeleton variant="circle" width={48} height={48} />
<Skeleton variant="text" width="60%" />
<Skeleton variant="rect" width="100%" height={150} />
// ── Textarea ───────────────────────────────────────────────
<Textarea
label="Away Message"
placeholder="Thanks for writing to us..."
rows={4}
helperText="Sent automatically during off-hours"
/>
// ── Select ─────────────────────────────────────────────────
<Select label="Timezone" defaultValue="Asia/Kolkata">
<option value="Asia/Kolkata">India Standard Time (IST)</option>
<option value="UTC">Coordinated Universal Time (UTC)</option>
</Select>
// ── Hooks ──────────────────────────────────────────────────
const debouncedQuery = useDebounce(searchQuery, 400);
const dropdownRef = useRef<HTMLDivElement>(null);
useClickOutside(dropdownRef, () => setDropdownOpen(false));Design Tokens
All components use CSS custom properties defined in src/tokens.css. The token file covers both dark and light themes.
Switching theme at runtime:
// Dark mode
document.documentElement.setAttribute('data-theme', 'dark');
// Light mode
document.documentElement.setAttribute('data-theme', 'light');Key token categories in tokens.css:
| Category | Examples |
|----------|---------|
| Colors | --ui-bg-base, --ui-bg-surface, --ui-border |
| Typography | --ui-font, --ui-text-primary, --ui-text-muted |
| Spacing | --ui-radius-sm, --ui-radius-md, --ui-radius-xl |
| Shadows | --ui-shadow-sm, --ui-shadow-md, --ui-shadow-modal |
See src/tokens.css for all available variables.
Project Structure
react-components/
├── package.json # Package metadata + peer deps (React >= 18)
├── tsconfig.json # TypeScript config
├── tsup.config.ts # tsup configuration for CJS, ESM and CSS
└── src/
├── index.ts # Public API — imports index.css and exports components/hooks
├── index.css # Master stylesheet combining tokens.css and custom styles
├── tokens.css # CSS custom properties for dark + light themes
├── components/
│ ├── Button/
│ │ ├── Button.tsx
│ │ └── index.ts
│ ├── Badge/
│ │ ├── Badge.tsx
│ │ └── index.ts
│ ├── Spinner/
│ │ ├── Spinner.tsx
│ │ └── index.ts
│ ├── Input/
│ │ ├── Input.tsx
│ │ └── index.ts
│ └── Modal/
│ ├── Modal.tsx
│ └── index.ts
├── hooks/
│ ├── useClickOutside.ts
│ └── useDebounce.ts
└── types/ # Shared TypeScript type definitionsAdding a New Component
Create the component directory and files:
src/components/YourComponent/YourComponent.tsx src/components/YourComponent/index.tsAdd custom styling classes inside
src/index.cssusing the--ui-variables.Export from the barrel
index.ts:// src/components/YourComponent/index.ts export { YourComponent } from './YourComponent'; export type { YourComponentProps } from './YourComponent';Add to the main public API in
src/index.ts:export { YourComponent } from './components/YourComponent'; export type { YourComponentProps } from './components/YourComponent';Run
npm run buildto verify compiling.
Repository
GitLab: https://gitlab.com/alphastry/code-snippets/react-components
Part of the Alphastry ecosystem — auth-backend · auth-frontend
