@gxui/components
v1.0.2
Published
Enterprise theme engine + UI components (MUI-based)
Downloads
242
Maintainers
Readme
@gx-ui/components
Enterprise-grade React UI library built on Material UI 7, Framer Motion, and a multi-theme engine. Drop it into any React 18+ / 19+ app to get a complete design system — themes, feedback components, user management forms, motion presets, and more — out of the box.
Table of Contents
- Installation
- Quick Start
- Theme System
- Feedback & Loading
- UI Components
- User Management
- Motion Presets
- Hooks
- Constants
- Types
- Peer Dependencies
- Bundle Info
Installation
# npm
npm install @gx-ui/components
# yarn
yarn add @gx-ui/components
# pnpm
pnpm add @gx-ui/componentsInstall peer dependencies (skip any you already have):
npm install @mui/material @mui/icons-material @emotion/react @emotion/styled framer-motion react react-domNote:
framer-motionis optional. The library works without it, butGlassOverlayand motion-enhanced components require it.
Quick Start
Wrap your app root with GxThemeProvider. Everything else is then importable on demand.
// main.tsx
import { StrictMode } from 'react';
import { createRoot } from 'react-dom/client';
import { GxThemeProvider } from '@gx-ui/components';
import App from './App';
createRoot(document.getElementById('root')!).render(
<StrictMode>
<GxThemeProvider defaultTheme="glassmorphism" defaultMode="system">
<App />
</GxThemeProvider>
</StrictMode>,
);Theme System
GxThemeProvider
The root provider. Must wrap your entire app. Handles MUI theme injection, light/dark mode, and optional cloud sync.
import { GxThemeProvider } from '@gx-ui/components';
<GxThemeProvider
defaultTheme="enterprise" // Which theme to start with (default: 'default')
defaultMode="system" // 'light' | 'dark' | 'system' (default: 'system')
syncUrl="https://api.example.com" // Optional: base URL for cloud theme sync
>
<App />
</GxThemeProvider>| Prop | Type | Default | Description |
|---|---|---|---|
| defaultTheme | GxThemeId | 'default' | Initial theme |
| defaultMode | GxThemeMode | 'system' | Initial color mode |
| syncUrl | string | 'https://api.gksvp.com' | Cloud sync base URL |
Available Themes
| ID | Style | Best For |
|---|---|---|
| default | Clean MUI blue, rounded surfaces | General-purpose apps |
| glassmorphism | Frosted glass panels, backdrop blur | Dashboards, media apps |
| liquid | Aurora radial gradients, fluid shapes | Creative tools, portfolios |
| materialYou | MD3-inspired tonal surfaces | Consumer mobile-first apps |
| minimalDark | Pure black, ultra-thin borders | Developer tools, IDEs |
| enterprise | Conservative navy, B2B SaaS | Admin panels, internal tools |
| natural | Forest greens, earthy tones | Wellness, sustainability apps |
| product | Violet & amber, conversion-optimized | Landing pages, SaaS marketing |
| skeuomorphism | Tactile neumorphic surfaces | Audio apps, knobs, sliders |
| claymorphism | Puffy 3D clay-like surfaces | Consumer apps, games |
| liquidGlass | Apple's spatial design language | Premium, spatial UIs |
Switching Themes at Runtime
Use the useGxTheme hook from anywhere inside GxThemeProvider.
import { useGxTheme } from '@gx-ui/components';
function ThemePicker() {
const { currentTheme, mode, setTheme, setMode } = useGxTheme();
return (
<>
<button onClick={() => setTheme('liquid')}>Liquid</button>
<button onClick={() => setTheme('enterprise')}>Enterprise</button>
<button onClick={() => setMode(mode === 'dark' ? 'light' : 'dark')}>
Toggle {mode === 'dark' ? 'Light' : 'Dark'}
</button>
</>
);
}ThemeStudio
A full-featured, self-contained theme management page. Drop it on a route — no additional props required.
import { lazy, Suspense } from 'react';
import { PageSkeleton } from '@gx-ui/components';
// Lazy-load — it's a heavy editor, only load when the route is visited.
const ThemeStudio = lazy(() =>
import('@gx-ui/components').then(m => ({ default: m.ThemeStudio }))
);
// In your router:
<Route path="/themes" element={
<Suspense fallback={<PageSkeleton layout="dashboard" />}>
<ThemeStudio />
</Suspense>
} />Features: theme grid/list view, search & sort, live light/dark preview, custom theme creation with color editor, WCAG contrast audit, and cloud sync.
Feedback & Loading
NavProgress
A fixed top-of-page progress bar (like YouTube/GitHub). Requires NavProgressProvider near your app root.
Step 1 — Add the provider and bar once (App or Layout root):
// App.tsx
import { NavProgressProvider, NavProgress } from '@gx-ui/components';
export default function App() {
return (
<NavProgressProvider>
<NavProgress /> {/* renders the fixed bar — put this once */}
<BrowserRouter>
<AppRoutes />
</BrowserRouter>
</NavProgressProvider>
);
}Step 2 — Call start() / stop() around async operations anywhere in your app:
import { useNavProgress } from '@gx-ui/components';
function SaveButton() {
const { start, stop } = useNavProgress();
const handleSave = async () => {
start();
try {
await api.saveData();
} finally {
stop();
}
};
return <button onClick={handleSave}>Save</button>;
}NavProgress props:
| Prop | Type | Default | Description |
|---|---|---|---|
| color | 'primary' \| 'secondary' \| 'inherit' | 'primary' | Bar color |
| height | number | 3 | Height in px |
| zIndex | number | 9999 | z-index override |
Behavior: start() sets progress to 8% and logarithmically increments toward 90%. stop() jumps to 100% then fades out after 450 ms.
LoadingButton
A MUI Button wrapper that shows a CircularProgress spinner while loading. Maintains button width so the layout never shifts.
import { LoadingButton } from '@gx-ui/components';
function SubmitForm() {
const [saving, setSaving] = useState(false);
return (
// Spinner at the end (default)
<LoadingButton
loading={saving}
variant="contained"
onClick={handleSubmit}
>
Save Changes
</LoadingButton>
);
}Spinner positions:
// Spinner replaces the startIcon
<LoadingButton loading={saving} loadingPosition="start" startIcon={<SaveIcon />}>
Save
</LoadingButton>
// Spinner overlays the label — button width is preserved exactly
<LoadingButton loading={saving} loadingPosition="center" loadingText="Saving…">
Save Changes
</LoadingButton>
// Spinner at the end (default)
<LoadingButton loading={saving} loadingPosition="end">
Submit
</LoadingButton>| Prop | Type | Default | Description |
|---|---|---|---|
| loading | boolean | false | Shows spinner and disables the button |
| loadingPosition | 'start' \| 'end' \| 'center' | 'end' | Where the spinner appears |
| loadingText | React.ReactNode | — | Label shown while loading (center mode) |
| spinnerSize | number | 16 | Spinner diameter in px |
| disabled | boolean | — | Disable independently of loading |
Accepts all standard MUI ButtonProps.
GlassOverlay
A blocking overlay with a frosted-glass card and spinner. Two variants: fullscreen (portal to document.body) and scoped (covers the nearest position: relative ancestor).
import { GlassOverlay } from '@gx-ui/components';
// Full-page — use for critical blocking operations (delete account, payment processing)
function DeleteAccountButton() {
const [deleting, setDeleting] = useState(false);
return (
<>
<GlassOverlay open={deleting} message="Deleting account…" />
<button onClick={() => { setDeleting(true); deleteAccount(); }}>
Delete Account
</button>
</>
);
}
// Scoped — covers only a card while it saves
function ProfileCard() {
const [saving, setSaving] = useState(false);
return (
<Box sx={{ position: 'relative' }}>
<GlassOverlay open={saving} variant="scoped" message="Saving…" />
<CardContent>…form fields…</CardContent>
</Box>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
| open | boolean | — | Required. Shows/hides the overlay |
| message | string | — | Label shown below the spinner |
| variant | 'fullscreen' \| 'scoped' | 'fullscreen' | Fullscreen uses a portal; scoped is inline |
| blur | number | 12 | Backdrop blur in px |
| spinnerSize | number | 40 | Spinner diameter in px |
| zIndex | number | 1400 | z-index (default is above MUI Dialog) |
Accessibility: Renders with
role="dialog",aria-modal,aria-busy, andaria-labelautomatically.
PageSkeleton
Full-page shimmer skeleton that mimics your page layout while data loads. Use as a Suspense fallback or an early if (loading) return guard.
import { PageSkeleton } from '@gx-ui/components';
// As a Suspense fallback (route-level lazy loading)
<Suspense fallback={<PageSkeleton layout="dashboard" />}>
<DashboardPage />
</Suspense>
// As an early return guard
function ProfilePage() {
const { loading } = useProfile();
if (loading) return <PageSkeleton layout="profile" />;
return <ActualProfilePage />;
}
// Table with custom row count
<PageSkeleton layout="table" rows={12} />
// Form with custom field count
<PageSkeleton layout="form" fields={8} />| Prop | Type | Default | Description |
|---|---|---|---|
| layout | 'dashboard' \| 'profile' \| 'table' \| 'form' | 'dashboard' | Which page pattern to mimic |
| rows | number | 8 | Row count for table layout |
| fields | number | 6 | Field count for form layout |
Layout previews:
dashboard— top nav + 4 stat cards + chart area + list panelprofile— top nav + avatar header + 3 form sectionstable— toolbar + filter chips + header row + data rowsform— page title + grouped input fields + action buttons
UI Components
GlassCard
A frosted-glass card with optional hover lift, glow, and shine effects. Adapts to the active theme automatically.
import { GlassCard } from '@gx-ui/components';
<GlassCard hover glow>
<Typography variant="h6">Card Title</Typography>
<Typography>Card content goes here.</Typography>
</GlassCard>
// Disable hover animation
<GlassCard hover={false}>
<StaticContent />
</GlassCard>| Prop | Type | Default | Description |
|---|---|---|---|
| hover | boolean | true | Lift + scale on hover |
| glow | boolean | false | Ambient glow around card |
| blur | number | 20 | Backdrop blur strength in px |
| shine | boolean | false | Diagonal shine sweep on hover |
Accepts all MUI BoxProps.
GlassTextField
A MUI TextField with glass morphism styling and optional focus animation.
import { GlassTextField } from '@gx-ui/components';
<GlassTextField label="Email" type="email" fullWidth />
<GlassTextField
label="Password"
type="password"
glassVariant="gradient"
fullWidth
/>
<GlassTextField
label="Notes"
multiline
rows={4}
glassVariant="inset"
disableMotion
/>| Prop | Type | Default | Description |
|---|---|---|---|
| glassVariant | 'default' \| 'gradient' \| 'inset' | 'default' | Glass style variant |
| disableMotion | boolean | false | Disables Framer Motion focus animation |
Accepts all MUI TextFieldProps except variant (always outlined).
GradientButton
A MUI Button with a gradient background, configurable angle, and optional glow effect.
import { GradientButton } from '@gx-ui/components';
<GradientButton>Get Started</GradientButton>
<GradientButton glow angle={90} toSecondary>
Learn More
</GradientButton>| Prop | Type | Default | Description |
|---|---|---|---|
| angle | number | 135 | Gradient angle in degrees |
| glow | boolean | true | Adds ambient glow shadow |
| toSecondary | boolean | false | Gradient goes from primary → secondary |
Accepts all MUI ButtonProps except component.
LoadingCard & ShimmerBlock
LoadingCard renders a themed skeleton for a single card. ShimmerBlock is the low-level primitive for building custom skeletons.
import { LoadingCard, ShimmerBlock } from '@gx-ui/components';
// Pre-built card skeletons
<LoadingCard variant="product" />
<LoadingCard variant="list" rows={5} />
<LoadingCard variant="profile" />
<LoadingCard variant="stat" shimmer={false} />
// Build a custom skeleton from primitives
function MyCustomSkeleton() {
return (
<Box sx={{ p: 2 }}>
<ShimmerBlock width="60%" height={24} radius={4} />
<Box sx={{ mt: 1 }}>
<ShimmerBlock width="100%" height={14} />
</Box>
<Box sx={{ mt: 0.5 }}>
<ShimmerBlock width="80%" height={14} />
</Box>
</Box>
);
}LoadingCard props:
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | 'product' \| 'list' \| 'profile' \| 'stat' | 'product' | Card shape to mimic |
| rows | number | 3 | Row count for list variant |
| shimmer | boolean | true | Enables the sweep shimmer animation |
| glass | boolean | false | Glass-style card background |
ShimmerBlock props:
| Prop | Type | Default | Description |
|---|---|---|---|
| width | string \| number | '100%' | Width (px or CSS string like '60%') |
| height | string \| number | 16 | Height in px |
| radius | number | 4 | Border radius in px |
ProductCard
A ready-to-use e-commerce / catalog card with image, badge, tags, price, and an action button.
import { ProductCard } from '@gx-ui/components';
<ProductCard
image="/products/widget.png"
title="Premium Widget"
subtitle="By Acme Corp"
price="$49.99"
badge="New"
tags={['TypeScript', 'React']}
actionLabel="View Details"
onAction={() => navigate('/products/1')}
/>
// Loading state
<ProductCard title="" loading />
// Glass style
<ProductCard title="Card Title" glass onAction={handleClick} />| Prop | Type | Default | Description |
|---|---|---|---|
| title | string | — | Required |
| image | string | — | Image URL |
| subtitle | string | — | Secondary text below title |
| price | string | — | Price string (formatted, e.g. '$49.99') |
| badge | string | — | Badge label (top-right corner) |
| tags | string[] | — | Chip tags below subtitle |
| loading | boolean | false | Shows skeleton instead of content |
| glass | boolean | false | Glass background variant |
| onAction | () => void | — | Action button click handler |
| actionLabel | string | 'View' | Action button label |
User Management
A complete set of forms and pages for managing a user's profile, contacts, addresses, KYC documents, social accounts, and preferences. Wire them to your own API.
UserManagementPage
All-in-one page with tabs for every user management section. The simplest integration path.
import { UserManagementPage } from '@gx-ui/components';
function ProfilePage() {
const handleSave = async (data) => {
// data contains: profile, phones, emails, addresses,
// documents, socialAccounts, uiPreferences,
// notificationPreferences, privacyPreferences
await userApi.save(data);
};
return (
<UserManagementPage
initialProfile={{
firstName: 'Jane',
lastName: 'Doe',
email: '[email protected]',
}}
onSave={handleSave}
isLoading={false}
/>
);
}| Prop | Type | Default | Description |
|---|---|---|---|
| initialProfile | Partial<UserProfile> | — | Pre-populate form fields |
| onSave | (data) => Promise<void> | — | Called when user saves any section |
| isLoading | boolean | false | Shows loading state |
| onNavigate | (tab: string) => void | — | Notified when the user switches tabs |
UserProfileCard
A compact or full display card for a user's profile — avatar, name, status, role badge.
import { UserProfileCard } from '@gx-ui/components';
<UserProfileCard profile={userProfile} />
// Compact single-line variant
<UserProfileCard profile={userProfile} compact />UserProfileForm
Controlled form for editing core profile fields.
import { UserProfileForm } from '@gx-ui/components';
const [profileData, setProfileData] = useState({ firstName: '', lastName: '', bio: '' });
<UserProfileForm
value={profileData}
onChange={(field, value) => setProfileData(p => ({ ...p, [field]: value }))}
showAdminFields={isAdmin}
/>AddressForm
Add, remove, and set-primary for a user's address list.
import { AddressForm } from '@gx-ui/components';
<AddressForm
addresses={profile.addresses}
onAdd={async (data) => { await api.addAddress(data); }}
onRemove={async (id) => { await api.removeAddress(id); }}
onSetPrimary={async (id) => { await api.setPrimaryAddress(id); }}
/>ContactDetailForm
Manages a list of phone numbers and email addresses with country dial code selection and validation.
import { ContactDetailForm } from '@gx-ui/components';
<ContactDetailForm
phoneEntries={phones}
emailEntries={emails}
onPhonesChange={setPhones}
onEmailsChange={setEmails}
showErrors
/>KycDocumentForm
Upload and manage identity documents (passport, national ID, driving license, etc.) with verification status display.
import { KycDocumentForm } from '@gx-ui/components';
<KycDocumentForm
documents={profile.kyc}
onAdd={async (data) => { await api.addDocument(data); }}
onRemove={async (id) => { await api.removeDocument(id); }}
readOnly={!canEdit}
/>SocialAccountsForm
Manage links to 20+ social platforms including LinkedIn, Twitter/X, GitHub, Instagram, YouTube, and regional platforms (WeChat, KakaoTalk, Zalo, VK, etc.).
import { SocialAccountsForm } from '@gx-ui/components';
<SocialAccountsForm
accounts={profile.socialAccounts}
onAdd={(data) => api.addSocial(data)}
onUpdate={(id, data) => api.updateSocial(id, data)}
onDelete={(id) => api.deleteSocial(id)}
/>UserPreferencesPanel
Three preference sections in a single panel: UI preferences (theme, language, density), notification preferences (email, push, SMS toggles), and privacy preferences (profile visibility, data sharing).
import { UserPreferencesPanel } from '@gx-ui/components';
<UserPreferencesPanel
ui={prefs.ui}
notifications={prefs.notifications}
privacy={prefs.privacy}
onUiChange={(key, value) => updateUiPref(key, value)}
onNotificationChange={(key, value) => updateNotifPref(key, value)}
onPrivacyChange={(key, value) => updatePrivacyPref(key, value)}
/>Motion Presets
Framer Motion animation presets for consistent motion across your app. Spread directly into motion component props.
import { motion } from 'framer-motion';
import { slideUp, staggerContainer, staggerItem, hoverLift, tapPress } from '@gx-ui/components';
// Entrance animation
<motion.div variants={slideUp} initial="hidden" animate="visible">
<MyCard />
</motion.div>
// Stagger children
<motion.ul variants={staggerContainer} initial="hidden" animate="visible">
{items.map(item => (
<motion.li key={item.id} variants={staggerItem}>
{item.label}
</motion.li>
))}
</motion.ul>
// Interactive gestures
<motion.div whileHover={hoverLift} whileTap={tapPress}>
<ClickableCard />
</motion.div>Entrance variants (use with initial="hidden" animate="visible"):
| Export | Effect |
|---|---|
| fadeIn | Opacity fade |
| slideUp | Fade + slide up 16 px |
| slideDown | Fade + slide down 16 px |
| slideIn | Fade + slide in from left 24 px |
| scaleIn | Fade + scale from 0.92 |
Stagger (apply to container, staggerItem to children):
| Export | Effect |
|---|---|
| staggerContainer | Staggers children by 60 ms |
| staggerItem | Fades + slides up 12 px |
Gestures (use with whileHover / whileTap):
| Export | Effect |
|---|---|
| hoverLift | Lifts up 6 px + scales 1.05× |
| hoverScale | Scales 1.03× |
| hoverGlow | Scales 1.02× |
| tapPress | Scales down to 0.97× |
| focusScale | Scales 1.02× |
Continuous (use with animate):
| Export | Effect |
|---|---|
| pulseAnimation | Breathing opacity pulse |
| shimmerAnimation | Left-to-right sweep |
| floatBob | Gentle up-down float |
| spin | Continuous rotation |
Hooks
useNavProgress
Controls the NavProgress bar from anywhere in the tree.
import { useNavProgress } from '@gx-ui/components';
const { start, stop, isLoading, progress } = useNavProgress();| Return | Type | Description |
|---|---|---|
| start | () => void | Begin progress animation |
| stop | () => void | Complete and hide the bar |
| isLoading | boolean | Whether the bar is currently active |
| progress | number | Current progress value (0–100) |
Requires
NavProgressProviderto be an ancestor in the tree.
useCountry
Look up country data by ISO code, or search the full country list.
import { useCountry, useCountrySearch } from '@gx-ui/components';
// Single lookup
const country = useCountry('IN');
// → { code: 'IN', name: 'India', dialCode: '+91' }
// Searchable list for autocomplete UI
const { query, setQuery, countries } = useCountrySearch();usePhoneValidation
Parse and validate phone numbers using libphonenumber-js. Returns E.164, national, and international formats.
import { usePhoneInput, validatePhone } from '@gx-ui/components';
// Controlled input hook
function PhoneField() {
const { rawValue, formatted, validation, handleChange, handleCountryChange } = usePhoneInput('IN');
return (
<>
<select onChange={e => handleCountryChange(e.target.value)}>…</select>
<input value={rawValue} onChange={e => handleChange(e.target.value)} />
{!validation.isValid && <span>{validation.error}</span>}
{validation.isValid && <span>E.164: {validation.e164}</span>}
</>
);
}
// One-shot validation
const result = validatePhone('+919876543210');
// → { isValid: true, e164: '+919876543210', national: '98765 43210', ... }Constants
import { COUNTRIES, CURRENCY_MAP, TIMEZONE_MAP, getCountryByCode } from '@gx-ui/components';
// Countries (ISO 3166-1 alpha-2)
COUNTRIES.forEach(c => console.log(c.code, c.name, c.dialCode));
const india = getCountryByCode('IN'); // { code: 'IN', name: 'India', dialCode: '+91' }
// Currencies
const usd = CURRENCY_MAP['USD']; // { code, name, symbol, decimals }
// Timezones
const tz = TIMEZONE_MAP['Asia/Kolkata']; // { id, label, offset, region }Types
All types are re-exported from the package root. Import them with import type for zero runtime cost.
import type {
// User
UserProfile, Gender, AccountStatus, AccountType,
// Contact
PhoneEntry, EmailEntry, PhoneContactType, EmailContactType,
// Address
Address, AddressFormData, AddressType,
// KYC
KycDocument, KycDocumentFormData, KycDocumentType, KycVerificationStatus,
// Social
SocialAccount, SocialAccountFormData, SocialPlatform,
// Preferences
UiPreferences, NotificationPreferences, PrivacyPreferences,
// Theme
GxThemeId, GxThemeMode, ThemeConfig, ThemePreset,
} from '@gx-ui/components';Peer Dependencies
| Package | Required | Version |
|---|---|---|
| react | Yes | >=18 |
| react-dom | Yes | >=18 |
| @mui/material | Yes | >=6 |
| @emotion/react | Yes | >=11 |
| @emotion/styled | Yes | >=11 |
| framer-motion | Optional | >=10 |
framer-motionis optional but required byGlassOverlayand any component that uses motion presets.
Bundle Info
The library ships as dual ESM + CJS with full TypeScript declarations.
dist/
├── index.js # ESM — tree-shakeable
├── index.cjs # CommonJS
├── index.d.ts # TypeScript declarations (ESM)
└── index.d.cts # TypeScript declarations (CJS)Built with tsup targeting ES2022. All MUI, React, and Framer Motion imports are externalized — they are not bundled into the output, keeping the installed size minimal.
To rebuild after source changes:
# One-time build
npm run build
# Watch mode for development
npm run dev
# Type-check only (no emit)
npm run typecheck