@wblo/ui
v0.3.0
Published
Reusable React UI component library.
Readme
@wblo/ui
Reusable React UI component library with RTL/LTR support, wblo-ui namespaced theming, dark mode, rich form controls, data display, and editor tooling.
Install
pnpm add @wblo/ui react react-domimport "@wblo/ui/styles.css"Quick Start
import { Button, Card, CardContent } from "@wblo/ui"
export function Demo() {
return (
<Card>
<CardContent>
<Button>Save</Button>
</CardContent>
</Card>
)
}Theming
Token Override
:root {
--wblo-ui-theme-primary: 210 92% 52%;
--wblo-ui-theme-primary-foreground: 0 0% 100%;
--wblo-ui-theme-background: 210 33% 98%;
--wblo-ui-theme-foreground: 222 26% 14%;
}Dark Mode
Dark mode is active when one of these is present:
:root[data-wblo-ui-theme="dark"].wblo-ui-dark.dark
document.documentElement.setAttribute("data-wblo-ui-theme", "dark")Font Utilities
font-ui-main, font-ui-latin, font-ui-greek, font-ui-arabic, font-ui-persian, font-ui-cyrillic, font-ui-mono
:root {
--font-main: "Plus Jakarta Sans", sans-serif;
--font-persian: "Vazir", sans-serif;
}Component Catalog (Complete Export List)
The package exports everything below from @wblo/ui:
Components
alertaction-iconavatar-image-uploadavatarbadgebuttoncalendarcardcheckboxchoice-cardscomboboxcommandcountry-flagdialogdate-pickerdropzonedropdown-menudynamic-item-listfieldfile-uploadformform-stepsinputinput-groupinput-stylesjalali-date-pickerlabellazy-comboboxmeta-paginationmultilingual-inputnotifications-popoverpopoverpaginationradio-grouprich-editorrich-sonnerscroll-areaselectselected-file-chipsegmented-tabsskeletonslidersticky-footerswitchtabletoggletooltiptextareaupload-dropzone
Utilities
cnfromlib/cnsanitizeSimpleHtmlfromlib/sanitize-simple-html
Usage Examples
Basic Form Row
import { FormItem, FormLabel, Input, FormDescription } from "@wblo/ui"
<FormItem>
<FormLabel>Email</FormLabel>
<Input placeholder="[email protected]" />
<FormDescription>We only use this for account updates.</FormDescription>
</FormItem>Select + Combobox
import { Select, SelectTrigger, SelectValue, SelectContent, SelectItem, LazyCombobox } from "@wblo/ui"
<Select defaultValue="active">
<SelectTrigger><SelectValue placeholder="Status" /></SelectTrigger>
<SelectContent>
<SelectItem value="active">Active</SelectItem>
<SelectItem value="paused">Paused</SelectItem>
</SelectContent>
</Select>
<LazyCombobox
value=""
onValueChange={() => {}}
options={[{ value: "1", label: "Workspace A" }]}
placeholder="Choose workspace"
searchPlaceholder="Search..."
emptyText="No result"
/>Date Controls
import { DatePickerInput, DateRangePicker, JalaliDatePickerInput } from "@wblo/ui"
<DatePickerInput value={undefined} onValueChange={() => {}} />
<DateRangePicker value={undefined} onValueChange={() => {}} />
<JalaliDatePickerInput value={undefined} onValueChange={() => {}} />Dialog + Tooltip + Popover
import { Dialog, DialogTrigger, DialogContent, Button, Tooltip, TooltipTrigger, TooltipContent } from "@wblo/ui"
<Dialog>
<DialogTrigger render={<Button>Open</Button>} />
<DialogContent>
<p>Dialog body</p>
</DialogContent>
</Dialog>
<Tooltip>
<TooltipTrigger render={<Button variant="outline">Hover me</Button>} />
<TooltipContent>Tooltip content</TooltipContent>
</Tooltip>Table + Pagination
import { Table, TableHeader, TableBody, TableRow, TableHead, TableCell, MetaPagination } from "@wblo/ui"
<Table>
<TableHeader>
<TableRow>
<TableHead>Name</TableHead>
<TableHead>Status</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>Release pipeline</TableCell>
<TableCell>Healthy</TableCell>
</TableRow>
</TableBody>
</Table>
<MetaPagination
meta={{ currentPage: 1, lastPage: 5, perPage: 20, total: 100 }}
previousText="Previous"
nextText="Next"
onPageChange={() => {}}
/>Uploads
import { UploadDropzone } from "@wblo/ui"
<UploadDropzone
description="Drop files here"
browseLabel="Browse"
emptyLabel="No files selected"
uploadErrorMessage="Upload failed"
removeSelectedFileAriaLabel="Remove file"
onUploadFile={async () => undefined}
/>Rich Editor
import { RichEditor, RichEditorHtmlPreview } from "@wblo/ui"
<RichEditor initialValue="<p>Hello</p>" onValueChange={(html) => {}} />
<RichEditorHtmlPreview value="<p>Preview</p>" />Notifications and Toast
import { showSemanticSonner, NotificationsPopover, Button } from "@wblo/ui"
showSemanticSonner({
type: "success",
title: "Saved",
message: "All changes are live.",
})
<NotificationsPopover
trigger={<Button variant="outline">Notifications</Button>}
title="Latest updates"
items={[]}
/>Helpers
import { cn, sanitizeSimpleHtml } from "@wblo/ui"
const cls = cn("px-2", true && "text-sm")
const safe = sanitizeSimpleHtml("<p>Hello <script>alert(1)</script></p>")Local Development
pnpm --filter @wblo/ui typecheck
pnpm --filter @wblo/ui build
pnpm storybookPublish
cd packages/ui
npm version patch
npm login
npm publish --access publicFor private scoped publish:
npm publish --access restrictedSecurity Note
Never commit npm auth tokens in .npmrc.
Use user-level npm auth locally and CI secrets in pipelines.
