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

@damourlabs/ui

v0.27.0

Published

A collection of reusable UI components for Nuxt applications.

Downloads

7

Readme

@damourlabs/ui

A comprehensive Vue 3 + Nuxt 3 UI component library with advanced form generation capabilities, built with TypeScript, TailwindCSS, and modern web technologies.

✨ Features

  • 🎨 Modern UI Components - Built with shadcn/ui and TailwindCSS
  • 🔧 Dynamic Form Generation - Automatic form creation from Zod schemas
  • 📊 Chart Components - Data visualization with vue-charts
  • 🌙 Dark Mode Support - Built-in theme switching
  • 🧩 Modular Architecture - Import only what you need
  • 🔒 Type Safety - Full TypeScript support
  • 🎯 Form Validation - Advanced validation with vee-validate and Zod
  • 🔗 Resource Management - Smart resource field handling and linking
  • 📱 Responsive Design - Mobile-first approach
  • Accessibility - ARIA compliant components

🚀 Quick Start

Installation

Add the layer to your Nuxt project:

npm install @damourlabs/ui
# or
pnpm add @damourlabs/ui
# or
yarn add @damourlabs/ui

Setup

Add the layer to your nuxt.config.ts:

export default defineNuxtConfig({
  extends: ['@damourlabs/ui'],
  // your config
})

That's it! The layer will automatically configure:

  • TailwindCSS with custom theme
  • Component auto-imports with Ui prefix
  • Dark mode support
  • Form validation setup
  • Chart components

📚 Core Components

🎯 Dynamic Form System

The crown jewel of this library is the dynamic form generation system that automatically creates forms from Zod schemas.

Basic Usage

<template>
  <div>
    <UiDynamicForm 
      :schema="formSchema" 
      :submit-fn="handleSubmit"
      :sections="true"
    />
  </div>
</template>

<script setup lang="ts">
import { z } from 'zod'
import { createDynamicForm } from '@damourlabs/ui/utils/form'

// Define your schema
const userSchema = z.object({
  name: z.string().min(2, 'Name must be at least 2 characters'),
  email: z.string().email('Invalid email address'),
  age: z.number().min(18, 'Must be at least 18 years old'),
  isActive: z.boolean().default(true),
  role: z.enum(['admin', 'user', 'moderator']),
  profile: z.object({
    bio: z.string().optional(),
    website: z.string().url().optional(),
  })
})

// Generate the form
const formSchema = createDynamicForm(userSchema)

const handleSubmit = (values: any) => {
  console.log('Form submitted:', values)
}
</script>

Advanced Form Configuration

import { createDynamicForm, type CreateDynamicFormOptions } from '@damourlabs/ui/utils/form'

const options: CreateDynamicFormOptions = {
  // Configure resource fields for foreign key relationships
  resourceFields: [
    { 
      field: 'user', 
      store: 'users', 
      displayField: 'email',
      searchFields: ['name', 'email']
    },
    { 
      field: 'project', 
      store: 'projects', 
      displayField: 'name' 
    }
  ],
  
  // Fields to exclude from form generation
  fieldsToIgnore: ['id', 'createdAt', 'updatedAt'],
  
  // Custom field type mappings
  fieldTypeMapping: {
    [z.ZodFirstPartyTypeKind.ZodString]: {
      as: 'textarea',
      inputType: 'text',
      handler: (fieldSchema, field, context) => {
        if (context.key === 'description') {
          field.as = 'textarea'
        }
      }
    }
  }
}

const formSchema = createDynamicForm(userSchema, options)

🎨 UI Components

All components are built with accessibility and customization in mind:

Buttons

<template>
  <UiButton variant="default">Default Button</UiButton>
  <UiButton variant="destructive">Delete</UiButton>
  <UiButton variant="outline">Outlined</UiButton>
  <UiButton variant="ghost">Ghost</UiButton>
  <UiButton variant="success">Success</UiButton>
</template>

Cards

<template>
  <UiCard>
    <UiCardHeader>
      <UiCardTitle>Card Title</UiCardTitle>
      <UiCardDescription>Card description</UiCardDescription>
    </UiCardHeader>
    <UiCardContent>
      <!-- Your content -->
    </UiCardContent>
    <UiCardFooter>
      <!-- Footer actions -->
    </UiCardFooter>
  </UiCard>
</template>

Data Tables

<template>
  <UiDataTable 
    :data="tableData" 
    :columns="columns"
    :pagination="true"
    :sorting="true"
    :filtering="true"
  />
</template>

📊 Chart Components

Built-in chart components for data visualization:

<template>
  <UiBarChart 
    :data="chartData"
    :categories="['sales', 'revenue']"
    :index="'month'"
    :colors="['#3b82f6', '#ef4444']"
  />
  
  <UiLineChart 
    :data="timeSeriesData"
    :categories="['users', 'sessions']"
    :index="'date'"
  />
</template>

🔧 Form Field Types

The dynamic form system supports all Zod schema types with intelligent field mapping:

String Fields

const schema = z.object({
  name: z.string(),                    // → text input
  email: z.string().email(),           // → email input
  website: z.string().url(),           // → url input
  birthday: z.string().date(),         // → date picker
  userId: z.string().uuid(),           // → resource finder (if configured)
  description: z.string(),             // → textarea (with custom mapping)
})

Number Fields

const schema = z.object({
  age: z.number(),                     // → number input with steppers
  price: z.number().min(0),            // → number input with validation
  rating: z.number().min(1).max(5),    // → range slider (with custom mapping)
})

Boolean Fields

const schema = z.object({
  isActive: z.boolean(),               // → checkbox
  agreeToTerms: z.boolean(),           // → checkbox with label
})

Enum Fields

const schema = z.object({
  status: z.enum(['active', 'inactive', 'pending']), // → select dropdown
  priority: z.enum(['low', 'medium', 'high']),       // → select dropdown
})

Date Fields

const schema = z.object({
  createdAt: z.date(),                 // → date input
  scheduledFor: z.date(),              // → calendar date picker
})

Array Fields

const schema = z.object({
  tags: z.array(z.string()),           // → dynamic array of text inputs
  members: z.array(z.object({          // → dynamic array of nested forms
    name: z.string(),
    role: z.enum(['admin', 'user'])
  })),
  userIds: z.array(z.string().uuid()), // → resource finder (multi-select)
})

Nested Objects

const schema = z.object({
  address: z.object({                  // → collapsible nested form section
    street: z.string(),
    city: z.string(),
    country: z.string(),
  }),
  preferences: z.record(z.string()),   // → dynamic key-value pairs
})

🔗 Resource Field Management

The library includes a powerful resource field system for handling relationships and foreign keys:

Basic Resource Configuration

const options: CreateDynamicFormOptions = {
  resourceFields: [
    {
      field: 'user',           // Field name (without 'Id' suffix)
      store: 'usersStore',     // Pinia store for data fetching
      displayField: 'email',   // Field to display in the UI
      searchFields: ['name', 'email'] // Fields to search in
    }
  ]
}

// This will automatically convert:
// userId: z.string().uuid() → Resource finder component

Resource Finder Component

<template>
  <UiResourceFinder
    v-model="selectedUserId"
    :resource-store="usersStore"
    :display-field="'email'"
    :search-fields="['name', 'email']"
    :allow-clear="true"
    placeholder="Search for a user..."
  />
</template>

Creating Custom Resource Fields

import { createResourceFinderField } from '@damourlabs/ui/utils/form'

const userField = createResourceFinderField(
  'userId',
  'User',
  'users',
  {
    description: 'Select the user for this record',
    displayField: 'email',
    subTextField: 'name',
    searchFields: ['name', 'email', 'username'],
    rules: z.string().uuid().optional()
  }
)

🎨 Theming and Customization

TailwindCSS Configuration

The library uses TailwindCSS v4 with a custom configuration. You can extend the theme in your project:

// tailwind.config.js
import { damourTheme } from '@damourlabs/ui/tailwind.config'

export default {
  extends: [damourTheme],
  theme: {
    extend: {
      colors: {
        // Your custom colors
      }
    }
  }
}

Dark Mode

Dark mode is automatically configured and can be toggled:

<template>
  <UiDarkModeToggleSwitch />
</template>

Component Customization

All components accept custom classes and can be styled:

<template>
  <UiButton 
    class="bg-gradient-to-r from-purple-500 to-pink-500"
    variant="outline"
  >
    Custom Styled Button
  </UiButton>
</template>

📱 Layout Components

Navigation

<template>
  <UiNavMain>
    <UiNavTopLevel>
      <UiNavLinks :links="navigationLinks" />
      <UiNavUser :user="currentUser" />
    </UiNavTopLevel>
    
    <UiNavSideBar>
      <UiNavQuickSettings />
    </UiNavSideBar>
  </UiNavMain>
</template>

Hero Section

<template>
  <UiHero :actions="heroActions">
    <template #title>
      Welcome to Our Platform
    </template>
    <template #description>
      Build amazing applications with our comprehensive UI library
    </template>
  </UiHero>
</template>

🧪 Form Validation

Built-in Validation

const schema = z.object({
  email: z.string()
    .email('Please enter a valid email')
    .min(1, 'Email is required'),
  
  password: z.string()
    .min(8, 'Password must be at least 8 characters')
    .regex(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/, 'Password must contain uppercase, lowercase and number'),
  
  age: z.number()
    .min(18, 'Must be at least 18 years old')
    .max(120, 'Please enter a valid age')
})

Custom Validation Rules

import { createFieldHandler } from '@damourlabs/ui/utils/form'

const customEmailHandler = createFieldHandler<z.ZodString>((fieldSchema, field, context) => {
  if (context.key.includes('email')) {
    field.inputType = 'email'
    field.rules = z.string().email().refine(async (email) => {
      // Custom async validation
      const exists = await checkEmailExists(email)
      return !exists
    }, 'Email already exists')
  }
})

📊 Advanced Examples

Complete User Management Form

<template>
  <div class="container mx-auto p-6">
    <UiDynamicForm 
      :schema="userFormSchema" 
      :submit-fn="handleUserSubmit"
      :sections="true"
    />
  </div>
</template>

<script setup lang="ts">
import { z } from 'zod'
import { createDynamicForm } from '@damourlabs/ui/utils/form'

const userSchema = z.object({
  // Basic Information
  firstName: z.string().min(2, 'First name must be at least 2 characters'),
  lastName: z.string().min(2, 'Last name must be at least 2 characters'),
  email: z.string().email('Invalid email address'),
  phone: z.string().optional(),
  
  // Account Settings
  role: z.enum(['admin', 'user', 'moderator']).default('user'),
  isActive: z.boolean().default(true),
  departmentId: z.string().uuid().optional(),
  managerId: z.string().uuid().optional(),
  
  // Profile Information
  profile: z.object({
    bio: z.string().max(500, 'Bio must be less than 500 characters').optional(),
    website: z.string().url('Invalid website URL').optional(),
    avatar: z.string().url().optional(),
    socialLinks: z.array(z.object({
      platform: z.enum(['twitter', 'linkedin', 'github']),
      url: z.string().url()
    })).optional()
  }),
  
  // Preferences
  preferences: z.object({
    emailNotifications: z.boolean().default(true),
    theme: z.enum(['light', 'dark', 'system']).default('system'),
    language: z.enum(['en', 'es', 'fr']).default('en')
  }),
  
  // Permissions
  permissions: z.array(z.enum(['read', 'write', 'delete', 'admin'])).default(['read']),
  
  // Projects
  projects: z.array(z.object({
    projectId: z.string().uuid(),
    role: z.enum(['owner', 'collaborator', 'viewer']),
    joinedAt: z.date().default(() => new Date())
  })).optional()
})

const userFormSchema = createDynamicForm(userSchema, {
  resourceFields: [
    { 
      field: 'department', 
      store: 'departments', 
      displayField: 'name',
      searchFields: ['name', 'code']
    },
    { 
      field: 'manager', 
      store: 'users', 
      displayField: 'email',
      searchFields: ['firstName', 'lastName', 'email']
    },
    { 
      field: 'project', 
      store: 'projects', 
      displayField: 'name',
      searchFields: ['name', 'description']
    }
  ],
  fieldsToIgnore: ['id', 'createdAt', 'updatedAt']
})

const handleUserSubmit = async (values: any) => {
  try {
    await $fetch('/api/users', {
      method: 'POST',
      body: values
    })
    // Handle success
  } catch (error) {
    // Handle error
  }
}
</script>

E-commerce Product Form

const productSchema = z.object({
  name: z.string().min(3, 'Product name must be at least 3 characters'),
  description: z.string().min(10, 'Description must be at least 10 characters'),
  price: z.number().min(0.01, 'Price must be greater than 0'),
  categoryId: z.string().uuid(),
  
  // Product variants
  variants: z.array(z.object({
    name: z.string(),
    sku: z.string(),
    price: z.number().min(0),
    inventory: z.number().min(0).int(),
    attributes: z.record(z.string())
  })),
  
  // SEO
  seo: z.object({
    title: z.string().max(60, 'SEO title must be less than 60 characters').optional(),
    description: z.string().max(160, 'SEO description must be less than 160 characters').optional(),
    keywords: z.array(z.string()).optional()
  }),
  
  // Media
  images: z.array(z.string().url()),
  
  // Shipping
  shipping: z.object({
    weight: z.number().min(0),
    dimensions: z.object({
      length: z.number().min(0),
      width: z.number().min(0),
      height: z.number().min(0)
    }),
    freeShipping: z.boolean().default(false)
  })
})

const productFormSchema = createDynamicForm(productSchema, {
  resourceFields: [
    { field: 'category', store: 'categories', displayField: 'name' }
  ]
})

🔧 Development

Setup

# Clone the repository
git clone https://github.com/damourlabs/ui.git
cd ui

# Install dependencies
pnpm install

# Start development server
pnpm dev

Testing

# Run tests
pnpm test

# Run tests in watch mode
pnpm test:watch

# Run tests with coverage
pnpm test:coverage

Building

# Build for production
pnpm build

# Generate static files
pnpm generate

📄 API Reference

Form Generation Functions

createDynamicForm(schema, options?)

Generates a dynamic form from a Zod schema.

Parameters:

  • schema: z.ZodObject - The Zod schema to generate the form from
  • options?: CreateDynamicFormOptions - Configuration options

Returns: FormSchema<RuleExpression<unknown>>

createResourceFinderField(name, label, storeKey, options?)

Creates a resource finder field configuration.

Parameters:

  • name: string - Field name
  • label: string - Field label
  • storeKey: string - Pinia store key for data fetching
  • options?: object - Additional configuration

createFieldHandler<T>(handler)

Creates a custom field handler for specific field types.

Parameters:

  • handler: FieldHandler<T> - The handler function

createFieldTypeMapping(mapping)

Creates custom field type mappings.

Parameters:

  • mapping: Partial<FieldTypeMapping> - The mapping configuration

Component Props

See individual component documentation for detailed prop specifications.

🤝 Contributing

We welcome contributions! Please see our Contributing Guide for details.

📝 License

This project is licensed under the MIT License - see the LICENSE file for details.

🙏 Acknowledgments


Made with ❤️ by DamourLabs

Production

Build the application for production:

pnpm build

Or statically generate it with:

pnpm generate

Locally preview production build:

pnpm preview

Checkout the deployment documentation for more information.