srcdev-nuxt-components 9.2.3 → 9.2.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,169 @@
1
+ # InputCopy Component
2
+
3
+ ## Overview
4
+
5
+ `InputCopy` renders a readonly text input with a copy-to-clipboard button. Displays a copyable value (e.g., license key, API token) with optional description text below. Shows visual feedback ("Copied!") in the button after a successful copy. Emits `copy` and `copied` events for consumer-side toast/feedback handling.
6
+
7
+ ---
8
+
9
+ ## Props reference
10
+
11
+ > **Hyphenation rule**: Vue's ESLint config enforces `vue/attribute-hyphenation`. Always write camelCase prop names hyphenated in templates: `:style-class-passthrough`.
12
+
13
+ | Prop (template form) | Type | Default | Notes |
14
+ | -------------------------- | ---------------------- | ---------------- | ------------------------------------------------------------ |
15
+ | `:value` | `string` | (required) | The text to copy to clipboard (e.g., license key, API token).|
16
+ | `:label` | `string` | (optional) | Short label for the field; used in aria-label if ariaLabel not set. |
17
+ | `:aria-label` | `string` | (optional) | Custom aria-label for the input; overrides label. |
18
+ | `:description` | `string` | (optional) | Helper text displayed below the input. |
19
+ | `:button-text` | `string` | `"Copy"` | Label on the copy button. |
20
+ | `:copied-text` | `string` | `"Copied!"` | Text shown in button after copy succeeds. |
21
+ | `:copied-duration` | `number` | `2000` | Milliseconds the "Copied!" state persists before resetting. |
22
+ | `:is-disabled` | `boolean` | `false` | Disables the copy button. |
23
+ | `:style-class-passthrough` | `string \| string[]` | `[]` | Extra CSS classes applied to the root element. |
24
+
25
+ ---
26
+
27
+ ## Events
28
+
29
+ | Event | Payload | Notes |
30
+ | -------- | -------------------- | ---------------------------------------------------------- |
31
+ | `copy` | `value: string` | Emitted when the copy button is clicked (before clipboard write). |
32
+ | `copied` | `value: string` | Emitted after successful clipboard write; fires after `copy`. |
33
+
34
+ ---
35
+
36
+ ## Slots
37
+
38
+ None. Use events to customize feedback behavior.
39
+
40
+ ---
41
+
42
+ ## CSS Token Customization
43
+
44
+ All `--input-copy-*` tokens can be overridden at global, page, or instance scope. See `CONSUMER-STYLING.md` in the component directory for full token documentation and examples.
45
+
46
+ **Common tokens:**
47
+ - `--input-copy-input-bg` — input field background
48
+ - `--input-copy-input-border` — input field border
49
+ - `--input-copy-button-bg` — copy button background
50
+ - `--input-copy-button-bg-hover` — button background on hover
51
+ - `--input-copy-description-color` — description text color
52
+
53
+ ---
54
+
55
+ ## Usage Examples
56
+
57
+ ### License key display (most common)
58
+
59
+ ```vue
60
+ <InputCopy
61
+ :value="licenseKey"
62
+ label="License key"
63
+ description="Your license key is ready to use. Copy it to embed in your application."
64
+ @copied="showSuccessToast('License key copied!')"
65
+ />
66
+ ```
67
+
68
+ ### API token with custom button text
69
+
70
+ ```vue
71
+ <InputCopy
72
+ :value="apiToken"
73
+ label="API token"
74
+ description="Do not share this token with anyone."
75
+ button-text="Copy token"
76
+ copied-text="Token copied!"
77
+ @copy="logCopy"
78
+ @copied="logCopied"
79
+ />
80
+ ```
81
+
82
+ ### Disabled state (e.g., loading or error)
83
+
84
+ ```vue
85
+ <InputCopy
86
+ :value="temporaryCode"
87
+ label="Temporary code"
88
+ button-text="Unavailable"
89
+ :is-disabled="isGenerating"
90
+ description="Code is being generated. Please wait."
91
+ />
92
+ ```
93
+
94
+ ### With custom styling via CSS tokens
95
+
96
+ ```vue
97
+ <InputCopy
98
+ :value="shareLink"
99
+ label="Share link"
100
+ description="Share this link with others"
101
+ style="
102
+ --input-copy-input-bg: #f0f0f0;
103
+ --input-copy-button-bg: var(--brand-primary);
104
+ --input-copy-button-text-color: white;
105
+ "
106
+ />
107
+ ```
108
+
109
+ ### With page-scoped styling
110
+
111
+ In your page's `<style>` block:
112
+
113
+ ```css
114
+ .success-page .input-copy {
115
+ --input-copy-input-border: 2px solid var(--success-color);
116
+ --input-copy-button-bg: var(--success-color);
117
+ --input-copy-description-color: var(--slate-06);
118
+ }
119
+ ```
120
+
121
+ Then in the template:
122
+
123
+ ```vue
124
+ <div class="success-page">
125
+ <InputCopy
126
+ :value="licenseKey"
127
+ label="Your license key"
128
+ description="Copy this key to activate the component in your application."
129
+ />
130
+ </div>
131
+ ```
132
+
133
+ ### With toast feedback (consumer-side)
134
+
135
+ ```vue
136
+ <template>
137
+ <InputCopy
138
+ :value="apiKey"
139
+ label="API key"
140
+ @copied="handleCopied"
141
+ />
142
+ </template>
143
+
144
+ <script setup>
145
+ const handleCopied = (value: string) => {
146
+ // Use your app's toast library
147
+ useToast().success(`Copied: ${value.slice(0, 8)}...`);
148
+ };
149
+ </script>
150
+ ```
151
+
152
+ ---
153
+
154
+ ## Accessibility
155
+
156
+ - Input always has `aria-label` set from `label` or `aria-label` prop
157
+ - Button has descriptive aria-label: "Copy [label] to clipboard"
158
+ - Button is disabled during the "Copied!" feedback window to prevent repeated clicks
159
+ - Icon-only display on mobile (<480px); text shown on desktop for clarity
160
+ - Readonly input has `readonly` attribute; not editable
161
+
162
+ ---
163
+
164
+ ## Notes
165
+
166
+ - **Clipboard API**: Uses native `navigator.clipboard.writeText()`. Fails silently if unavailable (e.g., insecure context).
167
+ - **Button text hide on mobile**: By default, only the copy icon displays on screens <480px. Text appears on desktop (≥480px).
168
+ - **No toast built-in**: This component does not show toasts. Listen to `@copied` event and use your app's toast library for feedback.
169
+ - **Manual reset**: The "Copied!" state automatically resets after `copied-duration` milliseconds. No manual reset needed.
@@ -0,0 +1,163 @@
1
+ # PricingCard Component
2
+
3
+ ## Overview
4
+
5
+ `PricingCard` renders a SaaS-style pricing plan card with plan name, price, description, feature list, and call-to-action button. Supports "Most Popular" highlight state with optional badge. Features are highly customizable via CSS token overrides, and the CTA button can be customized via the `#cta` slot for custom variants and themes.
6
+
7
+ ---
8
+
9
+ ## Props reference
10
+
11
+ > **Hyphenation rule**: Vue's ESLint config enforces `vue/attribute-hyphenation`. Always write camelCase prop names hyphenated in templates: `:style-class-passthrough`.
12
+
13
+ | Prop (template form) | Type | Default | Notes |
14
+ | -------------------------- | ----------------------------- | ------------ | ------------------------------------------------------------------ |
15
+ | `tag` | `"div" \| "section" \| "article"` | `"article"` | Root element tag for semantic HTML. |
16
+ | `:plan-name` | `string` | (required) | Plan/tier name (e.g., "Basic", "Professional", "Enterprise"). |
17
+ | `:price` | `number` | (required) | Price amount (e.g., `99`, `4.99`). Currency symbol added in template. |
18
+ | `:billing-period` | `string` | `"one-time"` | Billing frequency text (e.g., "monthly", "yearly"). |
19
+ | `:description` | `string` | (optional) | Short plan description. |
20
+ | `:features` | `string[]` | `[]` | Array of feature strings. Rendered with checkmark icons. |
21
+ | `:is-highlighted` | `boolean` | `false` | Highlight state; applies "Most Popular" badge, border, shadow, and scale. |
22
+ | `:cta-text` | `string` | `"Get started"` | Button label text. |
23
+ | `:cta-disabled` | `boolean` | `false` | Disables the CTA button. |
24
+ | `:style-class-passthrough` | `string \| string[]` | `[]` | Extra CSS classes applied to the card root. |
25
+
26
+ ---
27
+
28
+ ## Events
29
+
30
+ | Event | Payload | Notes |
31
+ | ------ | ---------- | ---------------------------------------- |
32
+ | `select` | `planName: string` | Emitted when the CTA button is clicked. |
33
+
34
+ ---
35
+
36
+ ## Slots
37
+
38
+ ### Default slot (features)
39
+
40
+ Override the default feature list rendering. Receives no slot scope.
41
+
42
+ ```vue
43
+ <PricingCard plan-name="Pro" :price="99">
44
+ <template #features>
45
+ <li>Custom feature HTML here</li>
46
+ </template>
47
+ </PricingCard>
48
+ ```
49
+
50
+ ### #cta slot
51
+
52
+ Customize the CTA button. Default renders `InputButtonCore` with theme support.
53
+
54
+ **Slot scope:**
55
+ - `ctaText: string` — button label from `:cta-text` prop
56
+ - `isDisabled: boolean` — button disabled state from `:cta-disabled` prop
57
+ - `planName: string` — plan name for context
58
+ - `onSelect: () => void` — callback to trigger `select` event
59
+
60
+ ```vue
61
+ <PricingCard plan-name="Pro" :price="99" @select="handleSelect">
62
+ <template #cta="{ ctaText, isDisabled, onSelect }">
63
+ <InputButtonCore
64
+ :button-text="ctaText"
65
+ variant="secondary"
66
+ theme="custom"
67
+ :readonly="isDisabled"
68
+ @click="onSelect"
69
+ />
70
+ </template>
71
+ </PricingCard>
72
+ ```
73
+
74
+ ---
75
+
76
+ ## CSS Token Customization
77
+
78
+ All `--pricing-card-*` tokens can be overridden at global, page, or instance scope. See `CONSUMER-STYLING.md` in the component directory for full token documentation and examples.
79
+
80
+ **Common tokens:**
81
+ - `--pricing-card-padding` — card internal spacing
82
+ - `--pricing-card-border-radius` — card corners
83
+ - `--pricing-card-cta-bg` — button background
84
+ - `--pricing-card-highlight-border` — highlighted card border
85
+ - `--pricing-card-name-color` — plan name text color
86
+
87
+ ---
88
+
89
+ ## Usage Examples
90
+
91
+ ### Single card with default button
92
+
93
+ ```vue
94
+ <PricingCard
95
+ plan-name="Basic"
96
+ :price="29.99"
97
+ billing-period="monthly"
98
+ description="Perfect for getting started"
99
+ :features="['Feature 1', 'Feature 2', 'Feature 3']"
100
+ cta-text="Get started"
101
+ @select="handleSelect"
102
+ />
103
+ ```
104
+
105
+ ### Highlighted "Most Popular" card
106
+
107
+ ```vue
108
+ <PricingCard
109
+ plan-name="Professional"
110
+ :price="79.99"
111
+ billing-period="monthly"
112
+ :is-highlighted="true"
113
+ :features="['All Basic features', 'Priority support', 'Advanced analytics']"
114
+ @select="handleSelect"
115
+ />
116
+ ```
117
+
118
+ ### Card with custom button variant
119
+
120
+ ```vue
121
+ <PricingCard
122
+ plan-name="Enterprise"
123
+ :price="199.99"
124
+ billing-period="monthly"
125
+ description="Everything you need"
126
+ :features="['Unlimited access', 'Dedicated support', 'Custom integrations']"
127
+ @select="handleSelect"
128
+ >
129
+ <template #cta="{ ctaText, isDisabled, onSelect }">
130
+ <InputButtonCore
131
+ :button-text="ctaText"
132
+ variant="primary"
133
+ :readonly="isDisabled"
134
+ @click="onSelect"
135
+ />
136
+ </template>
137
+ </PricingCard>
138
+ ```
139
+
140
+ ### Three-column grid with token customization
141
+
142
+ ```vue
143
+ <div class="pricing-grid">
144
+ <PricingCard
145
+ v-for="plan in plans"
146
+ :key="plan.id"
147
+ :plan-name="plan.name"
148
+ :price="plan.price"
149
+ :is-highlighted="plan.id === 'pro'"
150
+ :features="plan.features"
151
+ @select="handleSelect"
152
+ style="--pricing-card-padding: 2.5rem; --pricing-card-cta-bg: var(--brand-primary)"
153
+ />
154
+ </div>
155
+ ```
156
+
157
+ ---
158
+
159
+ ## Notes
160
+
161
+ - Feature checkmarks are always rendered with a teal checkmark (`✓`). Customize the color via `--teal-06` or component tokens.
162
+ - The `#cta` slot is preferred over CSS-only button customization when you need variant or theme changes.
163
+ - Highlighted cards apply a 1.05x scale transform — consider z-index when nesting in flex/grid layouts.
@@ -48,6 +48,7 @@ Each skill is a single markdown file named `<area>-<task>.md`.
48
48
  ├── qa-panel.md — collapsible dev-only panel for toggling component props live on a page (demo pages and consuming apps)
49
49
  ├── release-notes.md — produce release notes as a fenced markdown block from git log
50
50
  ├── pull-request-description.md — produce a PR description as a fenced markdown block from git diff vs main
51
+ ├── using-component-skills.md — discover and use component skills in consumer apps: where skills land, browsing patterns, workflow for deciding build vs. compose
51
52
  ├── composable-canonical-url.md — useCanonicalUrl: set <link rel="canonical"> from runtimeConfig.public.canonicalHost; layout setup, node types
52
53
  ├── composable-whatsapp.md — useWhatsApp: open pre-filled wa.me link from form payload; runtime config, security, usage
53
54
  ├── composable-zod-validation.md — useZodValidation: schema-driven form validation, error binding, submit flow, API error push
@@ -73,7 +74,8 @@ Each skill is a single markdown file named `<area>-<task>.md`.
73
74
  ├── expanding-panel.md — ExpandingPanel v-model, forceOpened, slots (summary/icon/content), ARIA wiring
74
75
  ├── glass-panel.md — GlassPanel props, slots, CSS token API (--glass-panel-bg/border-color/shadow/highlight), theming override
75
76
  ├── navigation-horizontal.md — NavigationHorizontal props, NavItemData type, CSS token API, import path gotcha
76
- ├── input-copy-core.md InputCopyCore: readonly copy-to-clipboard input; props, emits, slots, CSS classes, usage
77
+ ├── pricing-card.md PricingCard: SaaS-style plan card with highlight, feature list, #cta slot for button customization, CSS token API
78
+ ├── input-copy.md — InputCopy: readonly copy-to-clipboard input, visual feedback, Clipboard API, accessibility, CSS token API
77
79
  ├── banner-video.md — BannerVideo: full-width hero video banner, depth tier system, objectFit/objectPosition, playIcon/pauseIcon/toggle-icon slot, reduced-motion fallback, CSS tokens
78
80
  ├── grid-stack.md — GridStack: CSS Grid z-axis stacking, slot API, z-order rules, sizing, video+overlay and image+text patterns
79
81
  ├── scroll-reveal-frame.md — ScrollRevealFrame: generic parallax clipping frame, slot API, image grid pattern, CSS tokens, browser support
@@ -2,12 +2,14 @@
2
2
 
3
3
  ## Overview
4
4
 
5
- Prevent two common "forgot to run after install" problems in a consuming app:
5
+ Prevent common "forgot to run after install" problems in a consuming app:
6
6
 
7
7
  1. `nuxt prepare` — generates Nuxt type declarations. Skipping it causes TypeScript errors after install or package updates.
8
8
  2. `npm run setup:claude` — copies the latest `srcdev-nuxt-components` skills into `.claude/skills/srcdev-nuxt-components/`. Skipping it leaves Claude working from stale skill docs after a package update.
9
9
 
10
- A `postinstall` script runs both automatically after every `npm install`.
10
+ Additionally, `srcdev-nuxt-components` automatically copies VSCode snippet files (`.code-snippets`) to your `.vscode/` folder during its own postinstall, so components' code snippets are available immediately.
11
+
12
+ A consumer app's `postinstall` script runs both automatically after every `npm install`.
11
13
 
12
14
  ## Steps
13
15
 
@@ -41,5 +43,6 @@ From this point on, `npm install` and `npm ci` trigger both steps automatically.
41
43
  ## Notes
42
44
 
43
45
  - Skills land in `.claude/skills/srcdev-nuxt-components/` — safe to re-run without overwriting your own project's skills.
46
+ - VSCode snippets are copied to `.vscode/` automatically by the layer's postinstall — no extra step needed on the consumer's side. They're available in VSCode's autocomplete immediately after `npm install`.
44
47
  - `postinstall` also fires on `npm ci`, so CI environments get the skills too if they have a `.claude/` directory in the project.
45
48
  - If you do not want `postinstall` running in CI, guard it: `"postinstall": "[ \"$CI\" = \"true\" ] || (nuxt prepare && npm run setup:claude)"`.
@@ -0,0 +1,215 @@
1
+ # Using Component Skills
2
+
3
+ ## Overview
4
+
5
+ Component skills are reference documentation files for every reusable component in `srcdev-nuxt-components`. They land in your consumer app after running `npm run setup:claude` and serve two purposes:
6
+
7
+ 1. **As human-readable reference** — browse component skills to understand props, slots, CSS tokens, and usage patterns
8
+ 2. **As discovery tool** — before building custom components, check if a suitable pattern already exists in the layer
9
+
10
+ ---
11
+
12
+ ## Setup
13
+
14
+ ### 1. Copy skills from the layer
15
+
16
+ After scaffolding a new Nuxt app that extends `srcdev-nuxt-components`, run:
17
+
18
+ ```bash
19
+ npm run setup:claude
20
+ ```
21
+
22
+ This copies all skills (including component skills) into `.claude/skills/srcdev-nuxt-components/`.
23
+
24
+ ### 2. After upgrading the layer
25
+
26
+ When you upgrade `srcdev-nuxt-components` to a new version (which may include new components), re-run the command to refresh:
27
+
28
+ ```bash
29
+ npm run setup:claude
30
+ ```
31
+
32
+ ---
33
+
34
+ ## File structure
35
+
36
+ Component skills land in `.claude/skills/srcdev-nuxt-components/components/`:
37
+
38
+ ```
39
+ .claude/
40
+ ├── skills/
41
+ │ └── srcdev-nuxt-components/
42
+ │ ├── index.md — overview of all skills
43
+ │ ├── new-app-scaffold.md — scaffolding a new app
44
+ │ ├── theming-colour-ramps.md — theme customization
45
+ │ ├── composable-*.md — utility composables
46
+ │ └── components/
47
+ │ ├── pricing-card.md — SaaS pricing plan card
48
+ │ ├── input-copy.md — copy-to-clipboard input
49
+ │ ├── expanding-panel.md — single expand/collapse panel
50
+ │ ├── accordian-core.md — native accordion (grouped panels)
51
+ │ ├── display-avatar.md — circular avatar component
52
+ │ ├── card-core.md — generic card container
53
+ │ ├── auto-grid.md — responsive auto-fit grid
54
+ │ ├── display-dialog.md — native dialog overlay
55
+ │ ├── display-toast.md — toast notifications
56
+ │ └── ... (40+ more components)
57
+ ```
58
+
59
+ ---
60
+
61
+ ## Discovering components
62
+
63
+ ### Via your file explorer
64
+
65
+ Browse `.claude/skills/srcdev-nuxt-components/components/` to see all available components with one-line descriptions.
66
+
67
+ ### Via grep
68
+
69
+ Search for components by pattern:
70
+
71
+ ```bash
72
+ # Find all form-related components
73
+ grep -l "input\|form\|button" .claude/skills/srcdev-nuxt-components/components/*.md
74
+
75
+ # Find components with slot patterns
76
+ grep -l "slot" .claude/skills/srcdev-nuxt-components/components/*.md
77
+
78
+ # Find components with CSS token customization
79
+ grep -l "CSS token" .claude/skills/srcdev-nuxt-components/components/*.md
80
+ ```
81
+
82
+ ### Via Claude Code
83
+
84
+ If your `.claude/settings.json` includes the layer's skills in `additionalDirectories`, Claude can reference them:
85
+
86
+ ```json
87
+ {
88
+ "permissions": {
89
+ "additionalDirectories": [
90
+ "path/to/srcdev-nuxt-components/.claude/skills/components"
91
+ ]
92
+ }
93
+ }
94
+ ```
95
+
96
+ Then ask Claude: *"What button components are available in the layer?"* or *"Show me the expanding-panel skill."*
97
+
98
+ ---
99
+
100
+ ## Understanding a component skill
101
+
102
+ Each component skill documents:
103
+
104
+ ### Props
105
+
106
+ | Prop | Type | Default | Notes |
107
+ | --- | --- | --- | --- |
108
+ | `:prop-name` | type | default | What this prop does |
109
+
110
+ ### Slots
111
+
112
+ Explains what content goes inside each slot and provides scoped variables if applicable.
113
+
114
+ ### Events / Emits
115
+
116
+ When the component emits events and what data they carry.
117
+
118
+ ### CSS Tokens
119
+
120
+ All `--component-*` tokens available for customization via global/page/instance scope.
121
+
122
+ ### Usage Examples
123
+
124
+ Practical examples showing:
125
+ - Basic usage (simplest case)
126
+ - Common customizations
127
+ - Advanced patterns (slots, tokens, events)
128
+
129
+ ### Accessibility
130
+
131
+ ARIA attributes, keyboard support, screen reader behavior.
132
+
133
+ ### Notes
134
+
135
+ Edge cases, browser support, performance considerations, common gotchas.
136
+
137
+ ---
138
+
139
+ ## Workflow: Build a feature
140
+
141
+ ### 1. Understand the requirement
142
+
143
+ *"I need a contact form with error handling and field validation."*
144
+
145
+ ### 2. Search skills for similar patterns
146
+
147
+ ```bash
148
+ grep -l "form\|input\|validation" .claude/skills/srcdev-nuxt-components/components/*.md
149
+ ```
150
+
151
+ ### 3. Read relevant skills
152
+
153
+ Open 2–3 matching skills to see:
154
+ - What components already handle form inputs?
155
+ - What slots and CSS tokens do they expose?
156
+ - What validation patterns are documented?
157
+
158
+ ### 4. Decide: build vs. compose
159
+
160
+ **Compose existing components** if the layer has:
161
+ - Input components with validation props
162
+ - Card/container components for layout
163
+ - Button variants for form actions
164
+
165
+ **Build custom component** if you need something specific the layer doesn't provide.
166
+
167
+ ---
168
+
169
+ ## Examples
170
+
171
+ ### Pricing page
172
+
173
+ *Task: Build a pricing plan comparison with 3 tiers.*
174
+
175
+ 1. Search skills: `grep -l "price\|plan\|tier" components/*.md`
176
+ 2. Read `pricing-card.md` — describes PricingCard component, props, #cta slot, CSS tokens
177
+ 3. Use PricingCard in a grid layout, customize buttons via slot, override token colors via page-scoped CSS
178
+
179
+ ### FAQ section
180
+
181
+ *Task: Add expandable FAQ items.*
182
+
183
+ 1. Search skills: `grep -l "expand\|accordion\|collaps" components/*.md`
184
+ 2. Read `expanding-panel.md` — describes single panel behavior, v-model, slots
185
+ 3. Use ExpandingPanel in a v-for loop for FAQ items (no need to build custom accordion)
186
+
187
+ ### License key display
188
+
189
+ *Task: Show a copyable license key on success page.*
190
+
191
+ 1. Search skills: `grep -l "copy\|clipboard\|readonly" components/*.md`
192
+ 2. Read `input-copy.md` — describes readonly input, copy button, events, CSS tokens
193
+ 3. Use InputCopy component, listen to @copied event, show toast via consumer's toast library
194
+
195
+ ---
196
+
197
+ ## Updating skills
198
+
199
+ When the layer releases a new component or updates an existing one:
200
+
201
+ 1. **Upgrade the package**: `npm install srcdev-nuxt-components@latest`
202
+ 2. **Refresh skills**: `npm run setup:claude`
203
+ 3. **Read the new skill** to understand the new component's API
204
+
205
+ The skills always stay in sync with the layer's released version.
206
+
207
+ ---
208
+
209
+ ## Tips
210
+
211
+ - **Skim the index.md** in `.claude/skills/srcdev-nuxt-components/` to get an overview of all available skills
212
+ - **Reference skills when asking Claude** — "Here's the InputCopy skill: [paste content]. How do I customize the button color?"
213
+ - **CSS tokens are your friend** — most components expose tokens for customization without component changes
214
+ - **Slots > props for complexity** — if you need custom button behavior, use a #cta slot instead of adding button props to the component
215
+ - **Check accessibility notes** — ARIA labels, keyboard support, and screen reader behavior are documented per component
@@ -18,7 +18,7 @@
18
18
  ]
19
19
  },
20
20
  "SRCDEV PricingCard Highlighted": {
21
- "description": "PricingCard with 'Most Popular' highlight",
21
+ "description": "PricingCard with 'Most Popular' highlight and custom button",
22
22
  "scope": "vue,html",
23
23
  "body": [
24
24
  "<PricingCard",
@@ -33,7 +33,16 @@
33
33
  " '$7Feature 3',",
34
34
  " ]\"",
35
35
  " @select=\"$8handleSelect\"",
36
- "/>"
36
+ ">",
37
+ " <template #cta=\"{ ctaText, isDisabled, onSelect }\">",
38
+ " <InputButtonCore",
39
+ " :button-text=\"ctaText\"",
40
+ " variant=\"$9primary\"",
41
+ " :readonly=\"isDisabled\"",
42
+ " @click=\"onSelect\"",
43
+ " />",
44
+ " </template>",
45
+ "</PricingCard>"
37
46
  ]
38
47
  },
39
48
  "SRCDEV PricingCard Grid": {
@@ -69,6 +78,30 @@
69
78
  "</div>"
70
79
  ]
71
80
  },
81
+ "SRCDEV PricingCard Custom Button": {
82
+ "description": "PricingCard with custom button variant via #cta slot",
83
+ "scope": "vue,html",
84
+ "body": [
85
+ "<PricingCard",
86
+ " planName=\"$1Premium\"",
87
+ " :price=\"$2799\"",
88
+ " billingPeriod=\"$3one-time\"",
89
+ " description=\"$4All features included.\"",
90
+ " :features=\"['$5Feature 1', '$6Feature 2']\"",
91
+ " @select=\"$7handleSelect\"",
92
+ ">",
93
+ " <template #cta=\"{ ctaText, isDisabled, onSelect }\">",
94
+ " <InputButtonCore",
95
+ " :button-text=\"ctaText\"",
96
+ " variant=\"$8secondary\"",
97
+ " theme=\"$9default\"",
98
+ " :readonly=\"isDisabled\"",
99
+ " @click=\"onSelect\"",
100
+ " />",
101
+ " </template>",
102
+ "</PricingCard>"
103
+ ]
104
+ },
72
105
  "SRCDEV PricingCard CSS Override": {
73
106
  "description": "CSS override scaffold for PricingCard tokens",
74
107
  "scope": "css",
package/package.json CHANGED
@@ -1,11 +1,12 @@
1
1
  {
2
2
  "name": "srcdev-nuxt-components",
3
3
  "type": "module",
4
- "version": "9.2.3",
4
+ "version": "9.2.4",
5
5
  "main": "nuxt.config.ts",
6
6
  "types": "types.d.ts",
7
7
  "license": "MIT",
8
8
  "scripts": {
9
+ "postinstall": "node scripts/copy-snippets.mjs",
9
10
  "clean": "rm -rf .nuxt && rm -rf .output",
10
11
  "cleanall": "rm -rf node_modules && rm -rf .nuxt && rm -rf .output && rm package-lock.json",
11
12
  "reinstall": "rm -rf node_modules && npm install",
@@ -0,0 +1,38 @@
1
+ import { copyFileSync, mkdirSync, readdirSync } from 'fs';
2
+ import { join } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+
5
+ const __dirname = fileURLToPath(new URL('.', import.meta.url));
6
+ const srcDir = join(__dirname, '../.vscode');
7
+ const destDir = join(process.cwd(), '.vscode');
8
+
9
+ // Only run when installed as a package (not in the layer's own repo)
10
+ if (process.cwd() === join(__dirname, '..')) {
11
+ console.log('⊘ Skipping snippet copy (running in layer repo)');
12
+ process.exit(0);
13
+ }
14
+
15
+ mkdirSync(destDir, { recursive: true });
16
+
17
+ // Find and copy all .code-snippets files
18
+ try {
19
+ const files = readdirSync(srcDir).filter(file => file.endsWith('.code-snippets'));
20
+
21
+ if (files.length === 0) {
22
+ console.log('⊘ No snippet files found');
23
+ process.exit(0);
24
+ }
25
+
26
+ files.forEach(file => {
27
+ try {
28
+ copyFileSync(join(srcDir, file), join(destDir, file));
29
+ console.log(`✓ Copied VSCode snippet: ${file}`);
30
+ } catch (err) {
31
+ console.warn(`⚠ Failed to copy ${file}:`, err.message);
32
+ }
33
+ });
34
+
35
+ console.log(`✓ VSCode snippets installed to .vscode/`);
36
+ } catch (err) {
37
+ console.warn('⚠ Snippet installation skipped:', err.message);
38
+ }