@rayna2/shared-ui
v1.0.3
Published
Shared React UI component library for Rayna — booking flows, product cards, search, checkout, and more
Readme
@rayna2/shared-ui
A comprehensive React UI component library for the Rayna platform. Provides reusable components, hooks, utilities, and styling primitives shared across all Rayna applications (web-app, admin, and others).
Features
- 50+ production-ready components — forms, tables, cards, navigation, modals, and more
- Dual packaging — ships as both ESM (
.js) and CommonJS (.cjs) for maximum compatibility - Tree-shakeable — import only what you need; unused code is eliminated during bundling
- Next.js and generic React support — works seamlessly with Next.js App Router, Pages Router, and plain React (Vite, CRA, etc.)
- Deep-path imports — import individual components directly for granular bundle control
- First-class TypeScript — all components ship with complete type declarations
- Source maps — included for debugging in development
Installation
npm install @rayna2/shared-ui
# or
yarn add @rayna2/shared-ui
# or
pnpm add @rayna2/shared-uiPeer Dependencies
This package expects the following to be installed by the consumer project. They are not bundled to avoid duplicate copies in your application.
| Package | Minimum Version |
|---|---|
| react | ^18.0.0 |
| react-dom | ^18.0.0 |
| next | ^14.0.0 (optional — only for Next.js integration) |
| @trpc/client | ^11.0.0 (optional — only for tRPC integration) |
| @trpc/server | ^11.0.0 (optional) |
| @trpc/react-query | ^11.0.0 (optional) |
Components that depend on tRPC will gracefully degrade or require minimal integration setup (see tRPC setup below).
Bundled Workspace Dependencies
The following internal packages are bundled into @rayna2/shared-ui so consumers don't need to install them separately:
@rayna2/icons— SVG icon components@rayna2/shared-utils— general-purpose utilities@rayna2/colors— design token color values
Setup
Next.js (App Router or Pages Router)
The library works out of the box with Next.js. No additional configuration is required.
For 'use client' components, Next.js will automatically handle client/server boundaries. The library's internal aliases map next/* imports to generic React wrappers when building for non-Next.js consumers, but when used inside a Next.js project, the native Next.js modules are used directly.
Generic React (Vite, Create React App, etc.)
When using this library outside of Next.js (plain React, Vite, etc.), the build automatically replaces next/* imports (like next/link, next/image, next/navigation) with lightweight, generic React-compatible stubs. No manual configuration is needed.
tRPC Integration
If your project uses tRPC, ensure the following peer dependencies are installed:
npm install @trpc/client @trpc/server @trpc/react-queryThe library's tRPC-dependent hooks will pick up your project's tRPC client configuration automatically through React context.
Usage
Basic Component Import
import { Button } from '@rayna2/shared-ui';
import { Card } from '@rayna2/shared-ui';
function MyComponent() {
return (
<Card>
<h2>Welcome</h2>
<Button variant="primary" onClick={() => alert('Clicked!')}>
Get Started
</Button>
</Card>
);
}Named Imports (Tree-shaking Friendly)
import { Button, Card, Modal, TextInput, Spinner } from '@rayna2/shared-ui';Deep-path Imports (Granular Import Control)
For maximum tree-shaking, import components directly from their file path:
import { Button } from '@rayna2/shared-ui/Button';
import { ProductCard } from '@rayna2/shared-ui/new-components/ProductDisplay/ProductCardWrapper';Note: Deep-path imports bypass the barrel file and may improve build performance for large applications. All publicly exported components are available both from the main entry point and via deep paths.
Hook Imports
import { useDebounce } from '@rayna2/shared-ui';
import { useMediaQuery } from '@rayna2/shared-ui';
function ResponsiveComponent() {
const isMobile = useMediaQuery('(max-width: 768px)');
const debouncedValue = useDebounce(searchTerm, 300);
// ...
}TypeScript
This library ships with complete TypeScript declarations. All components, hooks, and utilities export typed interfaces and type helpers.
Typed Components
import { TextInput, type TextInputProps } from '@rayna2/shared-ui';
function Form(): JSX.Element {
const [value, setValue] = React.useState('');
return (
<TextInput
label="Email"
value={value}
onChange={setValue}
placeholder="Enter your email"
error={!isValidEmail(value) ? 'Invalid email address' : undefined}
/>
);
}Typed Hooks
import { useAsyncData, type AsyncDataState } from '@rayna2/shared-ui';
interface User {
id: string;
name: string;
}
function UserProfile({ userId }: { userId: string }) {
const { data, isLoading, error } = useAsyncData<User>(
() => fetchUser(userId),
[userId]
);
if (isLoading) return <Spinner />;
if (error) return <ErrorDisplay message={error.message} />;
return <div>{data?.name}</div>;
}Building
If you are working on this library within the Rayna monorepo:
# Build the library
nx build shared-ui
# Watch mode for development
nx build shared-ui --watch
# Run tests
nx test shared-ui
# Run tests with coverage
nx test shared-ui --coverageOutput Structure
After building, the dist/ directory contains:
dist/
├── esm/ # ES module (.js) output
│ ├── Button.js
│ ├── Card.js
│ └── ...
├── cjs/ # CommonJS (.cjs) output
│ ├── Button.cjs
│ ├── Card.cjs
│ └── ...
├── Button.d.ts # TypeScript declarations
├── Card.d.ts
└── ...Contents
The library includes components across several categories:
| Category | Examples | |---|---| | Primitives | Button, TextInput, Card, Modal, Spinner, Badge, Tooltip | | Layout | Container, Grid, Stack, Divider, Flex | | Forms | FormField, Select, Checkbox, RadioGroup, DatePicker, FileUpload | | Data Display | Table, DataGrid, List, Avatar, Chip, Tag | | Navigation | Tabs, Breadcrumbs, Pagination, SideNav | | Feedback | Toast, Alert, ProgressBar, Skeleton, EmptyState | | Hooks | useDebounce, useMediaQuery, useAsyncData, useClickOutside, useLocalStorage | | New Components | ProductCard, ActivityBooking, SalesDashboard, CustomerSelector | | Utilities | formatCurrency, formatDate, cn (classnames), validators |
Troubleshooting
Module not found: Can't resolve '@rayna2/shared-ui'
Ensure the package is installed correctly:
npm ls @rayna2/shared-uiIf using a monorepo (pnpm workspaces, yarn workspaces), check that the package is listed in your workspace configuration.
'next' module not found errors
This library supports both Next.js and plain React. When building for a non-Next.js consumer, next/* modules are automatically aliased to generic stubs. If you see errors about missing next modules, ensure:
- The library was built with the correct tsup configuration (it handles aliasing automatically).
- If you are using Next.js, install it as a dependency:
npm install next
Deep-path imports not resolving
Deep-path imports require the dist/ directory to maintain the same folder structure as src/. If imports like @rayna2/shared-ui/Button fail:
- Verify the library was built successfully (
nx build shared-ui). - Check that
dist/is present and contains the expected file structure. - Ensure your bundler resolves subpath exports from
package.json.
Tree-shaking not working
If you notice unused components being included in your bundle:
- Prefer named imports from the main entry point (
import { Button } from '@rayna2/shared-ui'). - For optimal results, use deep-path imports (
import { Button } from '@rayna2/shared-ui/Button'). - Verify your bundler is configured for tree-shaking (Webpack 5+, Vite, or esbuild handle this automatically).
CSS not loading
The library uses CSS files that are copied alongside the JavaScript output. If styles are missing:
- Ensure your bundler is configured to handle
.cssimports (Next.js and Vite do this automatically). - If you are using a custom bundler, you may need to add a CSS loader.
Type errors in components
Ensure your tsconfig.json includes the following compiler options:
{
"compilerOptions": {
"jsx": "react-jsx",
"moduleResolution": "bundler",
"esModuleInterop": true,
"strict": true
}
}If using deep-path imports, also enable moduleResolution: "bundler" or "node16".
CommonJS vs ESM issues
This library ships both formats. Modern bundlers (Webpack 5, Vite, esbuild, Next.js) will automatically pick the ESM build. If you encounter issues:
- For ESM projects: the
.jsfiles indist/esm/are used automatically. - For CJS projects: the
.cjsfiles indist/cjs/are used automatically. - If your bundler picks the wrong format, explicitly configure resolution in your bundler's config.
License
MIT — see LICENSE.