- Externalize all @tamagui/* and tamagui subpaths so dist no longer vendors Tamagui. - Emit TypeScript declarations with vite-plugin-dts; fix package exports types for ui/*. - Align initEnv with profiles: displayName, brandLogo, api.baseURL, themeColor, uiShell. - Stabilize tests with Node localStorage file; env tests pass. - Update README and component docs for services, menus, API client, and development.
Shell components
When consuming @reliancy/bface from npm, import shells and helpers from @reliancy/bface/ui/components (for example import { EmptyShell, useShell } from '@reliancy/bface/ui/components'). This repository uses @ui/* TypeScript path aliases in source; published paths follow package.json exports.
Shell components provide a flexible, responsive, sectioned layout system for the application. All components are built with Tamagui for cross-platform compatibility (web + React Native).
Architecture
Responsive Layout Structure
Desktop Layout (gtSm, > 801px)
┌─────────────────────────────────────┐
│ LeftSide │ MiddleSide │ RightSide │
│ │ ┌────────┐ │ │
│ │ │ Header │ │ │
│ │ ├────────┤ │ │
│ │ │ Main │ │ │
│ │ │Content │ │ │
│ │ ├────────┤ │ │
│ │ │ Footer │ │ │
│ │ └────────┘ │ │
└─────────────────────────────────────┘
Mobile Layout (sm and below, ≤ 801px)
┌─────────────────────┐
│ Header │
├─────────────────────┤
│ LeftSide (TopBar) │ ← Hamburger menu bar
├─────────────────────┤
│ MainContent │
├─────────────────────┤
│ RightSide │
├─────────────────────┤
│ Footer │
└─────────────────────┘
Default Dimensions
- LeftSide: 0px width (collapsed on desktop), full width on mobile
- RightSide: 0px width (collapsed on desktop), full width on mobile
- MiddleSide: 100% width (takes remaining space on desktop)
- Header: 0px height (collapsed)
- Footer: 0px height (collapsed)
- MainContent: 100% height (flex: 1)
Usage
Basic Usage
import { EmptyShell } from '@ui/components';
function App() {
return (
<EmptyShell>
<div>This goes to MainContent by default</div>
</EmptyShell>
);
}
Placing Children in Specific Sections
Method 1: Using ShellPlacement Component
import { EmptyShell, ShellPlacement } from '@ui/components';
function App() {
return (
<EmptyShell>
<ShellPlacement placement="leftSide">
<Sidebar />
</ShellPlacement>
<ShellPlacement placement="header">
<Header />
</ShellPlacement>
<div>Main content (default placement)</div>
<ShellPlacement placement="footer">
<Footer />
</ShellPlacement>
</EmptyShell>
);
}
Method 2: Using placement prop directly
import { EmptyShell } from '@ui/components';
function App() {
return (
<EmptyShell>
<Sidebar placement="leftSide" />
<Header placement="header" />
<MainContent /> {/* Defaults to mainContent */}
<Footer placement="footer" />
</EmptyShell>
);
}
Programmatic Control
Use the useShell hook to control section dimensions:
import { EmptyShell, useShell } from '@ui/components';
function SidebarToggle() {
const { toggleLeftSide, leftSideWidth } = useShell();
return (
<button onClick={() => toggleLeftSide(250)}>
{leftSideWidth === 0 ? 'Show' : 'Hide'} Sidebar
</button>
);
}
function Dashboard() {
return (
<EmptyShell>
<Sidebar placement="leftSide" />
<SidebarToggle />
<MainContent />
</EmptyShell>
);
}
Available Control Functions
const {
// Current dimensions
leftSideWidth,
rightSideWidth,
headerHeight,
footerHeight,
// Setter functions
setLeftSideWidth,
setRightSideWidth,
setHeaderHeight,
setFooterHeight,
// Convenience toggles
toggleLeftSide, // (targetWidth = 250) => void
toggleRightSide // (targetWidth = 250) => void
} = useShell();
Example: DashboardShell with Toggleable Sidebar
import { EmptyShell, useShell } from '@ui/components';
function DashboardShell({ children }) {
return (
<EmptyShell initialLeftWidth={250}>
<Sidebar placement="leftSide" />
<DashboardHeader placement="header" />
{children}
<DashboardFooter placement="footer" />
</EmptyShell>
);
}
function Sidebar() {
const { toggleLeftSide, leftSideWidth } = useShell();
return (
<div>
<button onClick={() => toggleLeftSide(250)}>
{leftSideWidth === 0 ? '☰' : '✕'}
</button>
{/* Sidebar content */}
</div>
);
}
Placement Values
'leftSide'or'left'- Left sidebar'rightSide'or'right'- Right sidebar'header'- Top header section'footer'- Bottom footer section'mainContent'or'main'- Main content area (default)
Responsive Design
All shell components are responsive and automatically adapt to screen size using Tamagui's useMedia() hook:
- Breakpoint: Switches at
sm(801px) using Tamagui's default breakpoints - Desktop (> 801px): Horizontal layout with sidebars
- Mobile (≤ 801px): Vertical stack layout
TopBar Component
The TopBar component automatically switches between wide and narrow layouts:
- Desktop: Full horizontal navigation bar with all menu items visible
- Mobile: Hamburger menu button + Sheet drawer for menu items
Subcomponents:
TopBar.Wide- Desktop layout (horizontal menu items)TopBar.Narrow- Mobile layout (hamburger + Sheet)
Usage:
import { TopBar } from '@ui/components';
// Automatically responsive
<TopBar>
{/* Custom content with placement */}
</TopBar>
SideBar Component
The SideBar component automatically switches between wide and narrow layouts:
- Desktop: Fixed vertical sidebar with all menu items visible
- Mobile: Hamburger menu button + Sheet drawer for menu items
Subcomponents:
SideBar.Wide- Desktop layout (vertical sidebar)SideBar.Narrow- Mobile layout (hamburger + Sheet)
Usage:
import { SideBar } from '@ui/components';
// Automatically responsive
<SideBar>
{/* Custom content with placement */}
</SideBar>
EmptyShell Responsive Behavior
EmptyShell automatically adapts its layout:
- Desktop: Horizontal
XStackwith LeftSide, MiddleSide, RightSide side-by-side - Mobile: Vertical
YStackwith sections stacked: Header → LeftSide → MainContent → RightSide → Footer
On mobile, LeftSide becomes a full-width top bar (perfect for hamburger menus), and RightSide stacks below main content.
Platform-Agnostic
All shell components use Tamagui components (XStack, YStack, View, Sheet, useMedia) making them work on:
- Web (React)
- iOS (React Native)
- Android (React Native)
- Other platforms supported by Tamagui
The responsive design uses Tamagui's built-in breakpoints and media queries, ensuring consistent behavior across platforms.