
Research
Malicious npm Packages Impersonate Flashbots SDKs, Targeting Ethereum Wallet Credentials
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
@qkit-emr/web-ui
Advanced tools
Thư viện UI component dùng chung cho hệ thống EMR (Electronic Medical Record) Monorepo, được xây dựng trên nền tảng React, TypeScript và Tailwind CSS với tích hợp shadcn/ui.
npm install @qkit-emr/web-ui
Có 2 cách import components:
import { Button, Card, Input, Badge } from '@qkit-emr/web-ui';
function App() {
return (
<div className="p-4">
<Card className="p-6">
<h2 className="text-xl font-bold mb-4">Quản lý bệnh nhân</h2>
<Input placeholder="Tìm kiếm bệnh nhân..." className="mb-4" />
<Button>Thêm bệnh nhân mới</Button>
</Card>
</div>
);
}
import { Button } from '@qkit-emr/web-ui/ui';
function App() {
return (
<Button variant="default" size="lg">
Click me
</Button>
);
}
Thêm preset vào file tailwind.config.js
:
module.exports = {
content: [
"./src/**/*.{js,ts,jsx,tsx}",
"./node_modules/@qkit-emr/web-ui/dist/**/*.{js,ts,jsx,tsx}",
],
presets: [require("@qkit-emr/web-ui/tailwind.preset")],
}
import '@qkit-emr/web-ui/styles';
import {
Button,
ButtonGroup,
ButtonGroupItem,
useButtonGroup,
Input,
InputAtom,
MemoizedInputAtom,
Label,
LabelAtom,
MemoizedLabelAtom,
Icon
} from '@qkit-emr/web-ui';
// Button với variants và medical-specific features
<Button variant="primary" size="md" medical>Khám bệnh</Button>
<ButtonGroup>
<ButtonGroupItem>Lưu</ButtonGroupItem>
<ButtonGroupItem>Hủy</ButtonGroupItem>
</ButtonGroup>
// Input với validation và medical masks
<Input placeholder="Nhập tên bệnh nhân" />
<InputAtom type="phone" mask="(999) 999-9999" />
// Label với accessibility
<Label htmlFor="patient-name">Họ và tên</Label>
// Icon với medical icon mapping
<Icon name="stethoscope" size="md" />
import {
// Data Display
BadgeAtom,
StatusBadgeAtom,
ProgressAtom,
TimelineAtom,
DataTableAtom,
// Form Controls
DatePickerAtom,
TimePickerAtom,
MultiSelectAtom,
RadioGroupAtom,
InputOTPAtom,
SecureInputAtom,
// UI Enhancement
ModalAtom,
DrawerAtom,
TabsAtom,
AccordionAtom,
TooltipAtom,
CarouselAtom,
// Medical-Specific
LabResultAtom,
// Utilities
SpinnerAtom as Spinner,
DividerAtom as Divider,
TypographyAtom as Typography,
FileInputAtom
} from '@qkit-emr/web-ui';
// Medical status badges
<StatusBadgeAtom status="critical" />
<StatusBadgeAtom status="stable" />
<StatusBadgeAtom status="discharged" />
// Progress indicators
<ProgressAtom value={75} label="Tiến độ điều trị" />
// Medical timeline
<TimelineAtom items={medicalEvents} />
// Lab results display
<LabResultAtom
testName="Xét nghiệm máu"
result="120 mg/dL"
normalRange="70-100 mg/dL"
status="high"
/>
// Secure input for sensitive data
<SecureInputAtom
placeholder="Nhập mật khẩu"
showToggle={true}
/>
// OTP input for 2FA
<InputOTPAtom length={6} />
// Medical file upload
<FileInputAtom
accept=".pdf,.jpg,.png"
maxSize={5 * 1024 * 1024} // 5MB
medical={true}
/>
import {
Heading1,
Heading2,
Heading3,
Paragraph,
Caption,
ErrorText,
SuccessText
} from '@qkit-emr/web-ui';
<Heading1>Tiêu đề chính</Heading1>
<Heading2>Tiêu đề phụ</Heading2>
<Paragraph>Nội dung văn bản</Paragraph>
<ErrorText>Thông báo lỗi</ErrorText>
<SuccessText>Thông báo thành công</SuccessText>
import {
FormField,
SearchBar,
Alert,
Badge,
Card,
Modal
} from '@qkit-emr/web-ui';
// Form field với validation
<FormField
label="Họ và tên"
error="Tên không được để trống"
required
>
<Input placeholder="Nhập họ và tên" />
</FormField>
// Search bar với medical context
<SearchBar
placeholder="Tìm kiếm bệnh nhân, mã BHYT..."
onSearch={(value) => console.log(value)}
medical={true}
/>
// Medical alert
<Alert
type="warning"
title="Cảnh báo thuốc"
description="Bệnh nhân có tiền sử dị ứng với Penicillin"
/>
import {
Header,
Sidebar,
Navigation,
DataTable,
Breadcrumb,
Pagination
} from '@qkit-emr/web-ui';
// Medical data table
<DataTable
data={patients}
columns={[
{ key: 'name', label: 'Họ tên' },
{ key: 'age', label: 'Tuổi' },
{ key: 'diagnosis', label: 'Chẩn đoán' },
{ key: 'status', label: 'Trạng thái' }
]}
pagination={{
currentPage: 1,
totalPages: 10,
onPageChange: (page) => console.log(page)
}}
medical={true}
/>
// Medical navigation
<Navigation
items={[
{ label: 'Dashboard', icon: 'dashboard', href: '/' },
{ label: 'Bệnh nhân', icon: 'users', href: '/patients' },
{ label: 'Lịch hẹn', icon: 'calendar', href: '/appointments' },
{ label: 'Báo cáo', icon: 'chart', href: '/reports' }
]}
medical={true}
/>
import {
AuthTemplate,
DashboardTemplate,
DetailTemplate,
ErrorTemplate,
FormTemplate,
ListTemplate
} from '@qkit-emr/web-ui';
// Medical dashboard template
<DashboardTemplate
header={<Header title="Dashboard Bệnh viện" />}
sidebar={<Sidebar />}
content={<DashboardContent />}
medical={true}
/>
// Patient detail template
<DetailTemplate
header={<PatientHeader patient={patient} />}
content={<PatientDetails patient={patient} />}
actions={<PatientActions patient={patient} />}
medical={true}
/>
// Medical form template
<FormTemplate
title="Thêm bệnh nhân mới"
form={<PatientForm />}
actions={<FormActions />}
medical={true}
/>
import {
// Responsive Providers & Hooks
ResponsiveProvider,
useResponsive,
// Responsive Layout Components
ResponsiveLayoutContainer,
ResponsiveGrid,
// Mobile Components
MobileLayout,
MobileStack,
MobileContainer,
MobileBottomNavigation,
MobileDrawerNavigation,
MobileHamburgerMenu,
// Tablet Components
TabletLayout,
TabletContainer,
TabletStack,
// Desktop Components
DesktopLayout,
DesktopContainer,
DesktopStack,
DesktopGrid,
// Responsive Form Components
ResponsiveForm,
ResponsiveFormField,
ResponsiveInputField,
ResponsiveSelectField,
ResponsiveTextareaField,
ResponsiveCheckboxField,
ResponsiveRadioField,
ResponsiveFormActions
} from '@qkit-emr/web-ui';
// Responsive medical form
<ResponsiveProvider>
<ResponsiveForm>
<ResponsiveFormField label="Họ và tên">
<ResponsiveInputField placeholder="Nhập họ và tên" />
</ResponsiveFormField>
<ResponsiveFormField label="Ngày sinh">
<ResponsiveInputField type="date" />
</ResponsiveFormField>
<ResponsiveFormActions>
<Button>Lưu</Button>
<Button variant="outline">Hủy</Button>
</ResponsiveFormActions>
</ResponsiveForm>
</ResponsiveProvider>
import { ThemeProvider } from '@qkit-emr/web-ui';
function App() {
return (
<ThemeProvider>
<YourApp />
</ThemeProvider>
);
}
import { useThemeToggle } from '@qkit-emr/web-ui';
function ThemeToggle() {
const { toggleTheme, theme } = useThemeToggle();
return (
<Button onClick={toggleTheme}>
{theme === 'dark' ? '🌞' : '🌙'}
</Button>
);
}
// Primary medical colors
className="bg-blue-600 text-white" // Medical blue
className="bg-green-500 text-white" // Success green
className="bg-red-600 text-white" // Error red
className="bg-yellow-500 text-white" // Warning yellow
// Medical status colors
className="bg-red-100 text-red-800" // Critical
className="bg-yellow-100 text-yellow-800" // Warning
className="bg-green-100 text-green-800" // Stable
className="bg-blue-100 text-blue-800" // Info
import { Button } from '@qkit-emr/web-ui';
// Sử dụng className để override
<Button className="bg-blue-600 hover:bg-blue-700">
Custom Button
</Button>
import { Button } from '@qkit-emr/web-ui';
// Button với medical variant
<Button variant="medical" size="lg">
Khám bệnh
</Button>
Tất cả components đều hỗ trợ responsive design với breakpoints:
sm:
)lg:
, xl:
, 2xl:
)<Card className="p-4 sm:p-6 lg:p-8">
<h1 className="text-xl sm:text-2xl lg:text-3xl">
Responsive Title
</h1>
</Card>
Tất cả components đều tuân thủ WCAG 2.1 AA:
<Button aria-label="Thêm bệnh nhân mới">
<Icon name="plus" />
</Button>
import { render, screen } from '@testing-library/react';
import { Button } from '@qkit-emr/web-ui';
test('Button renders correctly', () => {
render(<Button>Test Button</Button>);
expect(screen.getByRole('button')).toBeInTheDocument();
});
Chạy Storybook để xem tất cả components:
npm run storybook
Truy cập online: https://qkit-emr-share-ui.web.app/
interface ButtonProps {
variant?: 'default' | 'destructive' | 'outline' | 'secondary' | 'ghost' | 'link' | 'medical';
size?: 'default' | 'sm' | 'lg' | 'icon';
disabled?: boolean;
loading?: boolean;
children: React.ReactNode;
onClick?: () => void;
className?: string;
medical?: boolean; // Medical-specific styling
}
interface InputProps {
type?: 'text' | 'email' | 'password' | 'number' | 'tel';
placeholder?: string;
value?: string;
onChange?: (value: string) => void;
error?: string;
disabled?: boolean;
className?: string;
mask?: string; // Input mask for phone, date, etc.
medical?: boolean; // Medical-specific validation
}
// LabResultAtom
interface LabResultAtomProps {
testName: string;
result: string;
normalRange: string;
status: 'normal' | 'high' | 'low' | 'critical';
unit?: string;
date?: Date;
}
// StatusBadgeAtom
interface StatusBadgeAtomProps {
status: 'critical' | 'warning' | 'stable' | 'discharged' | 'admitted';
size?: 'sm' | 'md' | 'lg';
}
// SecureInputAtom
interface SecureInputAtomProps {
placeholder?: string;
showToggle?: boolean;
medical?: boolean; // HIPAA compliance
}
{
"react": "^18.2.0",
"react-dom": "^18.2.0",
"@radix-ui/react-*": "^1.0.0",
"tailwindcss": "^3.3.0",
"class-variance-authority": "^0.7.0",
"clsx": "^2.0.0",
"tailwind-merge": "^2.0.0"
}
{
"@types/react": "^18.2.0",
"@types/react-dom": "^18.2.0",
"typescript": "~5.8.2"
}
npm run build
npm run dev
npm run storybook
npm run build-storybook
npm test
npm run test:watch
npm run lint
npm run lint:fix
// UI Components (shadcn/ui)
export * from './components/ui';
// Atoms - Basic building blocks
export * from './components/atoms';
// Molecules - Complex components
export * from './components/molecules';
// Organisms - Page-level components
export * from './components/organisms';
// Templates - Layout components
export * from './components/templates';
// Pages - Complete page components
export * from './components/pages';
// Hooks
export * from './hooks';
// Responsive System
export * from './responsive';
// Utils
export * from './lib/utils';
import {
Button,
Input,
Card,
useTheme,
ThemeProvider,
cn,
ResponsiveProvider,
useResponsive
} from '@qkit-emr/web-ui';
git checkout -b feature/amazing-feature
)git commit -m 'Add amazing feature'
)git push origin feature/amazing-feature
)MIT License - xem file LICENSE để biết thêm chi tiết.
Xem CHANGELOG.md để biết lịch sử thay đổi.
Made with ❤️ by EMR Team
FAQs
Shared UI Component Library for EMR Monorepo
We found that @qkit-emr/web-ui demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers 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.
Research
Four npm packages disguised as cryptographic tools steal developer credentials and send them to attacker-controlled Telegram infrastructure.
Security News
Ruby maintainers from Bundler and rbenv teams are building rv to bring Python uv's speed and unified tooling approach to Ruby development.
Security News
Following last week’s supply chain attack, Nx published findings on the GitHub Actions exploit and moved npm publishing to Trusted Publishers.