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

@legalaidalberta/luic

v0.2.0

Published

Legal Aid Alberta's React component library. Built with React, Tailwind CSS v4, react-select, and Zod validation.

Readme

@luic/ui

Legal Aid Alberta's React component library. Built with React, Tailwind CSS v4, react-select, and Zod validation.

Installation

pnpm add @luic/ui

Quick Start

import { TextInput, createTextInputSchema } from '@luic/ui';
import '@luic/ui/dist/styles.css';

const schema = createTextInputSchema({ required: true, minLength: 2 });

function MyForm() {
  const [name, setName] = useState('');
  const [error, setError] = useState<string>();

  const handleBlur = () => {
    const result = schema.safeParse(name);
    setError(result.success ? undefined : result.error.issues[0].message);
  };

  return (
    <TextInput
      label="Full Name"
      value={name}
      onChange={(e) => setName(e.target.value)}
      onBlur={handleBlur}
      error={error}
      required
    />
  );
}

Components

Selection Controls

| Component | Description | When to Use | When Not to Use | |-----------|-------------|-------------|-----------------| | Select | Single-selection dropdown (react-select) | Choosing one option from a list of 5+; searchable, clearable by default | Binary choices (Toggle), 2-4 visible options (Radio) | | MultiSelect | Multi-selection dropdown (react-select) | Choosing multiple options from a list; tags, filters, categories | Single selection (Select), boolean agreement (Checkbox) | | TagInput | Creatable multi-select for free-text tags | Tags, keywords, labels where users can create new values | Selecting from fixed options only (MultiSelect) | | SearchInput | Text search or async typeahead | Simple search fields (simple mode) or server-side search (async mode) | Selecting from a static list (Select) |

Text Inputs

| Component | Description | When to Use | When Not to Use | |-----------|-------------|-------------|-----------------| | TextInput | Single-line text entry with optional addons | Names, emails, short text, any single-line field | Multi-line text (Textarea), passwords (PasswordInput), URLs (URLInput) | | PasswordInput | Password entry with toggle and strength meter | Password fields, PIN entry, secret keys | General text (TextInput), search (SearchInput) | | Textarea | Multi-line text with character counter | Comments, descriptions, messages | Single-line input (TextInput), rich text editing | | URLInput | URL entry with format validation | Website URLs, API endpoints, link fields | General text (TextInput), email addresses |

Numeric Inputs

| Component | Description | When to Use | When Not to Use | |-----------|-------------|-------------|-----------------| | NumericInput | Number entry with +/- buttons and clamping | Quantities, ages, counts, integers or decimals | Currency (CurrencyInput), percentages (PercentageInput), visual ranges (Slider) | | CurrencyInput | Money entry with currency symbol | Prices, payments, budgets, monetary values | Plain numbers (NumericInput), percentages (PercentageInput) | | PercentageInput | Percentage entry (0-100) with % symbol | Discount rates, completion %, probability | Plain numbers (NumericInput), visual ranges (Slider) | | Slider | Range slider for visual value selection | Volume, brightness, approximate values | Precise number entry (NumericInput), percentage fields (PercentageInput) |

Date & Time

| Component | Description | When to Use | When Not to Use | |-----------|-------------|-------------|-----------------| | DatePicker | Date selection via native input | Birthdates, deadlines, scheduling | Time selection (TimePicker) | | TimePicker | Time selection via native input | Appointment times, schedules | Date selection (DatePicker), durations (NumericInput) |

Boolean & Choice Controls

| Component | Description | When to Use | When Not to Use | |-----------|-------------|-------------|-----------------| | Toggle | On/off switch | Feature flags, settings, boolean preferences | Agreement checkboxes (Checkbox), multi-state options (Select) | | Checkbox | Single checkbox with label | Terms agreement, opt-in/out, boolean fields | On/off switches (Toggle), single selection (Radio) | | Radio | Radio button for group single-selection | 2-5 visible choices: gender, plan selection | Large lists (Select), multiple selections (MultiSelect), on/off (Toggle) |

Specialty Inputs

| Component | Description | When to Use | When Not to Use | |-----------|-------------|-------------|-----------------| | ColorPicker | Color input with hex display and preview | Theme customization, brand colors, design settings | Selecting from predefined options (Select) | | Rating | Star-based rating (1-5) | Reviews, feedback, satisfaction scores | Numeric scores (NumericInput), likes (Toggle) | | FileUpload | File upload with drag-and-drop | Documents, images, attachments | URL links to files (URLInput) |

Data Display

| Component | Description | When to Use | When Not to Use | |-----------|-------------|-------------|-----------------| | DataTable | Simple table with selection and pagination | Data lists, admin tables, simple tabular data | Complex filtering/grouping (AdvancedDataGrid) | | AdvancedDataGrid | Feature-rich grid with filtering, sorting, grouping, search, export, inline editing | Complex data management, admin dashboards, reporting | Simple lists (DataTable), fewer than 10 items |

Layout

| Component | Description | When to Use | When Not to Use | |-----------|-------------|-------------|-----------------| | Card | Container for grouping content | Dashboard widgets, content sections, summary panels | Form layouts (FormField), data display (DataTable) |

Shared Props

All form components support these base props:

| Prop | Type | Description | |------|------|-------------| | label | string | Field label | | error | string | Error message | | errors | string[] | Multiple validation errors (from Zod) | | helperText | string | Helper/hint text below the field | | disabled | boolean | Disables the field | | required | boolean | Marks the field as required | | size | 'sm' \| 'md' \| 'lg' | Size variant (default: 'md') | | colorVariant | 'default' \| 'primary' \| 'success' \| 'error' \| 'warning' | Color accent |

Zod Validation

Every component has a co-located Zod schema. Import directly from the component or from the validation barrel:

// From component
import { createTextInputSchema } from '@luic/ui';

// All schemas available
import {
  createTextInputSchema,
  createPasswordSchema,
  createTextareaSchema,
  urlSchema,
  createNumericInputSchema,
  currencySchema,
  percentageSchema,
  createDateSchema,
  timeSchema,
  colorSchema,
  ratingSchema,
  createSelectSchema,
  createMultiSelectSchema,
  createTagsSchema,
  createSearchInputSchema,
  fileSchema,
  toggleSchema,
  checkboxSchema,
  radioSchema,
} from '@luic/ui';

useFormValidation Hook

Framework-agnostic validation hook that works with any form library:

import { useFormValidation, createTextInputSchema } from '@luic/ui';

function MyInput() {
  const [value, setValue] = useState('');
  const { errors, getValidationProps } = useFormValidation({
    schema: createTextInputSchema({ required: true, minLength: 3 }),
    mode: 'onBlur', // 'onBlur' | 'onChange' | 'onSubmit'
  });

  return (
    <TextInput
      label="Name"
      value={value}
      onChange={(e) => setValue(e.target.value)}
      errors={errors}
      {...getValidationProps(value)}
    />
  );
}

React Select Customization

For advanced react-select customization, the theme layer is exported:

import { LuicSelectBase, getLuicSelectStyles } from '@luic/ui';

// Use LuicSelectBase directly for custom select implementations
// Use getLuicSelectStyles() to get the Luic theme for your own react-select instances

Development

pnpm install          # Install dependencies
pnpm dev              # Start Vite dev server
pnpm storybook        # Start Storybook
pnpm build            # Build (ES + CJS + UMD + types + CSS)
pnpm test             # Run tests (Vitest + Playwright)
pnpm lint             # Run ESLint

Build Output

dist/
  luic.es.js       # ES module
  luic.cjs.js      # CommonJS
  luic.umd.js      # UMD (global: LuicUI)
  styles.css       # Tailwind CSS
  index.d.ts       # TypeScript declarations