npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@thanghm/ui-component

v1.0.4

Published

Internal UI component library built with React, TypeScript, and TailwindCSS

Readme

Hướng dẫn sử dụng các Component

Demo (Xem bản demo trên Netlify)

Mục lục

SmartTable

SmartTable là một component bảng thông minh với các tính năng như tìm kiếm, sắp xếp, phân trang, và nhiều hơn nữa.

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | endpoint | string \| (params: object) => Promise<{data: any[]; total: number}> | - | API endpoint hoặc function để fetch data | | columns | TableColumn[] | - | Cấu hình các cột của bảng | | extraFilters | Record<string, any> | {} | Filters bổ sung từ bên ngoài | | pageSize | number | 10 | Số dòng hiển thị trên mỗi trang | | defaultSort | {field: string; order: 'asc' \| 'desc'} | - | Cấu hình sắp xếp mặc định | | className | string | - | CSS class bổ sung |

Ví dụ sử dụng

Cơ bản với API JSONPlaceholder

import { SmartTable } from '@HuynhManhThang/ui_component'

const columns = [
  { title: 'ID', dataIndex: 'id', sorter: true },
  { title: 'Name', dataIndex: 'name', sorter: true },
  { title: 'Email', dataIndex: 'email' },
]

function MyComponent() {
  return (
    <SmartTable
      endpoint="https://jsonplaceholder.typicode.com/posts"
      columns={columns}
      pageSize={10}
    />
  )
}

Với Custom Function

const fetchUsers = async (params: any) => {
  const response = await fetch('/api/users', {
    method: 'GET',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(params)
  })
  return response.json()
}

function MyComponent() {
  return (
    <SmartTable
      endpoint={fetchUsers}
      columns={columns}
      extraFilters={{ status: 'active' }}
      defaultSort={{ field: 'createdAt', order: 'desc' }}
    />
  )
}

Với Custom Render

const columns = [
  {
    title: 'Avatar',
    dataIndex: 'avatar',
    render: (value: string) => (
      <img src={value} alt="Avatar" className="w-10 h-10 rounded-full" />
    )
  },
  {
    title: 'Status',
    dataIndex: 'status',
    render: (value: string) => (
      <span className={`px-2 py-1 rounded text-xs ${
        value === 'active' ? 'bg-green-100 text-green-800' : 'bg-red-100 text-red-800'
      }`}>
        {value}
      </span>
    )
  }
]

Typography

Typography component dùng để định dạng văn bản.

Ví dụ sử dụng

import { Typography } from './Typography';

function MyComponent() {
  return (
    <Typography variant="h1">Tiêu đề chính</Typography>
  );
}

Card

Card component dùng để hiển thị nội dung trong một khung.

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | variant | string | 'default' | Kiểu dáng của card (default, outlined, elevated) | | padding | string | 'md' | Khoảng cách bên trong card |

Ví dụ sử dụng

Default

import { Card } from './Card';

function MyComponent() {
  return (
    <Card>
      <p>This is a simple card with default styling.</p>
    </Card>
  );
}

Outlined

import { Card } from './Card';

function MyComponent() {
  return (
    <Card variant="outlined">
      <p>This is an outlined card with a more prominent border.</p>
    </Card>
  );
}

Elevated

import { Card } from './Card';

function MyComponent() {
  return (
    <Card variant="elevated">
      <p>This is an elevated card with shadow for depth.</p>
    </Card>
  );
}

With Header and Footer

import { Card, CardHeader, CardBody, CardFooter } from './Card';

function MyComponent() {
  return (
    <Card className="w-80">
      <CardHeader>
        <h3 className="text-lg font-semibold text-gray-900">Card Title</h3>
        <p className="text-sm text-gray-600">Subtitle or description</p>
      </CardHeader>
      <CardBody>
        <p className="text-gray-700">
          This is the main content of the card. It can contain any kind of content
          like text, images, buttons, or other components.
        </p>
      </CardBody>
      <CardFooter>
        <div className="flex justify-end space-x-2">
          <Button variant="ghost" size="sm">Cancel</Button>
          <Button variant="primary" size="sm">Save</Button>
        </div>
      </CardFooter>
    </Card>
  );
}

Input

Input component dùng để nhập dữ liệu.

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | variant | string | 'default' | Kiểu dáng của input (default, error, success) | | size | string | 'md' | Kích thước của input (sm, md, lg) |

Ví dụ sử dụng

Default

import { Input } from './Input';

function MyComponent() {
  return (
    <Input placeholder="Enter text..." />
  );
}

With Label

import { Input } from './Input';

function MyComponent() {
  return (
    <Input label="Email Address" placeholder="Enter your email..." type="email" />
  );
}

With Helper Text

import { Input } from './Input';

function MyComponent() {
  return (
    <Input label="Username" placeholder="Enter username..." helperText="Must be at least 3 characters long" />
  );
}

With Error

import { Input } from './Input';

function MyComponent() {
  return (
    <Input label="Password" placeholder="Enter password..." type="password" error="Password must be at least 8 characters" />
  );
}

Alert

Alert component dùng để hiển thị thông báo.

Ví dụ sử dụng

import { Alert } from './Alert';

function MyComponent() {
  return (
    <Alert type="success">Thành công!</Alert>
  );
}

Button

Button component dùng để thực hiện hành động khi người dùng nhấn vào.

Props

| Prop | Type | Default | Description | |------|------|---------|-------------| | variant | string | 'primary' | Kiểu dáng của button (primary, secondary, outline, ghost, danger) | | size | string | 'md' | Kích thước của button (sm, md, lg) |

Ví dụ sử dụng

Primary

import { Button } from './Button';

function MyComponent() {
  return (
    <Button variant="primary">Primary Button</Button>
  );
}

Secondary

import { Button } from './Button';

function MyComponent() {
  return (
    <Button variant="secondary">Secondary Button</Button>
  );
}

Outline

import { Button } from './Button';

function MyComponent() {
  return (
    <Button variant="outline">Outline Button</Button>
  );
}

Ghost

import { Button } from './Button';

function MyComponent() {
  return (
    <Button variant="ghost">Ghost Button</Button>
  );
}

Danger

import { Button } from './Button';

function MyComponent() {
  return (
    <Button variant="danger">Danger Button</Button>
  );
}

With Icon

import { Button } from './Button';

function MyComponent() {
  return (
    <Button icon={<SampleIcon />}>Button with Icon</Button>
  );
}