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

@leodamours/ds-components

v0.3.1

Published

Vue 3 component library with built-in design tokens, theming via CSS custom properties, and algorithmic palette generation.

Downloads

78

Readme

@leodamours/ds-components

Vue 3 component library with built-in design tokens, theming via CSS custom properties, and algorithmic palette generation.

Install

npm install @leodamours/ds-components

Peer dependencies: vue ^3.5.0

Optional: @leodamours/ds-icons — 1,920 Lucide-based icon components that pair with this library.

Setup

// main.ts
import '@leodamours/ds-components/style.css'

The stylesheet bundles the default light theme, dark theme ([data-theme="dark"]), and all component styles. No additional CSS imports needed.

Usage

<script setup>
import { DsButton, DsInput } from '@leodamours/ds-components'
</script>

<template>
  <DsInput label="Email" placeholder="[email protected]" />
  <DsButton variant="primary" label="Submit" />
</template>

Components

| Component | Description | |---|---| | DsAvatar | User avatar with image or initials fallback | | DsBadge | Status badge / label | | DsButton | Button with variants: primary, secondary, outline, ghost, danger, success | | DsCard | Container card with variants: default, outlined, elevated | | DsCheckbox | Checkbox input | | DsDropdownSelect | Dropdown select with floating UI positioning | | DsExpandableCard | Collapsible card with title, supports v-model for expand state | | DsInput | Text input with label, help text, error state | | DsLoadingSpinner | Animated loading spinner | | DsModal | Modal dialog with backdrop | | DsRadio | Radio input | | DsSelect | Native select wrapper | | DsSlider | Range slider with optional value display | | DsSwitch | Toggle switch for boolean settings | | DsTable | Data table with sorting and pagination | | DsTabs | Tab navigation | | DsTextarea | Multiline text input | | DsToast / DsToastContainer | Toast notifications (see Toast system below) | | DsTooltip | Tooltip on hover | | DsUnderConstruction | Placeholder for pages not yet built |

All components export their prop types (e.g., DsButtonProps, DsCardProps).

Component props

DsAvatar

| Prop | Type | Default | Description | |---|---|---|---| | src | string | — | Image URL | | alt | string | — | Alt text for image | | name | string | — | Full name (used for initials fallback) | | size | 'sm' \| 'md' \| 'lg' \| 'xl' | 'md' | Avatar size | | variant | 'brand' \| 'neutral' | 'brand' | Color variant for initials background |

DsBadge

| Prop | Type | Default | Description | |---|---|---|---| | label | string | — | Badge text (can also use default slot) | | variant | 'brand' \| 'neutral' \| 'error' \| 'success' \| 'warning' \| 'info' \| 'processing' | 'neutral' | Color variant | | size | 'sm' \| 'md' \| 'lg' | 'md' | Badge size |

DsButton

| Prop | Type | Default | Description | |---|---|---|---| | label | string | — | Button text (can also use default slot) | | variant | 'primary' \| 'secondary' \| 'outline' \| 'ghost' \| 'danger' \| 'success' \| 'warning' | 'primary' | Visual style | | size | 'small' \| 'medium' \| 'large' | 'medium' | Button size | | htmlType | 'button' \| 'submit' \| 'reset' | 'button' | Native button type | | disabled | boolean | false | Disable interaction | | loading | boolean | false | Show loading spinner | | fullWidth | boolean | false | Expand to fill container | | iconLeft | Component | — | Vue component icon on the left | | iconRight | Component | — | Vue component icon on the right | | ariaLabel | string | — | Accessible label override |

DsCard

| Prop | Type | Default | Description | |---|---|---|---| | variant | 'default' \| 'outlined' \| 'elevated' | 'default' | Card style | | noPadding | boolean | false | Remove inner padding |

Default slot for card content.

DsCheckbox

| Prop | Type | Default | Description | |---|---|---|---| | modelValue | boolean | false | Checked state (v-model) | | label | string | — | Checkbox label | | id | string | auto | HTML id attribute | | value | string \| number \| boolean | — | Form value | | disabled | boolean | false | Disable interaction | | size | 'small' \| 'medium' \| 'large' | 'medium' | Checkbox size |

DsDropdownSelect

| Prop | Type | Default | Description | |---|---|---|---| | modelValue | string \| number | — | Selected value (v-model) | | options | (string \| number \| { label, value, disabled? })[] | [] | List of options | | placeholder | string | 'Select an option' | Placeholder text | | variant | 'primary' \| 'secondary' \| 'ghost' | 'primary' | Trigger button style | | size | 'small' \| 'medium' \| 'large' | 'medium' | Trigger button size | | disabled | boolean | false | Disable interaction | | loading | boolean | false | Show loading state | | iconLeft | Component | — | Icon in the trigger button | | fullWidth | boolean | false | Expand to fill container | | emptyText | string | 'No options available' | Text shown when options list is empty |

DsExpandableCard

| Prop | Type | Default | Description | |---|---|---|---| | title | string | required | Card header text | | modelValue | boolean | — | Controlled expand state (v-model) | | defaultExpanded | boolean | false | Initial expand state (uncontrolled) | | variant | 'default' \| 'outlined' \| 'elevated' | 'default' | Card style |

Default slot for expandable content.

DsInput

| Prop | Type | Default | Description | |---|---|---|---| | modelValue | string \| number | — | Input value (v-model) | | label | string | — | Label text | | type | 'text' \| 'email' \| 'password' \| 'number' \| 'tel' \| 'url' \| 'search' | 'text' | Input type | | placeholder | string | — | Placeholder text | | helpText | string | — | Help text below the input | | error | string | — | Error message (replaces help text) | | size | 'small' \| 'medium' \| 'large' | 'medium' | Input size | | disabled | boolean | false | Disable interaction | | readonly | boolean | false | Read-only state | | required | boolean | false | Mark as required | | clearable | boolean | false | Show clear button when filled | | iconLeft | Component | — | Icon on the left | | iconRight | Component | — | Icon on the right | | autocomplete | string | — | HTML autocomplete attribute | | maxLength | number | — | Character limit | | min | number \| string | — | Minimum value (number input) | | max | number \| string | — | Maximum value (number input) | | step | number \| string | — | Step increment (number input) |

DsLoadingSpinner

| Prop | Type | Default | Description | |---|---|---|---| | size | 'small' \| 'medium' \| 'large' | 'medium' | Spinner size | | variant | 'primary' \| 'secondary' \| 'white' \| 'current' | 'primary' | Color variant |

DsModal

| Prop | Type | Default | Description | |---|---|---|---| | modelValue | boolean | required | Open state (v-model) | | title | string | — | Modal title | | size | 'sm' \| 'md' \| 'lg' \| 'xl' | 'md' | Modal width | | closable | boolean | true | Show close button | | persistent | boolean | false | Prevent closing on backdrop click |

Slots: default (body), header, footer.

DsRadio

| Prop | Type | Default | Description | |---|---|---|---| | modelValue | string \| number \| boolean | — | Selected value (v-model) | | label | string | — | Radio label | | id | string | auto | HTML id attribute | | name | string | — | Radio group name | | value | string \| number \| boolean | — | This radio's value | | disabled | boolean | false | Disable interaction | | size | 'small' \| 'medium' \| 'large' | 'medium' | Radio size |

DsSelect

| Prop | Type | Default | Description | |---|---|---|---| | modelValue | string \| number | — | Selected value (v-model) | | label | string | — | Label text | | placeholder | string | — | Placeholder text | | helpText | string | — | Help text below the select | | error | string | — | Error message | | size | 'small' \| 'medium' \| 'large' | 'medium' | Select size | | disabled | boolean | false | Disable interaction | | required | boolean | false | Mark as required | | options | DsSelectOption[] | required | { label: string, value: string \| number, disabled?: boolean } |

DsSlider

| Prop | Type | Default | Description | |---|---|---|---| | modelValue | number | 0 | Slider value (v-model) | | min | number | 0 | Minimum value | | max | number | 100 | Maximum value | | step | number | 1 | Step increment | | disabled | boolean | false | Disable interaction | | label | string | — | Label text | | showValue | boolean | false | Display current value |

DsSwitch

| Prop | Type | Default | Description | |---|---|---|---| | modelValue | boolean | false | Checked state (v-model) | | label | string | — | Label text | | id | string | auto | HTML id attribute | | disabled | boolean | false | Disable interaction | | size | 'small' \| 'medium' \| 'large' | 'medium' | Switch size | | labelPosition | 'left' \| 'right' | 'right' | Label placement |

DsTable

| Prop | Type | Default | Description | |---|---|---|---| | columns | DsTableColumn[] | required | Column definitions (see below) | | rows | Record<string, any>[] | required | Row data | | sortBy | string | — | Active sort column key | | sortOrder | 'asc' \| 'desc' | — | Sort direction | | loading | boolean | false | Show loading state | | emptyText | string | 'No data available' | Text when no rows | | striped | boolean | false | Alternate row shading | | stickyHeader | boolean | false | Sticky column headers | | pagination | DsTablePagination | — | Enable pagination (see below) | | nextPageLabel | string | 'Next' | Pagination next label | | previousPageLabel | string | 'Previous' | Pagination previous label | | ofLabel | string | — | Pagination "of" label |

DsTableColumn: { key: string, label: string, sortable?: boolean, width?: string, align?: 'left' | 'center' | 'right' }

DsTablePagination: { page: number, perPage: number, total: number }

Column cells can be customized via named slots: #cell-{key}="{ row, column }".

DsTabs

| Prop | Type | Default | Description | |---|---|---|---| | modelValue | string | required | Active tab key (v-model) | | tabs | DsTab[] | required | Tab definitions | | variant | 'line' \| 'pill' | 'line' | Tab style | | ariaLabel | string | 'Tabs' | Accessible label |

DsTab: { key: string, label: string, disabled?: boolean }

Tab content is rendered via named slots: #tab-{key}.

DsTextarea

| Prop | Type | Default | Description | |---|---|---|---| | modelValue | string | — | Textarea value (v-model) | | label | string | — | Label text | | placeholder | string | — | Placeholder text | | helpText | string | — | Help text below the textarea | | error | string | — | Error message | | size | 'small' \| 'medium' \| 'large' | 'medium' | Textarea size | | disabled | boolean | false | Disable interaction | | readonly | boolean | false | Read-only state | | required | boolean | false | Mark as required | | rows | number | 3 | Visible rows | | maxLength | number | — | Character limit (shows counter) |

DsTooltip

| Prop | Type | Default | Description | |---|---|---|---| | content | string | required | Tooltip text | | placement | Placement | 'top' | Position ('top', 'bottom', 'left', 'right', etc.) | | disabled | boolean | false | Disable tooltip |

Wrap any element in <DsTooltip> — the default slot is the trigger.

DsUnderConstruction

| Prop | Type | Default | Description | |---|---|---|---| | title | string | 'Under Construction' | Heading text | | description | string | 'This page is under construction...' | Body text |

Toast system

Place <DsToastContainer /> once at the root of your app, then trigger toasts from anywhere via the useToast composable:

<!-- App.vue -->
<script setup>
import { DsToastContainer } from '@leodamours/ds-components'
</script>

<template>
  <router-view />
  <DsToastContainer />
</template>
// Any component or composable
import { useToast } from '@leodamours/ds-components'

const toast = useToast()

toast.success('Saved successfully')
toast.error('Something went wrong', { title: 'Error' })
toast.warning('Session expiring soon', { duration: 8000 })
toast.info('New version available')
toast.brand('Welcome back!')

Each method accepts (message, options?) where options are { title?: string, duration?: number }. Default duration is 5000ms.

Theming

Every color in the library flows through CSS custom properties prefixed with --ds-. The default theme is included in style.css.

Option 1: CSS overrides

Override only the variables you need:

/* my-theme.css */
:root {
  --ds-brand: #8B5CF6;
  --ds-brand-hover: #7C3AED;
  --ds-brand-active: #6D28D9;
  --ds-brand-on-solid: #FFFFFF;
  --ds-bg: #FAFAFA;
  /* Only override what differs — everything else inherits defaults */
}
import '@leodamours/ds-components/style.css' // defaults
import './my-theme.css'                       // your overrides

Option 2: Generate a full theme from 7 base colors

The generateFullTheme function derives all hover, soft, border, contrast, and disabled variants automatically from just one hex per semantic role:

import { generateFullTheme } from '@leodamours/ds-components'

const css = generateFullTheme(
  {
    brand: '#8B5CF6',
    error: '#E11D48',
    success: '#059669',
    warning: '#EA580C',
    info: '#6366F1',
    processing: '#D946EF',
    neutral: '#6B5F7D',
  },
  '[data-theme="purple"]', // CSS selector (defaults to ':root')
)

// Inject into a <style> tag
const style = document.createElement('style')
style.textContent = css
document.head.appendChild(style)

For finer control, generatePalette(hex) returns the full variant set for a single color:

import { generatePalette } from '@leodamours/ds-components'

const brandPalette = generatePalette('#8B5CF6')
// => { base, hover, active, disabled, soft, soft-hover, soft-active,
//      on-solid, on-soft, border, border-hover, border-strong }

Option 3: Override individual tokens at runtime

import { generateThemeCss } from '@leodamours/ds-components'

const css = generateThemeCss(
  { brand: '#8B5CF6', 'brand-hover': '#7C3AED' },
  '[data-theme="purple"]',
)

Runtime theme switching

A dark theme is bundled and activates via data-theme:

// Switch to dark
document.documentElement.dataset.theme = 'dark'

// Switch back to light
delete document.documentElement.dataset.theme

Token naming convention

Tokens follow a role + tone pattern: --ds-{role}[-{tone}][-{state}]

Core UI tokens:

| Token | Purpose | |---|---| | bg, bg-secondary, bg-tertiary | Page backgrounds | | bg-inverse, bg-inverse-secondary | Inverted backgrounds | | fg, fg-secondary, fg-tertiary, fg-inverse, fg-disabled | Text colors | | icon, icon-hover, icon-active, icon-inverse, icon-disabled | Icon colors | | border, border-light, border-strong, border-focus | Border colors | | surface-hover, surface-hover-light, surface-active, surface-disabled | Interactive surfaces | | overlay, focus-ring | Overlays and focus states |

Semantic role tokens — each role (brand, error, success, warning, info, processing, neutral) has:

| Tone | Purpose | Example | |---|---|---| | {role} | Solid color | --ds-brand | | {role}-hover | Hover state | --ds-brand-hover | | {role}-active | Active/pressed state | --ds-brand-active | | {role}-soft | Light background | --ds-error-soft | | {role}-soft-hover | Soft hover state | --ds-error-soft-hover | | {role}-soft-active | Soft active state | --ds-error-soft-active | | {role}-on-solid | Text on solid bg | --ds-success-on-solid | | {role}-on-soft | Text on soft bg | --ds-success-on-soft | | {role}-border | Border color | --ds-warning-border | | {role}-border-hover | Border hover | --ds-warning-border-hover | | {role}-border-strong | Strong border | --ds-info-border-strong |

UnoCSS Preset

If your app uses UnoCSS, import the design system preset instead of configuring tokens manually. It includes the full theme, rules, shortcuts, variants, and CSS custom properties.

Basic setup

// uno.config.ts
import { defineConfig, presetUno } from 'unocss'
import { dsPreset } from '@leodamours/ds-components/uno'

export default defineConfig({
  presets: [presetUno(), dsPreset()],
})

Custom palette

Pass base colors to override the default palette. All hover, soft, border, and contrast variants are derived automatically:

dsPreset({
  brand: '#8B5CF6',
  error: '#E11D48',
  success: '#059669',
  warning: '#EA580C',
  info: '#6366F1',
  processing: '#D946EF',
  neutral: '#6B5F7D',
})

Only override what differs — unspecified roles keep their defaults. The preset accepts these roles: brand, error, success, warning, info, processing, neutral.

Full export reference

Components

import {
  DsAvatar,
  DsBadge,
  DsButton,
  DsCard,
  DsCheckbox,
  DsDropdownSelect,
  DsExpandableCard,
  DsInput,
  DsLoadingSpinner,
  DsModal,
  DsRadio,
  DsSelect,
  DsSlider,
  DsSwitch,
  DsTable,
  DsTabs,
  DsTextarea,
  DsToast,
  DsToastContainer,
  DsTooltip,
  DsUnderConstruction,
} from '@leodamours/ds-components'

Prop types

import type {
  DsAvatarProps,
  DsBadgeProps,
  DsButtonProps,
  DsCardProps,
  DsCheckboxProps,
  DsDropdownSelectProps,
  DsExpandableCardProps,
  DsInputProps,
  DsLoadingSpinnerProps,
  DsModalProps,
  DsRadioProps,
  DsSelectProps,
  DsSelectOption,
  DsSliderProps,
  DsSwitchProps,
  DsTableProps,
  DsTableColumn,
  DsTablePagination,
  DsTabsProps,
  DsTab,
  DsTextareaProps,
  DsTooltipProps,
  DsUnderConstructionProps,
  Toast,
  ToastVariant,
} from '@leodamours/ds-components'

Token utilities

import {
  colorTokens,          // All color token values as a JS object
  spacingTokens,        // Spacing scale values
  radiusTokens,         // Border radius values
  shadowTokens,         // Box shadow values
  allTokens,            // All tokens combined
  generateThemeCss,     // Override specific tokens → CSS string
  tokenToCssVar,        // Convert token name to CSS var reference
} from '@leodamours/ds-components'

import type { ColorToken, SpacingToken, RadiusToken, ShadowToken, ThemeOverride } from '@leodamours/ds-components'

Palette generation

import {
  generatePalette,    // Single hex → full SemanticPalette (12 variants)
  generateFullTheme,  // 7 base colors → complete CSS theme string
  expandBases,        // 7 base colors → flat token map (no CSS wrapping)
  hexToHSL,           // Hex → { h, s, l }
  hslToHex,           // (h, s, l) → hex string
} from '@leodamours/ds-components'

import type { SemanticPalette, ThemeBases, SemanticRole } from '@leodamours/ds-components'

Composables

import { useToast, useId } from '@leodamours/ds-components'
  • useToast() — returns { toasts, removeToast, success, error, warning, info, brand } (see Toast system)
  • useId() — generates unique IDs for accessible form element associations