
Security News
Attackers Are Hunting High-Impact Node.js Maintainers in a Coordinated Social Engineering Campaign
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.
@dsbtek/component-library
Advanced tools
A collection of advanced React components built with TypeScript, Tailwind CSS, and shadcn/ui.
npm install @dsbtek/component-library
npm install react@^18 react-dom@^18
npm install -D tailwindcss postcss autoprefixer
npx tailwindcss init -p
tailwind.config.js:/** @type {import('tailwindcss').Config} */
module.exports = {
darkMode: ['class'],
content: [
'./src/**/*.{js,ts,jsx,tsx}',
'./node_modules/@dsbtek/component-library/**/*.{js,ts,jsx,tsx}',
],
theme: {
extend: {
colors: {
border: 'hsl(var(--border))',
input: 'hsl(var(--input))',
ring: 'hsl(var(--ring))',
background: 'hsl(var(--background))',
foreground: 'hsl(var(--foreground))',
primary: {
DEFAULT: 'hsl(var(--primary))',
foreground: 'hsl(var(--primary-foreground))',
},
secondary: {
DEFAULT: 'hsl(var(--secondary))',
foreground: 'hsl(var(--secondary-foreground))',
},
destructive: {
DEFAULT: 'hsl(var(--destructive))',
foreground: 'hsl(var(--destructive-foreground))',
},
muted: {
DEFAULT: 'hsl(var(--muted))',
foreground: 'hsl(var(--muted-foreground))',
},
accent: {
DEFAULT: 'hsl(var(--accent))',
foreground: 'hsl(var(--accent-foreground))',
},
popover: {
DEFAULT: 'hsl(var(--popover))',
foreground: 'hsl(var(--popover-foreground))',
},
card: {
DEFAULT: 'hsl(var(--card))',
foreground: 'hsl(var(--card-foreground))',
},
},
borderRadius: {
lg: 'var(--radius)',
md: 'calc(var(--radius) - 2px)',
sm: 'calc(var(--radius) - 4px)',
},
},
},
plugins: [require('tailwindcss-animate')],
};
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--primary: 222.2 47.4% 11.2%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 222.2 84% 4.9%;
--radius: 0.5rem;
/* Sidebar Variables */
--sidebar-background: 0 0% 98%;
--sidebar-foreground: 240 5.3% 26.1%;
--sidebar-primary: 240 5.9% 10%;
--sidebar-primary-foreground: 0 0% 98%;
--sidebar-accent: 240 4.8% 95.9%;
--sidebar-accent-foreground: 240 5.9% 10%;
--sidebar-border: 220 13% 91%;
--sidebar-ring: 217.2 91.2% 59.8%;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--card: 222.2 84% 4.9%;
--card-foreground: 210 40% 98%;
--popover: 222.2 84% 4.9%;
--popover-foreground: 210 40% 98%;
--primary: 210 40% 98%;
--primary-foreground: 222.2 47.4% 11.2%;
--secondary: 217.2 32.6% 17.5%;
--secondary-foreground: 210 40% 98%;
--muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%;
--accent: 217.2 32.6% 17.5%;
--accent-foreground: 210 40% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%;
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;
--ring: 212.7 26.8% 83.9%;
/* Sidebar Variables - Dark Mode */
--sidebar-background: 240 5.9% 10%;
--sidebar-foreground: 240 4.8% 95.9%;
--sidebar-primary: 0 0% 98%;
--sidebar-primary-foreground: 240 5.9% 10%;
--sidebar-accent: 240 3.7% 15.9%;
--sidebar-accent-foreground: 240 4.8% 95.9%;
--sidebar-border: 240 3.7% 15.9%;
--sidebar-ring: 217.2 91.2% 59.8%;
}
}
A flexible, customizable sidebar component with navigation, search, team switching, and user profile features. Built on top of the shadcn/ui Sidebar primitives.
| Prop | Type | Default | Description |
|---|---|---|---|
| teams | Team[] | [] | Array of teams for the team switcher |
| defaultTeam | Team | - | Default selected team |
| onTeamChange | (team: Team) => void | - | Callback when team selection changes |
| onSearch | (query: string) => void | - | Callback when search query changes |
| searchPlaceholder | string | "Search..." | Placeholder text for search input |
| navItems | NavItem[] | Required | Array of navigation items |
| navGroupLabel | string | "Navigation" | Label for the main navigation group |
| navSecondary | { title: string; url: string; icon: LucideIcon; onClick?: () => void }[] | [] | Array of secondary navigation items |
| navSecondaryLabel | string | - | Label for the secondary navigation group |
| user | User | - | User data for the profile section |
| onLogout | () => void | - | Callback when logout is clicked |
| userMenuItems | { group: string; items: { label: string; icon: React.ComponentType<{ className?: string }>; onClick?: () => void }[] }[] | - | Custom menu items for user dropdown |
| isLoading | boolean | false | Loading state for all sidebar components |
| variant | `"sidebar" | "floating" | "inset"` |
| collapsible | `"offcanvas" | "icon" | "none"` |
| side | `"left" | "right"` | "left" |
| defaultOpen | boolean | true | Default open state of the sidebar |
| open | boolean | - | Controlled open state |
| onOpenChange | (open: boolean) => void | - | Callback when open state changes |
| ...props | React.ComponentProps<typeof Sidebar> | - | All props from shadcn Sidebar component |
The SidebarProvider is a context provider that manages the state of the sidebar. It's automatically included in the AppSidebar component, but can also be used separately for more advanced use cases.
| Prop | Type | Default | Description |
|---|---|---|---|
| children | React.ReactNode | Required | Child components |
| defaultOpen | boolean | true | Default open state of the sidebar |
| open | boolean | - | Controlled open state |
| onOpenChange | (open: boolean) => void | - | Callback when open state changes |
The useSidebar hook provides access to the sidebar context. It returns an object with the following properties:
| Property | Type | Description
|-----|-----|-----|-----
| state | "expanded" | "collapsed" | Current state of the sidebar
| open | boolean | Whether the sidebar is open
| setOpen | (open: boolean) => void | Function to set the open state
| openMobile | boolean | Whether the mobile sidebar is open
| setOpenMobile | (open: boolean) => void | Function to set the mobile open state
| isMobile | boolean | Whether the current device is mobile
| toggleSidebar | () => void | Function to toggle the sidebar open/closed
import { AppSidebar } from '@dsbtek/component-library';
import { Home, Settings, Users, HelpCircle, LogOut } from 'lucide-react';
function SidebarExample() {
const navItems = [
{
title: "Dashboard",
url: "/dashboard",
icon: Home,
isActive: true
},
{
title: "Settings",
url: "/settings",
icon: Settings,
items: [
{ title: "Profile", url: "/settings/profile" },
{ title: "Account", url: "/settings/account" },
{ title: "Preferences", url: "/settings/preferences" }
]
},
{
title: "Users",
url: "/users",
icon: Users
}
];
const teams = [
{ name: "Acme Inc", logo: Users, plan: "Pro" },
{ name: "Personal", logo: Home, plan: "Free" }
];
const secondaryNav = [
{ title: "Help", url: "/help", icon: HelpCircle }
];
const user = {
name: "John Doe",
email: "john@example.com",
image: "/avatar.jpg"
};
return (
<div className="flex h-screen">
<AppSidebar
teams={teams}
defaultTeam={teams[0]}
onTeamChange={(team) => console.log("Team changed:", team)}
onSearch={(query) => console.log("Search:", query)}
searchPlaceholder="Search..."
navItems={navItems}
navGroupLabel="Main Navigation"
navSecondary={secondaryNav}
navSecondaryLabel="Support"
user={user}
onLogout={() => console.log("Logout clicked")}
userMenuItems={[
{
group: "Account",
items: [
{
label: "Settings",
icon: Settings,
onClick: () => console.log("Settings clicked")
},
{
label: "Logout",
icon: LogOut,
onClick: () => console.log("Logout clicked")
}
]
}
]}
defaultOpen={true}
collapsible="icon"
variant="sidebar"
/>
<main className="flex-1 p-6">
<h1 className="text-2xl font-bold">Dashboard</h1>
{/* Your page content */}
</main>
</div>
);
}
For more advanced use cases, you can use the SidebarProvider and sidebar components separately:
import {
SidebarProvider,
useSidebar,
NavProjects,
NavMain,
NavUser
} from '@dsbtek/component-library';
import { Home, Settings, Users } from 'lucide-react';
function CustomSidebar() {
const navItems = [
{ title: "Dashboard", url: "/dashboard", icon: Home },
{ title: "Settings", url: "/settings", icon: Settings },
{ title: "Users", url: "/users", icon: Users }
];
const projects = [
{ name: "Project A", url: "/projects/a", icon: Home },
{ name: "Project B", url: "/projects/b", icon: Settings }
];
const user = {
name: "John Doe",
email: "john@example.com"
};
return (
<SidebarProvider defaultOpen={true}>
<div className="flex h-screen">
<div className="w-64 bg-sidebar text-sidebar-foreground">
<NavMain items={navItems} groupLabel="Navigation" />
<NavProjects projects={projects} groupLabel="Projects" />
<NavUser user={user} onLogout={() => console.log("Logout")} />
</div>
<main className="flex-1 p-6">
<SidebarToggleButton />
<h1 className="text-2xl font-bold">Dashboard</h1>
{/* Your page content */}
</main>
</div>
</SidebarProvider>
);
}
// Custom toggle button using the useSidebar hook
function SidebarToggleButton() {
const { toggleSidebar, state } = useSidebar();
return (
<button
onClick={toggleSidebar}
className="p-2 rounded-md bg-primary text-primary-foreground"
>
{state === "expanded" ? "Collapse" : "Expand"} Sidebar
</button>
);
}
A navigation component that helps users understand their current location within a website's hierarchy.
| Prop | Type | Default | Description |
|---|---|---|---|
| segments | Array<{ label: string; href?: string }> | Required | Array of breadcrumb segments |
| separator | React.ReactNode | <ChevronRight className="h-4 w-4" /> | Custom separator between breadcrumb items |
| className | string | - | Additional CSS classes |
| onNavigate | (href: string) => void | - | Callback function when a breadcrumb is clicked |
import { Breadcrumbs } from '@dsbtek/component-library';
function BreadcrumbsExample() {
return (
<Breadcrumbs
segments={[
{ label: 'Home', href: '/' },
{ label: 'Products', href: '/products' },
{ label: 'Electronics', href: '/products/electronics' },
{ label: 'Smartphones' },
]}
onNavigate={(href) => console.log(`Navigating to: ${href}`)}
/>
);
}
A comprehensive color selection component with RGB, HSL support, color schemes, and history.
| Prop | Type | Default | Description |
|---|---|---|---|
| color | string | #000000 | Current color value in hex format |
| onChange | (value: string) => void | - | Callback function when color changes |
| className | string | - | Additional CSS classes |
import { ColorPicker } from '@dsbtek/component-library';
import { useState } from 'react';
function ColorPickerExample() {
const [color, setColor] = useState('#3B82F6');
return (
<ColorPicker
color={color}
onChange={setColor}
/>
);
}
A feature-rich table component with sorting, filtering, pagination, and more.
| Prop | Type | Default | Description |
|---|---|---|---|
| data | T[] | Required | Array of data items |
| columns | ColumnDef<T>[] | Required | Array of column definitions |
| meta | { current_page: number; last_page: number; per_page: number; total: number } | - | Pagination metadata |
| loading | boolean | false | Loading state of the table |
| onPageChange | (page: number) => void | - | Callback when page changes |
| onPerPageChange | (perPage: number) => void | - | Callback when items per page changes |
| onSort | `(column: string, direction: 'asc' | 'desc' | null) => void` |
| onSearch | (value: string) => void | - | Callback when search value changes |
| onFilter | (filters: AdvancedFilter[]) => void | - | Callback when filters change |
| pageSizeOptions | number[] | [10,20,50] | Available options for items per page |
| renderItemActions | (row: T) => React.ReactNode | - | Function to render action buttons for each row |
| features | Partial<DataTableFeatures> | - | Object to enable/disable various table features |
import { DataTable } from '@dsbtek/component-library';
function DataTableExample() {
const columns = [
{ accessorKey: 'name', header: 'Name' },
{ accessorKey: 'email', header: 'Email' },
{ accessorKey: 'role', header: 'Role' },
];
const data = [
{ id: '1', name: 'John Doe', email: 'john@example.com', role: 'Admin' },
{ id: '2', name: 'Jane Smith', email: 'jane@example.com', role: 'User' },
// ... more data
];
return (
<DataTable
data={data}
columns={columns}
features={{
sorting: true,
pagination: true,
search: true,
}}
onPageChange={(page) => console.log(`Page changed to ${page}`)}
onSort={(column, direction) => console.log(`Sorting ${column} ${direction}`)}
/>
);
}
A versatile date and time selection component with support for ranges, time-only, and date-only modes.
| Prop | Type | Default | Description |
|---|---|---|---|
| date | `DateValue | DateRange | undefined |
| setDate | `(date: DateValue | DateRange | undefined) => void` |
| isRange | boolean | false | Enable date range selection |
| includeTime | boolean | true | Include time selection |
| dateOnly | boolean | false | Show date picker only |
| timeOnly | boolean | false | Show time picker only |
| minDate | Date | - | Minimum selectable date |
| maxDate | Date | - | Maximum selectable date |
| disabledDates | Date[] | - | Array of disabled dates |
| clearable | boolean | true | Allow clearing the selection |
| disabled | boolean | false | Disable the input |
import { DateTimePicker } from '@dsbtek/component-library';
import { useState } from 'react';
function DateTimePickerExample() {
const [date, setDate] = useState<Date | undefined>(new Date());
return (
<DateTimePicker
date={date}
setDate={setDate}
includeTime={true}
/>
);
}
A file upload component with drag and drop support, previews, and progress indication.
| Prop | Type | Default | Description |
|---|---|---|---|
| value | FileWithPreview[] | - | Array of selected files |
| onChange | (files: FileWithPreview[]) => void | Required | Callback when files change |
| multiple | boolean | false | Allow multiple file selection |
| accept | Record<string, string[]> | { "image/*": [".png", ".jpg", ".jpeg", ".gif"], "application/pdf": [".pdf"] } | Accepted file types |
| maxSize | number | 2MB | Maximum file size in bytes |
| maxFiles | number | 5 | Maximum number of files |
| disabled | boolean | false | Disable the input |
| loading | boolean | false | Show loading state |
| progress | `number | number[]` | - |
| onRemove | (file: FileWithPreview) => void | - | Callback when a file is removed |
import { FileInput } from '@dsbtek/component-library';
import { useState } from 'react';
function FileInputExample() {
const [files, setFiles] = useState([]);
return (
<FileInput
value={files}
onChange={setFiles}
multiple={true}
maxSize={5 * 1024 * 1024} // 5MB
/>
);
}
A flexible select component that supports single or multiple selection with grouping, search, and responsive behavior.
| Prop | Type | Default | Description |
|---|---|---|---|
| options | OptionType[] | Required | Array of selectable options with format {label: string, value: string, group?: string} |
| selected | string[] | Required | Array of selected option values |
| onChange | (value: string[]) => void | Required | Callback when selection changes |
| placeholder | string | "Select..." | Placeholder text |
| className | string | - | Additional CSS classes for the main component |
| multiple | boolean | false | Allow multiple selection |
| onLoadMore | () => void | - | Callback for infinite loading |
| hasMore | boolean | false | Indicates if more options can be loaded |
| isDialog | boolean | false | Use dialog instead of drawer on mobile |
| triggerClassName | string | - | Custom class for the trigger button |
| contentClassName | string | - | Custom class for the dropdown content |
| badgeClassName | string | - | Custom class for the selected item badges |
| commandClassName | string | - | Custom class for the command component |
| commandInputClassName | string | - | Custom class for the search input |
| commandListClassName | string | - | Custom class for the options list |
| commandItemClassName | string | - | Custom class for individual option items |
| commandEmptyClassName | string | - | Custom class for the empty state |
| commandGroupClassName | string | - | Custom class for option groups |
| commandSeparatorClassName | string | - | Custom class for group separators |
| align | "start" | "center" | "end" | "start" | Alignment of the dropdown relative to the trigger |
| sideOffset | number | 5 | Offset from the trigger |
| width | "auto" | "trigger" | string | "trigger" | Width of the dropdown content |
import { MultiSelect } from '@dsbtek/component-library';
import { useState } from 'react';
function MultiSelectExample() {
const [selected, setSelected] = useState(['react']);
const options = [
{ label: 'React', value: 'react', group: 'Frontend' },
{ label: 'Vue', value: 'vue', group: 'Frontend' },
{ label: 'Angular', value: 'angular', group: 'Frontend' },
{ label: 'Node.js', value: 'nodejs', group: 'Backend' },
{ label: 'Express', value: 'express', group: 'Backend' },
];
return (
<MultiSelect
options={options}
selected={selected}
onChange={setSelected}
placeholder="Select technologies..."
multiple={true}
className="w-[350px]"
badgeClassName="bg-blue-100 text-blue-800"
/>
);
}
A comprehensive multi-step form component with navigation, validation, and customizable steps.
| Prop | Type | Default | Description |
|---|---|---|---|
| context | React.Context<UseMultiStepFormTypeOptions<T>> | Required | Context created with buildMultiStepForm |
| previousLabel | string | "Previous" | Label for the previous button |
| nextLabel | string | "Next" | Label for the next button |
| endStepLabel | string | "Submit" | Label for the submit button |
| showNavbar | boolean | true | Show the step navigation bar |
| showButtons | boolean | true | Show the navigation buttons |
| isLoading | boolean | false | Loading state for the submit button |
| className | string | "" | Additional CSS classes |
| debug | boolean | false | Show debug information |
| Function | Description |
|---|---|
| buildMultiStepForm | Creates a context and provider for a multi-step form |
| useMultiStepForm | Hook for accessing multi-step form functionality |
import {
buildMultiStepForm,
useMultiStepForm,
Form
} from '@dsbtek/component-library';
import { z } from 'zod';
import { useForm, FormProvider, useFormContext } from 'react-hook-form';
import {
FormField,
FormItem,
FormLabel,
FormControl,
FormMessage
} from '@/components/ui/form';
import { Input } from '@/components/ui/input';
import { PasswordInput } from '@dsbtek/component-library';
import { MultiSelect } from '@dsbtek/component-library';
import { FileInput } from '@dsbtek/component-library';
// Define your form schema
export const signupSchema = z.object({
name: z.string().min(2, "Name must be at least 2 characters"),
email: z.string().email("Please enter a valid email"),
phone: z.string().min(10, "Please enter a valid phone number"),
password: z.string().min(8, "Password must be at least 8 characters"),
password_confirmation: z.string(),
roles: z.array(z.string()),
permissions: z.array(z.string()),
image: z.any().optional(),
}).refine((data) => data.password === data.password_confirmation, {
message: "Passwords do not match",
path: ["password_confirmation"],
});
// Step 1: Basic Information
export function Step1() {
const { control } = useFormContext();
return (
<>
<FormField
control={control}
name="name"
render={({ field }) => (
<FormItem>
<FormLabel>Name</FormLabel>
<FormControl>
<Input placeholder="Enter your name" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={control}
name="email"
render={({ field }) => (
<FormItem>
<FormLabel>Email</FormLabel>
<FormControl>
<Input placeholder="Enter your email" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={control}
name="phone"
render={({ field }) => (
<FormItem>
<FormLabel>Phone</FormLabel>
<FormControl>
<Input placeholder="Enter your phone number" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</>
);
}
// Step 2: Security
export function Step2() {
const { control } = useFormContext();
return (
<>
<FormField
control={control}
name="password"
render={({ field }) => (
<FormItem>
<FormLabel>Password</FormLabel>
<FormControl>
<PasswordInput placeholder="Enter your password" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={control}
name="password_confirmation"
render={({ field }) => (
<FormItem>
<FormLabel>Confirm Password</FormLabel>
<FormControl>
<PasswordInput placeholder="Confirm your password" {...field} />
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</>
);
}
// Step 3: Roles & Permissions
export function Step3() {
const { control } = useFormContext();
const roleOptions = [
{ label: 'Admin', value: 'admin' },
{ label: 'User', value: 'user' },
{ label: 'Editor', value: 'editor' },
];
const permissionOptions = [
{ label: 'Create', value: 'create', group: 'Content' },
{ label: 'Edit', value: 'edit', group: 'Content' },
{ label: 'Delete', value: 'delete', group: 'Content' },
{ label: 'View Users', value: 'view_users', group: 'Users' },
{ label: 'Manage Users', value: 'manage_users', group: 'Users' },
];
return (
<>
<FormField
control={control}
name="roles"
render={({ field }) => (
<FormItem>
<FormLabel>Roles</FormLabel>
<FormControl>
<MultiSelect
options={roleOptions}
selected={field.value || []}
onChange={field.onChange}
placeholder="Select roles"
multiple={true}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
<FormField
control={control}
name="permissions"
render={({ field }) => (
<FormItem>
<FormLabel>Permissions</FormLabel>
<FormControl>
<MultiSelect
options={permissionOptions}
selected={field.value || []}
onChange={field.onChange}
placeholder="Select permissions"
multiple={true}
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
</>
);
}
// Step 4: Profile Picture
export function Step4() {
const { control } = useFormContext();
return (
<FormField
control={control}
name="image"
render={({ field }) => (
<FormItem>
<FormLabel>Profile Picture</FormLabel>
<FormControl>
<FileInput
value={field.value || []}
onChange={field.onChange}
accept={{ "image/*": [".png", ".jpg", ".jpeg"] }}
maxSize={2 * 1024 * 1024} // 2MB
/>
</FormControl>
<FormMessage />
</FormItem>
)}
/>
);
}
//Sign Up Step Config
import React from 'react'
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle
} from '@/components/ui/card'
import { Social } from '@/components/auth/social'
import { BackButton } from '@/components/auth/back-button'
import { cn } from "@/lib/utils"
interface AuthWrapperProps {
children: React.ReactNode
headerTitle: string
headerDescription: string
backButtonLabel: string
backLinkLabel: string
backButtonHref: string
enableSocial: boolean
onSocialLogin: (provider: string) => void
showGoogle?: boolean
showFacebook?: boolean
showApple?: boolean
showGithub?: boolean
showSlack?: boolean
showX?: boolean
showLinkedin?: boolean
showMicrosoft?: boolean
className?: string
contentClassName?: string
width?: string;
}
export function AuthWrapper({
children,
headerTitle,
headerDescription,
backButtonLabel,
backLinkLabel,
backButtonHref,
enableSocial,
onSocialLogin,
className,
contentClassName,
width = "w-[350px]",
...socialProps
}: AuthWrapperProps) {
return (
<Card className={cn(width, className)}>
<CardHeader className="space-y-1">
<CardTitle>{headerTitle}</CardTitle>
<CardDescription>{headerDescription}</CardDescription>
</CardHeader>
<CardContent className={cn(contentClassName)}>{children}</CardContent>
<CardFooter className="flex flex-col items-center gap-4">
{enableSocial && (
<Social onSocialLogin={onSocialLogin} {...socialProps} />
)}
<BackButton
backLinkLabel={backLinkLabel}
label={backButtonLabel}
href={backButtonHref}
/>
</CardFooter>
</Card>
)
}
// Use the Sign Up Dorm
"use client";
import {containerSignUpForm as container} from "@/constants/framer-motion";
import {useMultiStepForm, MultiStepNavbar, MultiStepNavButtons} from "@smartflowssbu/component-pack";
import {motion} from "framer-motion";
import MultiStepForm from "@/app/(auth)/signup/_components/multi-step-form";
import {SignUpFormContext} from "@/app/(auth)/signup/_components/signup-step-config";
export default function SignUpForm() {
const {CurrentForm} = useMultiStepForm(SignUpFormContext);
return (
<MultiStepForm title="Sign up" description="Create an account to get started">
<MultiStepNavbar context={SignUpFormContext}/>
<div className="flex-1">
<motion.div variants={container} className="space-y-6" initial="hidden" animate="visible" exit="exit">
<CurrentForm/>
</motion.div>
<MultiStepNavButtons
context={SignUpFormContext}
previousLabel="Previous"
nextLabel="Next"
endStepLabel="Submit"
/>
</div>
</MultiStepForm>
);
};
//Use the Multi Step Form
"use client";
import {containerMultiStepForm as container} from "@/constants/framer-motion";
import {useMultiStepForm} from "@/hooks/multi-step-form";
import {motion} from "framer-motion";
import {Form} from "@/components/ui/form";
import React, {PropsWithChildren} from "react";
import {SignUpFormContext} from "@/app/(auth)/signup/_components/signup-step-config";
import {AuthWrapper} from "@/components/auth/auth-wrapper";
interface Props extends PropsWithChildren {
title: string;
description: string;
}
const MultiStepForm = ({title, description, children}: Props) => {
const {form, onSubmit, onErrors} = useMultiStepForm(SignUpFormContext);
function handleSocialLogin(provider: string) {
// Implement social signin logic here
console.log(Social login with ${provider})
}
return (
<Form {...form}>
<form onSubmit={form?.handleSubmit(onSubmit, onErrors)}>
<motion.div
variants={container}
className="flex flex-col gap-2"
initial="hidden"
animate="visible"
exit="exit"
>
<AuthWrapper
headerTitle={title}
headerDescription={description}
backButtonLabel='Already have an account?'
backLinkLabel='Sign in'
backButtonHref='/signin'
enableSocial={false}
onSocialLogin={handleSocialLogin}
width='w-[500px]'
contentClassName='flex flex-col sm:flex-row gap-2 p-2 m-2'>
{children}
</AuthWrapper>
</motion.div>
</form>
</Form>
);
};
export default MultiStepForm;
//Use Auth Wrapper
import React from 'react'
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle
} from '@/components/ui/card'
import { Social } from '@/components/auth/social'
import { BackButton } from '@/components/auth/back-button'
import { cn } from "@/lib/utils"
interface AuthWrapperProps {
children: React.ReactNode
headerTitle: string
headerDescription: string
backButtonLabel: string
backLinkLabel: string
backButtonHref: string
enableSocial: boolean
onSocialLogin: (provider: string) => void
showGoogle?: boolean
showFacebook?: boolean
showApple?: boolean
showGithub?: boolean
showSlack?: boolean
showX?: boolean
showLinkedin?: boolean
showMicrosoft?: boolean
className?: string
contentClassName?: string
width?: string;
}
export function AuthWrapper({
children,
headerTitle,
headerDescription,
backButtonLabel,
backLinkLabel,
backButtonHref,
enableSocial,
onSocialLogin,
className,
contentClassName,
width = "w-[350px]",
...socialProps
}: AuthWrapperProps) {
return (
<Card className={cn(width, className)}>
<CardHeader className="space-y-1">
<CardTitle>{headerTitle}</CardTitle>
<CardDescription>{headerDescription}</CardDescription>
</CardHeader>
<CardContent className={cn(contentClassName)}>{children}</CardContent>
<CardFooter className="flex flex-col items-center gap-4">
{enableSocial && (
<Social onSocialLogin={onSocialLogin} {...socialProps} />
)}
<BackButton
backLinkLabel={backLinkLabel}
label={backButtonLabel}
href={backButtonHref}
/>
</CardFooter>
</Card>
)
}
//Multi Ster SignUp Form
"use client";
import {SignUpProvider} from "@/app/(auth)/signup/_components/signup-step-config";
import SignUpForm from "@/app/(auth)/signup/_components/form/signup-form";
export default function MultiStepSignUp () {
return (
<SignUpProvider>
<SignUpForm />
</SignUpProvider>
);
};
//back button
import Link from 'next/link'
interface BackButtonProps {
label: string
href: string
backLinkLabel: string
}
export function BackButton({ backLinkLabel, label, href }: BackButtonProps) {
return (
<div className="text-sm text-muted-foreground text-center w-full">
{label}{' '}
<Link href={href} className="text-primary underline-offset-4 hover:underline">
{backLinkLabel}
</Link>
</div>
)
}
A password input component with show/hide functionality.
| Prop | Type | Default | Description |
|---|---|---|---|
| className | string | - | Additional CSS classes |
| showPasswordLabel | string | "Show password" | Screen reader label for show password button |
| hidePasswordLabel | string | "Hide password" | Screen reader label for hide password button |
| ...props | React.InputHTMLAttributes<HTMLInputElement> | - | All standard input props |
import { PasswordInput } from '@smartflowssbu/component-pack';
import { useState } from 'react';
function PasswordInputExample() {
const [password, setPassword] = useState('');
return (
<PasswordInput
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Enter your password"
/>
);
}
An international phone number input with country selection and validation.
| Prop | Type | Default | Description |
|---|---|---|---|
| value | string | - | Phone number value |
| defaultCountry | CountryCode | "US" | Default country code |
| ...props | React.ComponentPropsWithoutRef<'input'> | - | All standard input props |
import { PhoneInput, getPhoneData } from '@smartflowssbu/component-pack';
import { useState, useEffect } from 'react';
function PhoneInputExample() {
const [phone, setPhone] = useState('+1');
const [phoneData, setPhoneData] = useState(getPhoneData(phone));
useEffect(() => {
setPhoneData(getPhoneData(phone));
}, [phone]);
return (
<PhoneInput
value={phone}
onChange={(e) => setPhone(e.target.value)}
defaultCountry="US"
/>
);
}
An alert dialog component that adapts to desktop (modal) and mobile (drawer) views.
| Prop | Type | Default | Description |
|---|---|---|---|
| trigger | React.ReactNode | Required | Element that triggers the dialog |
| title | string | Required | Dialog title |
| description | string | Required | Dialog description |
| cancelText | string | "Cancel" | Text for the cancel button |
| confirmText | string | "Continue" | Text for the confirm button |
| onConfirm | () => void | Required | Callback when confirm button is clicked |
import { ResponsiveAlertDialog } from '@smartflowssbu/component-pack';
import { Button } from '@smartflowssbu/component-pack';
function AlertDialogExample() {
const handleDelete = () => {
console.log('Item deleted');
};
return (
<ResponsiveAlertDialog
trigger={<Button variant="destructive">Delete Item</Button>}
title="Are you sure?"
description="This action cannot be undone. This will permanently delete the item."
cancelText="Cancel"
confirmText="Delete"
onConfirm={handleDelete}
/>
);
}
A dialog component that adapts to desktop (modal) and mobile (drawer) views.
| Prop | Type | Default | Description |
|---|---|---|---|
| trigger | React.ReactNode | Required | Element that triggers the dialog |
| title | string | Required | Dialog title |
| description | string | Required | Dialog description |
| children | React.ReactNode | Required | Dialog content |
import { ResponsiveDialog } from '@smartflowssbu/component-pack';
import { Button } from '@smartflowssbu/component-pack';
function DialogExample() {
return (
<ResponsiveDialog
trigger={<Button>Open Dialog</Button>}
title="Edit Profile"
description="Make changes to your profile here."
>
<form className="space-y-4 pt-4">
<div className="space-y-2">
<label htmlFor="name">Name</label>
<input id="name" className="w-full p-2 border rounded" />
</div>
<div className="space-y-2">
<label htmlFor="email">Email</label>
<input id="email" type="email" className="w-full p-2 border rounded" />
</div>
<div className="flex justify-end space-x-2">
<Button type="button" variant="outline">Cancel</Button>
<Button type="submit">Save</Button>
</div>
</form>
</ResponsiveDialog>
);
}
A component for adding and managing tags with suggestions and validation.
| Prop | Type | Default | Description |
|---|---|---|---|
| placeholder | string | "Add tag..." | Placeholder text |
| tags | string[] | Required | Array of current tags |
| setTags | (tags: string[]) => void | Required | Callback when tags change |
| suggestions | string[] | [] | Array of tag suggestions |
| maxTags | number | - | Maximum number of tags allowed |
| disabled | boolean | false | Disable the input |
| error | string | - | Error message to display |
import { TagInput } from '@smartflowssbu/component-pack';
import { useState } from 'react';
function TagInputExample() {
const [tags, setTags] = useState(['react', 'typescript']);
const suggestions = [
'react', 'vue', 'angular', 'svelte', 'javascript',
'typescript', 'node', 'express', 'mongodb'
];
return (
<TagInput
tags={tags}
setTags={setTags}
suggestions={suggestions}
placeholder="Add technologies..."
/>
);
}
All components use Tailwind CSS for styling and can be customized using Tailwind classes. The components also respect the theme variables defined in your CSS.
<Breadcrumbs
className="text-blue-600 dark:text-blue-400"
segments={[
{ label: 'Home', href: '/' },
{ label: 'Products', href: '/products' },
{ label: 'Current Page' },
]}
/>
<ColorPicker
className="w-[300px] rounded-lg"
color="#3B82F6"
onChange={setColor}
/>
All components include full TypeScript support out of the box. Type definitions are automatically available when you import components.
Please read our Contributing Guide before submitting a Pull Request.
MIT © Smartflowtech Team
FAQs
Advanced components built with shadcn/ui
We found that @dsbtek/component-library demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
Multiple high-impact npm maintainers confirm they have been targeted in the same social engineering campaign that compromised Axios.

Security News
Axios compromise traced to social engineering, showing how attacks on maintainers can bypass controls and expose the broader software supply chain.

Security News
Node.js has paused its bug bounty program after funding ended, removing payouts for vulnerability reports but keeping its security process unchanged.