UNPKG

@titancasket/component-library

Version:

Titan Casket Vue 3 component library with design system - usable as Nuxt layer or standalone NPM package

507 lines (411 loc) • 17.4 kB
# Titan Casket Component Library A Nuxt 4 + Vue 3 component library that powers Titan Casket customer journeys. The project ships typed UI primitives styled with Tailwind, documented scenarios, and a comprehensive quality bar enforced by automated testing. **Dual-purpose library:** - šŸ“¦ **NPM Package**: Install in any Vue 3 project - šŸ”Œ **Nuxt Layer**: Extend in Nuxt 4 applications ## Installation ### As NPM Package (Vue 3 Projects) ```bash # Using npm npm install @titancasket/component-library # Using yarn yarn add @titancasket/component-library # Using pnpm pnpm add @titancasket/component-library ``` #### Setup Tailwind CSS Add the Titan preset to your `tailwind.config.js`: ```js export default { presets: [require('@titancasket/component-library/tailwind.preset')], content: ['./src/**/*.{vue,js,ts}', './node_modules/@titancasket/component-library/dist/**/*.{js,mjs}'], }; ``` #### Import Components ```vue <script setup> import { TitanButton, TitanInput, TitanSelect, TitanIconSelect } from '@titancasket/component-library'; </script> <template> <TitanButton variant="default">Click me</TitanButton> <TitanInput v-model="email" label="Email" type="email" /> </template> ``` ### As Nuxt Layer (Nuxt 4 Projects) Add to your `nuxt.config.ts`: ```ts export default defineNuxtConfig({ extends: ['@titancasket/component-library'], }); ``` Components and composables are auto-imported. ## Available Components ### UI Components #### `TitanButton` Button component with two variants and customizable sizes. - **Variants**: `default` (yellow fill), `outline` (transparent with yellow border) - **Sizes**: `sm`, `md`, `lg` - **Features**: Optional arrow, disabled state, full accessibility support ```vue <TitanButton variant="default" size="md" @click="handleClick"> Click me </TitanButton> ``` #### `TitanIcon` Dynamic icon component that renders SVG icons from the auto-generated icon registry. The library includes an automated icon system with 12 SVG icons: - **UI Icons** (8): casket, casket-open, casket-closed, family, fire, question-mark, tombstone, urn - **Benefits Icons** (4): cart, truck, casket, heart Icons are automatically generated from `public/icons/` and use `currentColor` for CSS-based styling. ```vue <div class="w-6 h-6 text-titan-green-800"> <TitanIcon name="ui/casket" aria-label="Casket selection" /> </div> ``` See [TitanIcon documentation](docs/components/TitanIcon.md) for details. #### `TitanInput` Floating label text input with validation support. - **Types**: `text`, `email`, `password`, `number`, `tel`, `url` - **Features**: Floating labels, error states, required field indicator, placeholder support - **Accessibility**: Full ARIA support, keyboard navigation ```vue <TitanInput v-model="email" label="Email Address" type="email" :required="true" :error="hasError" error-message="Please enter a valid email" /> ``` #### `TitanTextarea` Multi-line text input with floating labels. - **Features**: Auto-resizing, character limits, floating labels, error states - **Accessibility**: ARIA support with proper labeling and error announcements ```vue <TitanTextarea v-model="message" label="Your Message" :rows="4" :max-length="500" :required="true" /> ``` #### `TitanSelectContainer` Flexible select component with three visual variants: - **Inline**: Pill-based buttons (compact, horizontal) - **Icon**: Icon cards with custom icon slots - **Stacked**: Full-width buttons with title and description Features: Single/multi-select, custom values, keyboard navigation, ARIA support ```vue <!-- Inline variant (pills) --> <TitanSelectContainer v-model="selected" :options="['Option 1', 'Option 2', 'Option 3']" variant="inline" label="SELECT AN OPTION" /> <!-- Icon variant with slots --> <TitanSelectContainer v-model="disposition" :options="[ { value: 'buried', label: 'Buried' }, { value: 'cremated', label: 'Cremated' } ]" variant="icon" label="CHOOSE A DISPOSITION" > <template #icon-buried>🪦</template> <template #icon-cremated>āš±ļø</template> </TitanSelectContainer> <!-- Stacked variant with title/description --> <TitanSelectContainer v-model="serviceType" :options="[ { value: 'traditional', label: 'traditional', title: 'Traditional service', description: 'A ceremony at a place of worship.' } ]" variant="stacked" label="WITH A:" /> <!-- Multiple selection with custom values --> <TitanSelectContainer v-model="selected" :options="['Flowers', 'Donation', 'Memorial']" variant="inline" multiple allow-custom show-checkmark /> ``` See [TitanSelectContainer documentation](docs/components/TitanSelectContainer.md) for complete API and usage examples. #### `TitanSelect` (Deprecated) Pill-based single or multi-select component with custom value support. - **Note**: This is now a wrapper around `TitanSelectContainer` for backward compatibility. New code should use `TitanSelectContainer` with `variant="inline"`. - **Modes**: Single-select or multi-select - **Features**: Keyboard navigation (Arrow keys, Home, End), custom value entry, disabled options, toggle deselect - **Styling**: Selected items highlighted in Titan Purple, unselected in light green ```vue <!-- Single select --> <TitanSelect v-model="selectedOption" label="Choose one" :options="['Option 1', 'Option 2', 'Option 3']" /> <!-- Multi-select with custom values --> <TitanSelect v-model="selectedItems" label="Choose multiple" :options="options" :multiple="true" :allow-custom="true" /> ``` #### `TitanIconSelect` (Deprecated) Icon-based single-select component with card layout for visual selection. - **Note**: This is now a wrapper around `TitanSelectContainer` for backward compatibility. New code should use `TitanSelectContainer` with `variant="icon"`. - **Layout**: 100px Ɨ 102px cards with icons and labels - **Icons**: Provided via named slots (e.g., `#icon-buried`) - **Features**: Single-select only, keyboard navigation (Arrow keys, Space, Enter), disabled state, required validation, optional checkmark - **Styling**: Selected cards in Titan Purple with white text, unselected in light green with visible borders - **Accessibility**: Full ARIA support with radiogroup/radio roles ```vue <TitanIconSelect v-model="selectedOption" name="memorialization" :options="[ { value: 'buried', label: 'Buried' }, { value: 'cremated', label: 'Cremated' }, { value: 'other', label: 'Other' } ]" :show-checkmark="false" > <template #icon-buried> <svg><!-- Headstone icon --></svg> </template> <template #icon-cremated> <svg><!-- Urn icon --></svg> </template> <template #icon-other> <svg><!-- Flames icon --></svg> </template> </TitanIconSelect> ``` #### `TitanDatePicker` Date selection component with proper placeholder handling. - **Features**: Date validation, required field support, error states, accessible labeling - **Accessibility**: Proper ARIA attributes and keyboard support ```vue <TitanDatePicker v-model="selectedDate" label="Select a date" :required="true" /> ``` #### `TitanImageUpload` Drag-and-drop image upload with preview. - **Features**: Click or drag to upload, image preview, file validation, error handling - **Accessibility**: Keyboard accessible with proper ARIA labels ```vue <TitanImageUpload v-model="uploadedImage" label="Upload Image" :max-size="5242880" /> ``` #### `TitanInfoPanel` Informational panel component for displaying tips and guidance. - **Variants**: `default` (light background), `compact` (minimal padding), `transparent` (no background) - **Features**: Optional title, bullet list support, slot support for custom content ```vue <TitanInfoPanel title="Tips for a great photo" :items="['Use high resolution', 'Ensure good lighting', 'Face the camera']" variant="default" /> ``` #### `TitanSubheader` Section heading component for organizing form content. - **Typography**: 13px Work Sans Bold with uppercase styling (Figma-accurate) - **Features**: Consistent spacing, Titan green color, custom class support - **Use Cases**: Form section headers, content dividers, subsection titles ```vue <TitanSubheader text="What are you envisioning for the parade elements?" /> ``` #### `TitanProgressBar` Progress indicator with step counter for multi-step processes. - **Layout**: Full-width bar with label showing current/total (e.g., "3/8") - **Design**: 6px height bar with Titan yellow fill, 8px gap between bar and label - **Features**: Smooth 500ms transitions, automatic percentage calculation, validation warnings - **Accessibility**: Full ARIA progressbar support with value announcements - **Use Cases**: Multi-step forms, onboarding flows, task completion tracking ```vue <TitanProgressBar :current="3" :total="8" /> ``` ### Layout Components #### `TitanFormSection` Schema-based dynamic form renderer for creating forms declaratively. - **Features**: Dynamic component rendering, v-model integration, mixed component support (form + non-form) - **Benefits**: Reduced boilerplate, consistent spacing, easy form structure changes - **Schema Support**: TitanInput, TitanTextarea, TitanSelect, TitanDatePicker, TitanSubheader, and more ```vue <script setup> const formData = ref({ paradeElements: '', colors: '', }); const schema = [ { component: 'TitanSubheader', props: { text: 'What are you envisioning for the parade elements?' } }, { component: 'TitanTextarea', props: { label: 'Notes', rows: 3 }, model: 'paradeElements' }, { component: 'TitanSubheader', props: { text: 'Any particular colors you would like represented?' } }, { component: 'TitanTextarea', props: { label: 'Notes', rows: 3 }, model: 'colors' } ]; </script> <template> <TitanFormSection v-model="formData" :schema="schema" /> </template> ``` **Composable**: The `useFormSchema()` composable provides utilities for schema validation, form data initialization, and field validation. #### `TitanCard` Flexible card container with header, content, and optional logo. - **Variants**: `default` (white background), `system` (translucent with backdrop blur) - **Features**: Optional title, header slot, logo display (top-right), responsive design - **Styling**: Rounded corners, shadow, grid-based layout ```vue <TitanCard variant="default" title="Welcome" :logo="true"> <p>Your content goes here</p> </TitanCard> ``` #### `TitanStepper` Step indicator component for multi-step forms and wizards. - **Features**: Current step tracking, completed step indicators, step labels - **Accessibility**: Proper ARIA landmarks and step announcements ```vue <TitanStepper :steps="['Personal Info', 'Upload Photo', 'Review']" :current-step="1" /> ``` ### Design System The library includes a complete Titan Casket design system with scientifically-generated color scales: - **Primary Green**: `#003822` (titan-green-800) - Main brand color - **Secondary Yellow**: `#facf60` (titan-yellow-400) - Accent and CTAs - **Tertiary Purple**: `#3F1038` (titan-purple-500) - Selection highlights All components use these brand colors and are fully typed with TypeScript. Import the Tailwind preset to access the complete design token system. ## Development Setup 1. Install dependencies (Node 18+, Yarn 1.x): ```bash yarn install ``` 2. Launch the playground at `http://localhost:3000`: ```bash yarn dev ``` 3. Build the library for NPM publishing: ```bash yarn build # Builds standalone Vue 3 library to dist/ ``` 4. Build Nuxt layer or preview: ```bash yarn build:nuxt # Build Nuxt layer yarn preview # Preview production build yarn generate # Generate static site ``` ## Scripts & Tooling | Command | Purpose | | ------------------------- | ---------------------------------------------------------------------------------- | | `yarn dev` | Run the Nuxt development server with HMR. | | `yarn build` | **Build standalone Vue 3 library** to `dist/` (for NPM publishing). | | `yarn lib:build` | Same as `yarn build` - builds NPM package. | | `yarn build:nuxt` | Build Nuxt layer for production. | | `yarn preview` | Preview the production build locally. | | `yarn generate` | Produce static output for Jamstack-style hosting. | | `yarn prepare` | Prepare Nuxt layer (runs automatically after install in Nuxt projects). | | `yarn storybook` | Launch Storybook at `http://localhost:6006` for interactive component development. | | `yarn build-storybook` | Build Storybook as a static site for deployment. | | `yarn test` | Execute Vitest unit suites with Happy DOM. | | `yarn test:watch` | Keep Vitest running for rapid feedback. | | `yarn test:coverage` | Generate coverage reports (minimum 80%). | | `yarn test:visual` | Run Playwright snapshot tests across browsers. | | `yarn test:visual:update` | Update Playwright baselines after approved design changes. | | `yarn test:storybook` | Run Storybook test runner (Playwright-based) for story validation. | | `yarn test:all` | Chain unit + visual + Storybook runs; required before PRs. | ## Directory Layout ``` app/ ā”œā”€ components/ │ ā”œā”€ ui/ # Exported UI primitives (TitanButton, TitanInput, TitanSelect, TitanIconSelect, ...) │ │ # Each component has a .stories.ts file for Storybook │ └─ layout/ # Structural/layout wrappers ā”œā”€ composables/ # Shared logic (useFormField, etc.) ā”œā”€ pages/ # Playground demos used by visual tests ā”œā”€ types/ # Component-specific TypeScript contracts ā”œā”€ utils/ # Reusable helpers and formatters .storybook/ ā”œā”€ main.ts # Storybook + Vite + Tailwind configuration ā”œā”€ preview.ts # Global styles and preview settings └─ test-runner.ts # Playwright-based test runner config docs/ ā”œā”€ components/ # Consumer-facing component documentation └─ templates/ # Documentation boilerplate for component docs .agent/ └─ sop/ # Standard Operating Procedures (internal docs) ā”œā”€ component-creation-process.md ā”œā”€ testing-guide.md └─ npm-publishing.md tests/ ā”œā”€ unit/ # Vitest specs grouped by domain ā”œā”€ visual/ # Playwright visual regression suites ā”œā”€ fixtures/ # Shared datasets and mocks └─ templates/ # Copyable test scaffolding ``` Nuxt, Tailwind, Vitest, and Playwright configurations live at the repo root (`nuxt.config.ts`, `tailwind.config.js`, `vitest.config.ts`, `playwright.config.ts`). ## Component Development Workflow Follow the repeatable process captured in `.agent/sop/component-creation-process.md`. In short: - Plan props, events, and accessibility before coding. - Scaffold Vue SFCs with `<script setup lang="ts">` and two-space indentation. - Use Tailwind tokens from `tailwind.config.js` rather than custom values. - **Create Storybook stories** (`.stories.ts`) alongside each component for interactive development and documentation. - Keep documentation, preview examples, and data-testids in sync with implementation. ### Storybook Integration Every UI component must have a corresponding `.stories.ts` file that: - Documents all component variants and states - Provides interactive controls for props - Includes comprehensive examples (default, error, disabled, etc.) - Serves as living documentation with auto-generated props tables Run `yarn storybook` during development to iterate on components with instant feedback. ## Testing Standards - Unit tests live in `tests/unit/` and rely on Vitest + @vue/test-utils; name files `ComponentName.test.ts`. - Visual snapshots live in `tests/visual/`; cover every interactive state and rebaseline only after reviewing diffs. - Maintain ≄80% coverage by running `yarn test:coverage`; HTML reports are emitted to `coverage/index.html`. - End each iteration with `yarn test:all` so regressions surface early. For deeper guidance, reference `.agent/sop/testing-guide.md`. ## Contributing Before opening a pull request: - Review the contributor playbook in `AGENTS.md` (Repository Guidelines). - Use Conventional Commit prefixes (`fix:`, `docs:`, `chore:`) with imperative subjects ≤72 characters. - Fill PR descriptions with motivation, linked issues, screenshots for UI changes, and test evidence. ## Additional Resources - [Component creation process](.agent/sop/component-creation-process.md) - [Testing guide](.agent/sop/testing-guide.md) - [NPM Publishing guide](.agent/sop/npm-publishing.md) - [Nuxt documentation](https://nuxt.com/docs) - [Playwright documentation](https://playwright.dev/)