UI KitPrototype

Getting Started

  • Guide

Installation

  • Nextjs

Components

Select
Demo
Installation
With Command
npx infoteam-ui-kit@latest add Select
Manually
1. Add component file
src/components/Select/Select.tsx
"use client"; import { cva, type VariantProps } from "class-variance-authority"; import * as React from "react"; import Button from "../Button/Button"; import { cn } from "../utils"; const variantsConfig = { size: { small: "", big: "", }, divider: { on: "divide-solid divide-transparent divide-x-2", off: "", }, }; const variants = cva("inline-flex rounded-md shadow-sm overflow-clip", { variants: variantsConfig, defaultVariants: { size: "small", divider: "on", }, }); export interface SelectProps extends Omit< React.SelectHTMLAttributes<HTMLSelectElement>, "onChange" | "size" >, VariantProps<typeof variants> { options: string[]; value: string; onChange: (value: string) => void; } const Select = React.forwardRef<HTMLSelectElement, SelectProps>( ({ className, size, divider, value, options, onChange, ...props }, ref) => { return ( <div> <select value={value} className="hidden" ref={ref} onChange={(e) => onChange(e.target.value)} {...props} > {options.map((option) => ( <option key={option} value={option}> {option} </option> ))} </select> <div className={cn(variants({ size, divider, className }))} role="group" > {options.map((option) => ( <div key={option}> <Button variant={option === value ? "fill" : "sub"} size={size} onClick={() => onChange(option)} className={`rounded-none active:scale-100 border-none`} > {option} </Button> </div> ))} </div> </div> ); } ); Select.displayName = "Select"; export default Select; export { variantsConfig };
2. Add imported files
src/components/Button/Button.tsx
import { cva, type VariantProps } from "class-variance-authority"; import * as React from "react"; import { cn } from "../utils"; const variantsConfig = { variant: { fill: "bg-primary text-white", outline: "border border-primary text-primary hover:bg-primary hover:text-white", sub: "bg-greyLight text-text border border-greyBorder", }, size: { small: "px-4 py-2 text-sm font-semibold rounded w-fit", big: "rounded-md px-6 py-3 font-semibold text-base w-fit", full: "rounded-xl w-full px-8 py-4 text-lg font-bold", }, animate: { on: "active:scale-95 transition", off: "", }, }; const variants = cva( "inline-flex items-center justify-center whitespace-nowrap ring-offset-background focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50", { variants: variantsConfig, defaultVariants: { variant: "fill", size: "small", animate: "on", }, } ); export interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement>, VariantProps<typeof variants> {} const Button = React.forwardRef<HTMLButtonElement, ButtonProps>( ({ className, variant, size, ...props }, ref) => { return ( <button className={cn(variants({ variant, size, className }))} ref={ref} {...props} /> ); } ); Button.displayName = "Button"; export default Button; export { variantsConfig };
src/components/utils.ts
import { type ClassValue, clsx } from "clsx"; import { twMerge } from "tailwind-merge"; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); } export function extractDefaultVariants< T extends { [K in keyof T]: { [key: string]: string } } >(variantsConfig: T): { [K in keyof T]: keyof T[K] } { return Object.fromEntries( (Object.entries(variantsConfig) as [keyof T, T[keyof T]][]).map( ([key, value]) => [key, Object.keys(value)[0] as keyof T[keyof T]] ) ) as { [K in keyof T]: keyof T[K] }; }
3. Install dependencies
npm
npm install class-variance-authority
npm
npm install react