srcdev-hair-treatments
v0.1.8
Published
[](https://github.com/srcdev/hair-treatments/actions/workflows/test.yml) [](https://badge.fury.io/js/srcdev-hai
Readme
SRCDEV Hair Treatments
Note: Although this repo is private and developed for use with websites we develop, you are welcome to use it.
A standalone Vue 3 component library providing a hair treatment consultation wizard. Distributed via npm — no Nuxt or framework dependency required.
Claude Code Skills
This package ships consumer-facing Claude Code skills — reference docs for using the component in your app — in .claude/skills/public/.
To make them available in your project, add this script to your package.json:
"setup:claude": "cp -r node_modules/srcdev-hair-treatments/.claude/skills/public/. .claude/skills/srcdev-hair-treatments"Then run it after install:
npm run setup:claudeSkills are copied into .claude/skills/srcdev-hair-treatments/ so they never conflict with or overwrite skills your own project defines. Re-running the script after a package update is safe.
Install
npm install srcdev-hair-treatmentsPeer dependency
Vue 3.4+ must be installed in the consuming app:
npm install vue@^3.4Basic Usage
Import the component and its bundled stylesheet:
import { TreatmentConsultant } from "srcdev-hair-treatments";
import "srcdev-hair-treatments/dist/style.css";<template>
<TreatmentConsultant />
</template>Consumer Requirements
The component intentionally does not impose a global rem reset or colour tokens on your app. You must supply both:
1. rem reset
The component uses rem units throughout. Add this to your app's global CSS:
html {
font-size: 62.5%; /* 1rem = 10px */
}2. Colour tokens
The component reads these CSS custom properties from :root. Define them in your app's global stylesheet:
:root {
--amber-01: oklch(0.945 0.064 75);
--amber-02: oklch(0.894 0.11 75);
/* ... --amber-03 through --amber-10 */
--green-00: oklch(0.99 0.02 157);
--green-01: oklch(0.95 0.078 157);
/* ... --green-02 through --green-10 */
--sunset-01: oklch(0.98 0.06 45);
/* ... --sunset-02 through --sunset-10 */
--red-00: oklch(98% 0.01 30);
/* ... --red-01 through --red-10 */
}Token values used during development are in .storybook/tokens.css.
Configuration
All behaviour, text, and data is configurable via the config prop. Pass any subset — it deep-merges with the defaults.
<TreatmentConsultant
:config="{
behaviour: { autoAdvance: true },
text: {
cta: {
bookHref: '/book',
bookLabel: 'Book Your Appointment',
},
},
}"
/>Behaviour
| Key | Type | Default | Description |
| ---------------------- | --------- | ------- | ---------------------------------------------------- |
| autoAdvance | boolean | false | Auto-advance to the next step on selection |
| allowMultipleTreatments | boolean | false | Allow selecting multiple treatments with conflict detection |
Text
All UI copy lives under config.text. The full shape is exported as TextConfig:
import type { TextConfig } from "srcdev-hair-treatments";Key sections:
| Path | Description |
| ---- | ----------- |
| text.navigation.steps | Step label array (5 items) |
| text.navigation.back / next / viewResults | Navigation button labels |
| text.steps.* | Step headings and subtitles |
| text.results.* | Results section headings, no-colour / no-treatment messages, suitability labels |
| text.summary.* | Summary panel column labels |
| text.cta.bookHref | Booking link URL |
| text.cta.bookLabel / disclaimer / resetLabel | CTA copy |
Text config is deep-merged — override only what you need.
Data Arrays
hairTypes, naturalColours, desiredColours, and treatments can be fully replaced. Arrays are not merged — pass the complete replacement array:
import { defaultConfig } from "srcdev-hair-treatments";
const config = {
naturalColours: [
...defaultConfig.naturalColours,
{ id: "custom", label: "Custom Blend", colour: "#abc123" },
],
};Overriding Styles
The component root class is .treatment-consultant. All internal CSS custom properties are scoped to it and can be overridden in your stylesheet:
.treatment-consultant {
/* Override the check badge colours */
--treatment-consultant-checked-surface-colour: hsl(220 80% 40%);
--treatment-consultant-checked-stroke-colour: hsl(220 80% 80%);
}You can also pass additional classes to the root element:
<TreatmentConsultant style-class-passthrough="my-custom-theme" />Exported API
import {
TreatmentConsultant, // Vue component
defaultConfig, // full default config object
mergeConfig, // utility: mergeConfig(defaultConfig, partialOverride)
} from "srcdev-hair-treatments";
import type {
TreatmentConsultantConfig,
DeepPartial,
TextConfig,
Treatment,
HairTypeOption,
ColourOption,
DesiredColourOption,
// ... other types
} from "srcdev-hair-treatments";Development
Prerequisites
- Node 20–22
- npm 10+
Commands
# Install dependencies
npm install
# Start Storybook dev server (http://localhost:6006)
npm run storybook
# Type check
npm run typecheck
# Lint
npm run lint
# Build library output (dist/)
npm run buildTesting
Unit Tests (Vitest)
# Watch mode
npm run test
# Single run
npm run test:run
# Browser UI
npm run test:ui
# Update snapshots
npm run test:updateVisual Regression Tests (Playwright)
Requires Storybook to be built and served first.
# 1. Build and serve Storybook
npm run storybook:serve
# 2. In a separate terminal, run visual tests
npm run playwright
# Update visual baselines after an intentional change
npm run playwright:updateVisual tests run across Chromium, Firefox, and WebKit.
What Each Layer Catches
| Change | Unit tests | Visual tests | | ------------------------------------- | :--------: | :----------: | | Class added / removed | ✅ | ✅ | | HTML structure changed | ✅ | ✅ | | Font / colour / spacing changed | ❌ | ✅ | | Prop or config logic broken | ✅ | ❌ | | Accessibility attribute missing | ✅ | ❌ |
Storybook
# Dev server
npm run storybook
# Build static output
npm run storybook:build
# Build and serve (used before Playwright)
npm run storybook:serve
# Clear caches (if styles appear stale)
npm run storybook:cache:cleanAfter clearing the cache, restart with
npm run storybook. Useful when@layerCSS changes aren't reflected in the running dev server.
Fonts
Fonts are served from local files in .storybook/public/_fonts/ and declared in .storybook/fonts.css.
| Font | Format | | ---------------- | ------ | | Inter | woff2 | | Playfair Display | woff2 |
Architecture
src/
├── components/
│ └── TreatmentConsultant.vue # Template + CSS only
├── composables/
│ └── useTreatmentConsultant.ts # All reactive state and actions
├── config/
│ ├── types.ts # Exported TypeScript interfaces
│ ├── defaults.ts # defaultConfig + mergeConfig utility
│ └── matrix.ts # Colour recommendation logic (private)
└── index.ts # Public API exportsThe recommendation matrix (natural colour × desired colour → suitability) is private to the package and not part of the public API.
