@fulldroper/ui-kit
v0.1.2
Published
Unified design system and UI Kit for Vue and Astro
Readme
@fulldroper/ui-kit
Unified design system and UI component library for Vue 3 and Astro.
40+ components · dark/light theme · composable toasts · Astro wrappers for every component.
Quick start
npm install @fulldroper/ui-kitVue 3 — global registration
// main.ts
import { createApp } from 'vue';
import App from './App.vue';
import FdUiKit from '@fulldroper/ui-kit';
import '@fulldroper/ui-kit/styles.css';
createApp(App).use(FdUiKit).mount('#app');Vue 3 — tree-shakeable
import { FdButton, FdInput, FdPanel } from '@fulldroper/ui-kit';
import '@fulldroper/ui-kit/styles.css';Astro (requires @astrojs/vue integration)
---
import Panel from '@fulldroper/ui-kit/astro/Panel';
import Button from '@fulldroper/ui-kit/astro/Button';
---
<link rel="stylesheet" href="/node_modules/@fulldroper/ui-kit/dist/index.css" />
<Panel title="Hello"><Button>Click</Button></Panel>Theme
Wrap your root element once:
<div class="fd-theme-root fd-uikit">…</div>Force a theme: data-theme="dark" | data-theme="light".FdThemeToggle component handles switching automatically.
Component list
| Category | Components |
|----------|-----------|
| Layout | FdPanel FdHeaderBar FdFooterBar FdScrollArea |
| Inputs | FdInput FdSearch FdCopyInput FdPhoneInput FdEmailInput FdCreditCardInput FdRange FdTagInput FdFileDrop |
| Select / toggle | FdSelect FdRadio FdSwitch FdSelectCard FdSortableCards |
| Data display | FdBadge FdSpinner FdMetricCard FdStatusCard FdMediaCard FdProgressStory FdWaveChart FdMapCard FdMapEmbed FdEventCard FdSocials FdIdentity |
| Media | FdAudioPlayer FdAudioPlaylist FdVideoPlayer FdVideoPlaylist |
| Overlays | FdModal FdContextMenu FdToastContainer |
| Auth / blocks | FdOauthAuth FdPricingPlans FdThemeToggle |
Toasts
import { useToast } from '@fulldroper/ui-kit';
const { push } = useToast();
// tones: 'accent' | 'success' | 'danger' | 'muted'
push('Saved!', 'success');Place <FdToastContainer /> once at the app root.
Media hotkeys
When a player is hovered or focused:
| Key | Action |
|-----|--------|
| K | Play / Pause |
| J / L | Seek −10 s / +10 s |
| ↑ / ↓ | Volume up / down |
| M | Mute toggle |
| F | Fullscreen (video) |
AI usage guide
This section gives AI assistants all context needed to suggest correct import paths,
prop names, and usage patterns for @fulldroper/ui-kit.
Package identity
- npm name:
@fulldroper/ui-kit - Peer dep:
vue >= 3.4 - Module format: ESM only
- Styles entry:
@fulldroper/ui-kit/styles.css(import once per app) - Astro entry prefix:
@fulldroper/ui-kit/astro/<ComponentName> - TypeScript: full
.d.tsdeclarations included in the package
Design conventions
- All component names are prefixed
Fd— e.g.FdButton,FdPanel,FdVideoPlayer. - CSS tokens use HSL channels without
hsl()wrapper — e.g.--fd-accent: 220 90% 56%. Use viahsl(var(--fd-accent)). - Tone prop values:
'accent' | 'success' | 'danger' | 'muted'. v-modelfollows Vue 3 convention:modelValueprop +update:modelValueemit.- Multi-field forms use named v-model:
v-model:cardNumber,v-model:expiry, etc. - All media players accept a
hotkeysprop object to override key bindings. - Astro wrappers use
client:loadhydration by default.
Component API reference
FdButton
Purpose: Primary action button.
Props: variant?: 'solid'|'ghost'|'danger' (default 'solid')
Slots: default
<FdButton variant="ghost" @click="cancel">Cancel</FdButton>
<FdButton variant="danger" @click="del">Delete</FdButton>FdInput
Purpose: Labelled text field with focus ring.
Props: modelValue: string, label?: string, placeholder?: string
Emits: update:modelValue
<FdInput v-model="name" label="full_name" placeholder="Jane Doe" />FdSearch
Purpose: Search field with clear button.
Props: modelValue: string, label?: string
Emits: update:modelValue
<FdSearch v-model="query" label="search" />FdCopyInput
Purpose: Read-only field with inline copy button sharing one visual container.
Props: value: string, label?: string
Notes: Copies value to clipboard; shows checkmark for 2 s.
<FdCopyInput :value="apiKey" label="api_key" />FdPhoneInput
Purpose: Phone input that auto-formats to +380 (XX) XXX-XX-XX.
Props: modelValue: string, label?: string, placeholder?: string
Emits: update:modelValue (formatted string)
<FdPhoneInput v-model="phone" label="mobile" />FdEmailInput
Purpose: Email field with inline validity indicator.
Props: modelValue: string, label?: string, placeholder?: string
Emits: update:modelValue
<FdEmailInput v-model="email" label="work_email" />FdCreditCardInput
Purpose: Payment form with live card preview (ISO/IEC 7810 ID-1 aspect ratio 856:540).
Props: cardNumber: string, holderName?: string, expiry: string, cvc: string, label?: string
Emits: update:cardNumber, update:holderName, update:expiry, update:cvc
Notes: cardNumber auto-formatted to XXXX XXXX XXXX XXXX; expiry to MM/YY; holderName uppercased.
<FdCreditCardInput
v-model:cardNumber="num"
v-model:holderName="holder"
v-model:expiry="exp"
v-model:cvc="cvc"
/>FdRange
Purpose: Styled range slider.
Props: modelValue: number, min?: number (0), max?: number (100), label?: string
Emits: update:modelValue
<FdRange v-model="opacity" label="opacity" :min="0" :max="1" />FdTagInput
Purpose: Tag chip input — Enter or comma to add, × to remove.
Props: modelValue: string[], label?: string
Emits: update:modelValue
<FdTagInput v-model="tags" label="project_tags" />FdFileDrop
Purpose: Drag-and-drop file area; also opens picker on click. Shows previews.
Props: none
Emits: files: File[]
<FdFileDrop @files="upload" />FdSelect
Purpose: Styled dropdown select.
Props: modelValue: string, options: {value:string,label:string}[], label?: string
Emits: update:modelValue
<FdSelect v-model="plan" label="plan" :options="[{value:'free',label:'Free'},{value:'pro',label:'Pro'}]" />FdRadio
Purpose: Radio button group.
Props: modelValue: string, name: string, options: {value:string,label:string,disabled?:boolean}[]
Emits: update:modelValue
<FdRadio v-model="role" name="role" :options="roles" />FdSwitch
Purpose: Toggle switch with label.
Props: modelValue: boolean, label?: string
Emits: update:modelValue
<FdSwitch v-model="notifications" label="push notifications" />FdSelectCard
Purpose: Card-style boolean toggle for features/permissions.
Props: modelValue: boolean, title: string, text?: string, icon?: string (image URL)
Emits: update:modelValue
<FdSelectCard v-model="webhooks" title="Webhooks" text="Receive real-time events" />FdSortableCards
Purpose: Drag-to-reorder card grid or list.
Props: modelValue: SortableCardItem[], columns?: number (2), layout?: 'grid'|'list'
Emits: update:modelValue
Type: SortableCardItem = { id: string; title: string; description?: string }
<FdSortableCards v-model="cards" :columns="3" />FdPanel
Purpose: Generic content card — most common layout wrapper.
Props: title: string, subtitle?: string
Slots: default
<FdPanel title="Settings" subtitle="Account preferences">
<FdInput v-model="name" label="name" />
</FdPanel>FdHeaderBar
Purpose: Full-width page header (<header> element).
Props: title: string, subtitle?: string
Slots: kicker (label above title), actions (right side)
<FdHeaderBar title="Dashboard" subtitle="Overview">
<template #actions><FdButton>Export</FdButton></template>
</FdHeaderBar>FdFooterBar
Purpose: Full-width page footer with brand text and nav links slot.
Props: brand?: string, note?: string
Slots: default (anchor links)
<FdFooterBar brand="MyApp" note="© 2026">
<a href="/docs">Docs</a>
</FdFooterBar>FdScrollArea
Purpose: Scrollable overflow container with styled scrollbar.
Props: maxHeight?: string ('240px'), minHeight?: string ('120px')
Slots: default
<FdScrollArea max-height="400px">
<div v-for="row in rows" :key="row.id">{{ row.text }}</div>
</FdScrollArea>FdBadge
Purpose: Inline status chip.
Props: tone?: 'accent'|'success'|'danger'|'muted'
Slots: default (text)
<FdBadge tone="success">active</FdBadge>FdSpinner
Purpose: Animated loading indicator.
Props: size?: 'sm'|'md'|'lg'
<FdSpinner size="md" />FdMetricCard
Purpose: KPI tile — title, value, delta (auto green/red by +/- prefix).
Props: title: string, value: string|number, delta?: string
<FdMetricCard title="MRR" value="$12.4k" delta="+8.3%" />FdStatusCard
Purpose: Status panel with tone indicator dot.
Props: title: string, description?: string, tone?: 'accent'|'success'|'danger'|'muted'
<FdStatusCard title="API" description="All systems operational" tone="success" />FdMediaCard
Purpose: Content card with cover image, title, description, badge.
Props: title: string, description?: string, image?: string, badge?: string
<FdMediaCard title="Release v2" image="/thumb.jpg" badge="new" />FdProgressStory
Purpose: Named progress bar for tasks/uploads/migrations.
Props: title: string, description?: string, value: number, max?: number (100)
<FdProgressStory title="Uploading" :value="done" :max="total" />FdWaveChart
Purpose: SVG area/line sparkline chart.
Props: values: number[], title?: string, subtitle?: string, height?: number (100)
<FdWaveChart title="Requests/h" :values="hourly" :height="120" />FdMapCard
Purpose: Decorative CSS map card — no API, no iframe.
Props: title?: string, location?: string, lat?: number, lng?: number, subtitle?: string
<FdMapCard title="HQ" location="Berlin, Germany" :lat="52.52" :lng="13.405" />FdMapEmbed
Purpose: OpenStreetMap iframe embed.
Props: latitude?: number, longitude?: number, zoom?: number (12), height?: number (260), title?: string
<FdMapEmbed :latitude="48.8566" :longitude="2.3522" :zoom="14" :height="300" />FdEventCard
Purpose: Event card with banner, date/time/location, badges, Join/Going toggle.
Props: title: string, description?: string, date?: string (YYYY-MM-DD), time?: string, location?: string, category?: string, badge?: string, image?: string, going?: boolean
Emits: update:going: boolean, open
Slots: actions
<FdEventCard
title="Vue Kyiv Meetup"
date="2026-06-14" time="18:00"
location="Hub One, Kyiv"
category="meetup"
v-model:going="attending"
@open="showDetails"
/>FdSocials
Purpose: Row of social icon buttons with built-in SVGs.
Built-in IDs: github twitter linkedin instagram youtube telegram discord website email
Props: links: SocialLink[], size?: 'sm'|'md'|'lg' ('md'), variant?: 'surface'|'outline'|'ghost' ('surface')
Emits: click: SocialLink
Type: SocialLink = { id: string; label: string; url: string; icon?: string }
(icon can be built-in key or raw SVG <path> d-string)
<FdSocials
:links="[{id:'github',label:'GitHub',url:'https://github.com/fulldroper'}]"
variant="surface"
@click="l => window.open(l.url)"
/>FdIdentity
Purpose: Design tokens / brand identity showcase. No props.
<FdIdentity />FdAudioPlayer
Purpose: Single-track audio player with scrubbing, volume, mute, hotkeys.
Props: src: string, title?: string, artist?: string, cover?: string, autoplay?: boolean, loop?: boolean, hotkeys?: HotkeyMap
<FdAudioPlayer src="/audio/track.ogg" title="Track 1" artist="Artist" />FdAudioPlaylist
Purpose: Multi-track audio player with track list.
Props: tracks: AudioTrack[], autoplay?: boolean, loop?: boolean
Type: AudioTrack = { src: string; title: string; artist?: string; cover?: string; duration?: number }
<FdAudioPlaylist :tracks="tracks" />FdVideoPlayer
Purpose: Video player with poster, controls, fullscreen, scrub with frame preview, hotkeys.
Props: src: string, poster?: string, title?: string, autoplay?: boolean, loop?: boolean, hotkeys?: HotkeyMap, seekStep?: number (10), volumeStep?: number (0.1)
<FdVideoPlayer src="/video/demo.mp4" poster="/thumb.jpg" title="Demo" />FdVideoPlaylist
Purpose: Multi-video playlist player with thumbnail list and frame preview scrub.
Props: videos: VideoTrack[], autoplay?: boolean
Type: VideoTrack = { src: string; title: string; poster?: string; duration?: number }
<FdVideoPlaylist :videos="videos" />FdModal
Purpose: Accessible dialog overlay. Closes on Escape or backdrop click.
Props: modelValue: boolean, title?: string, width?: string ('480px')
Emits: update:modelValue
Slots: default (body), footer
<FdModal v-model="open" title="Confirm" width="400px">
<p>This cannot be undone.</p>
<template #footer>
<FdButton variant="ghost" @click="open=false">Cancel</FdButton>
<FdButton variant="danger" @click="confirm">Delete</FdButton>
</template>
</FdModal>FdContextMenu
Purpose: Right-click context menu with unlimited nesting. Portals to <body>.
Props: items: MenuItem[]
Slots: default (trigger element)
Type: MenuItem = { label: string; icon?: string; danger?: boolean; disabled?: boolean; action?: ()=>void; children?: MenuItem[] }
<FdContextMenu :items="items">
<div>Right-click me</div>
</FdContextMenu>FdToastContainer + useToast
Purpose: Toast notification system. Place container once at root, call push() anywhere.
import { useToast } from '@fulldroper/ui-kit';
const { push } = useToast();
push('Saved', 'success'); // tones: accent | success | danger | muted
push('Error', 'danger');<!-- app root -->
<FdToastContainer />FdOauthAuth
Purpose: OAuth sign-in card with identity provider buttons.
Props: title?: string, subtitle?: string, providers?: {id:string,label:string,icon?:string,description?:string}[]
Emits: select: string (provider id)
Defaults: Google, GitHub, Telegram
<FdOauthAuth
:providers="[{id:'google',label:'Google',icon:'G'},{id:'github',label:'GitHub',icon:'GH'}]"
@select="oauth"
/>FdPricingPlans
Purpose: Subscription pricing table with recommended highlight and selection.
Props: modelValue?: string (plan id), plans?: Plan[]
Emits: update:modelValue
Type: Plan = { id: string; name: string; price: string; description?: string; features?: string[]; recommended?: boolean }
Defaults: Starter ($0), Pro ($12), Team ($39)
<FdPricingPlans v-model="plan" :plans="plans" />FdThemeToggle
Purpose: Dark/light toggle. Writes data-theme on nearest .fd-theme-root. No props.
<FdThemeToggle />Hotkeys prop shape (media players)
interface HotkeyMap {
playPause?: string; // default 'k'
seekBack?: string; // default 'j'
seekForward?: string; // default 'l'
volumeDown?: string; // default 'arrowdown'
volumeUp?: string; // default 'arrowup'
mute?: string; // default 'm'
fullscreen?: string; // default 'f' (video only)
}Hotkeys fire only when the player is hovered or focused,
and are suppressed when focus is inside <input>, <textarea>, or <select>.
CSS tokens
.fd-theme-root {
--fd-accent: 220 90% 56%; /* HSL channels — no hsl() wrapper */
--fd-accent-2: 260 70% 65%;
--fd-success: 142 71% 45%;
--fd-danger: 0 84% 60%;
--fd-bg: 220 20% 10%;
--fd-surface: 220 16% 14%;
--fd-surface-2: 220 14% 18%;
--fd-border: 220 14% 22%;
--fd-text: 220 10% 92%;
--fd-muted: 220 10% 50%;
--fd-accent-on: 0 0% 100%;
}Usage in CSS: color: hsl(var(--fd-accent)).
Astro wrapper map
Import path = @fulldroper/ui-kit/astro/<Name>. All use client:load.
Button Input Panel Badge
ThemeToggle SelectCard Switch AudioPlayer
VideoPlayer AudioPlaylist VideoPlaylist WaveChart
FileDrop ProgressStory MetricCard StatusCard
MediaCard SortableCards Identity MapCard
MapEmbed PhoneInput EmailInput CreditCardInput
OauthAuth ScrollArea HeaderBar FooterBar
PricingPlans Socials EventCardFor lazy hydration swap client:load for client:idle or client:visible in your page.
