@tontinepay/design-system
v0.4.15
Published
UI component library and design tokens for the TontinePay platform — client and seller apps.
Readme
@tontinepay/design-system
UI component library and design tokens for the TontinePay platform — client and seller apps.
Built with React 19, Tailwind CSS v4, and TypeScript. Optimised for mobile-first experiences with native-feel interactions.
Keywords: react, tailwindcss, design-system, ui-components, mobile-first, fintech, tontine, buy-now-pay-later, bnpl, typescript, react19
Installation
pnpm add @tontinepay/design-systemPublished to npmjs.com.
Setup
Import the stylesheet in your app's CSS entry point:
/* index.css */
@import "tailwindcss";
@import "@tontinepay/design-system/styles";That's it — no @source directive needed. The package ships a pre-built CSS bundle that includes all component styles, tokens, animations, and utilities.
Components
Button
import { Button } from "@tontinepay/design-system";
<Button variant="gradient" size="md" onClick={...}>
Payer en 3x
</Button>| Prop | Values |
|------|--------|
| variant | primary secondary gradient success danger ghost muted outline |
| size | xs sm md lg full icon icon-sm |
Input
import { Input } from "@tontinepay/design-system";
<Input
label="Email"
type="email"
placeholder="[email protected]"
error="Email invalide"
/>Prevents iOS Safari viewport zoom (uses font-size: 16px minimum). Supports label, error, prefix, suffix, and all native <input> props.
Toggle
import { Toggle } from "@tontinepay/design-system";
<Toggle on={enabled} onChange={() => setEnabled(v => !v)} />44px touch target, role="switch" + aria-checked for accessibility. Accepts disabled prop.
Badge
import { Badge } from "@tontinepay/design-system";
<Badge variant="success" dot size="sm">Livré</Badge>| Prop | Values |
|------|--------|
| variant | primary success warning danger neutral |
| size | xs sm md |
| dot | boolean — shows a status dot |
BottomSheet
import { BottomSheet } from "@tontinepay/design-system";
<BottomSheet open={open} onClose={() => setOpen(false)} title="Filtres" snap="auto">
{/* content */}
</BottomSheet>Swipe-to-dismiss (drag handle, 80px threshold), ESC key, backdrop tap to close, opacity fade during drag.
| Prop | Values |
|------|--------|
| snap | auto (85svh) · half (50svh) · full (92svh) |
Modal
import { Modal } from "@tontinepay/design-system";
<Modal open={open} onClose={() => setOpen(false)} title="Confirmation" size="sm">
{/* content */}
</Modal>ESC key to close, backdrop tap to close. Sizes: sm md lg.
Tabs / TabPanel
import { Tabs, TabPanel } from "@tontinepay/design-system";
<Tabs
tabs={[
{ id: "en_cours", label: "En cours", badge: 3 },
{ id: "terminees", label: "Terminées" },
]}
active={tab}
onChange={setTab}
variant="default"
/>
<TabPanel id="en_cours" active={tab}>...</TabPanel>
<TabPanel id="terminees" active={tab}>...</TabPanel>variant="pills" for scrollable pill-style tabs (touch-pan-x). 44px minimum touch target on all tabs.
Progress
import { Progress } from "@tontinepay/design-system";
<Progress value={65} />Skeleton
import { SkeletonCard, SkeletonList, SkeletonProduct } from "@tontinepay/design-system";
<SkeletonList count={3} />
<SkeletonProduct />
<SkeletonCard />Shimmer animation. SkeletonList renders count rows with avatar + text lines.
Toast
import { useToast, ToastProvider } from "@tontinepay/design-system";
// Wrap your app root:
<ToastProvider>
<App />
</ToastProvider>
// Then anywhere in your app:
const { success, error, info } = useToast();
success("Paiement confirmé !", "Votre commande est en cours de préparation.");Timeline
import { Timeline } from "@tontinepay/design-system";
<Timeline steps={[
{ label: "Commande reçue", date: new Date(), fait: true },
{ label: "En préparation", fait: true },
{ label: "Prêt au retrait", fait: false },
]} />Helpers
import {
formatEuros, // 1234.5 → "1 234,50 €"
formatEurosCompact, // 12000 → "12 k€"
formatDateShort, // Date → "11/05/2026"
formatDateLong, // Date → "11 mai 2026"
formatDateMonth, // Date → "11 mai"
formatRelative, // Date → "Il y a 3 min"
addMonths, // (date, n) → Date
cn, // clsx + tailwind-merge
} from "@tontinepay/design-system";Icons
All Lucide icons are re-exported:
import { Bell, ChevronRight, ShoppingCart } from "@tontinepay/design-system";Design tokens
Tokens are defined in src/index.css via @theme and available as Tailwind utilities:
| Token | Values |
|-------|--------|
| primary | 50 → 950 (brand blue) |
| success | 50 → 700 |
| warning | 50 → 600 |
| danger | 50 → 600 |
| neutral | 50 → 900 |
| shadow-card | subtle card elevation |
| shadow-elevated | medium elevation |
| shadow-overlay | sheets and modals |
| shadow-primary | brand-coloured glow |
Animations
| Class | Effect |
|-------|--------|
| animate-slide-up | entrance slide + fade |
| animate-fade-in | fade in |
| animate-scale-in | scale + fade entrance |
| animate-check-pop | checkmark pop |
| animate-bounce-subtle | gentle infinite bounce |
| animate-pulse-dot | pulsing dot |
| animate-bar-grow | bar chart grow |
All animations are disabled when the user has prefers-reduced-motion: reduce set.
Utilities
| Class | Effect |
|-------|--------|
| safe-top / safe-bottom | env(safe-area-inset-*) padding |
| no-scrollbar | hides scrollbar cross-browser |
| scroll-ios | momentum scrolling on iOS |
| active-scale | scale(0.97) on :active |
Changelog
0.4.5
- CSS — removed app-specific globals (
html,body,#root) from the published bundle; each consuming app owns its own layout reset
0.4.4
- CSS export — package now ships
dist/style.css; setup requires only@import "@tontinepay/design-system/styles"in the app CSS, no@sourceneeded - Build — story
.d.tsfiles excluded from the published package (tsconfig.lib.jsonexclude)
0.4.x
- Storybook — stories for all components, Vitest + Playwright browser tests
- CI — publish to npmjs.com, skip publish when version unchanged
0.3.0
- BottomSheet — swipe-to-dismiss,
snapprop (auto/half/full), ESC key, drag opacity - Toggle — 44px touch target,
role="switch"+aria-checked,disabledprop - Button — instant active feedback (
active:transition-none),touch-manipulation, 44px icon sizes - Input —
font-size: 16pxto prevent iOS Safari zoom - Tabs — 44px min touch target,
touch-pan-xon pills - Modal — ESC key handler
- CSS —
prefers-reduced-motionsupport,.no-scrollbarutility, mobile native-feel globals
0.2.0
- Initial publish — Badge, BottomSheet, Button, Input, Modal, Progress, Skeleton, Tabs, Timeline, Toast, Toggle
