@stlhorizon/vue-ui 2.5.5 → 2.5.6

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.
Files changed (105) hide show
  1. package/README.md +1971 -552
  2. package/dist/index.esm.js +1839 -1854
  3. package/dist/index.js +15 -15
  4. package/dist/src/__tests__/Alert.spec.d.ts +2 -0
  5. package/dist/src/__tests__/Alert.spec.d.ts.map +1 -0
  6. package/dist/src/__tests__/Badge.spec.d.ts +2 -0
  7. package/dist/src/__tests__/Badge.spec.d.ts.map +1 -0
  8. package/dist/src/__tests__/Button.spec.d.ts +2 -0
  9. package/dist/src/__tests__/Button.spec.d.ts.map +1 -0
  10. package/dist/src/__tests__/Card.spec.d.ts +2 -0
  11. package/dist/src/__tests__/Card.spec.d.ts.map +1 -0
  12. package/dist/src/__tests__/Checkbox.spec.d.ts +2 -0
  13. package/dist/src/__tests__/Checkbox.spec.d.ts.map +1 -0
  14. package/dist/src/__tests__/Dropdown.spec.d.ts +2 -0
  15. package/dist/src/__tests__/Dropdown.spec.d.ts.map +1 -0
  16. package/dist/src/__tests__/Input.spec.d.ts +2 -0
  17. package/dist/src/__tests__/Input.spec.d.ts.map +1 -0
  18. package/dist/src/__tests__/Modal.spec.d.ts +2 -0
  19. package/dist/src/__tests__/Modal.spec.d.ts.map +1 -0
  20. package/dist/src/__tests__/Radio.spec.d.ts +2 -0
  21. package/dist/src/__tests__/Radio.spec.d.ts.map +1 -0
  22. package/dist/src/__tests__/Select.spec.d.ts +2 -0
  23. package/dist/src/__tests__/Select.spec.d.ts.map +1 -0
  24. package/dist/src/__tests__/Tabs.spec.d.ts +2 -0
  25. package/dist/src/__tests__/Tabs.spec.d.ts.map +1 -0
  26. package/dist/src/__tests__/integration/CardIntegration.spec.d.ts +2 -0
  27. package/dist/src/__tests__/integration/CardIntegration.spec.d.ts.map +1 -0
  28. package/dist/src/__tests__/integration/FormIntegration.spec.d.ts +2 -0
  29. package/dist/src/__tests__/integration/FormIntegration.spec.d.ts.map +1 -0
  30. package/dist/src/__tests__/integration/ModalIntegration.spec.d.ts +2 -0
  31. package/dist/src/__tests__/integration/ModalIntegration.spec.d.ts.map +1 -0
  32. package/dist/src/__tests__/integration/NavigationIntegration.spec.d.ts +2 -0
  33. package/dist/src/__tests__/integration/NavigationIntegration.spec.d.ts.map +1 -0
  34. package/dist/src/components/Accordion.vue.d.ts.map +1 -1
  35. package/dist/src/components/AccordionItem.vue.d.ts.map +1 -1
  36. package/dist/src/components/Alert.vue.d.ts.map +1 -1
  37. package/dist/src/components/Avatar.vue.d.ts.map +1 -1
  38. package/dist/src/components/Badge.vue.d.ts.map +1 -1
  39. package/dist/src/components/Breadcrumb.vue.d.ts.map +1 -1
  40. package/dist/src/components/Button.vue.d.ts +2 -2
  41. package/dist/src/components/Button.vue.d.ts.map +1 -1
  42. package/dist/src/components/ButtonGroup.vue.d.ts.map +1 -1
  43. package/dist/src/components/Calendar.vue.d.ts.map +1 -1
  44. package/dist/src/components/Card.vue.d.ts.map +1 -1
  45. package/dist/src/components/Checkbox.vue.d.ts.map +1 -1
  46. package/dist/src/components/DataTable.vue.d.ts +1 -1
  47. package/dist/src/components/DataTable.vue.d.ts.map +1 -1
  48. package/dist/src/components/DataTableFilters.vue.d.ts.map +1 -1
  49. package/dist/src/components/DataTableHeader.vue.d.ts.map +1 -1
  50. package/dist/src/components/DataTablePagination.vue.d.ts +2 -2
  51. package/dist/src/components/DataTablePagination.vue.d.ts.map +1 -1
  52. package/dist/src/components/DataTableRow.vue.d.ts.map +1 -1
  53. package/dist/src/components/DataTableToolBar.vue.d.ts.map +1 -1
  54. package/dist/src/components/DatePicker.vue.d.ts.map +1 -1
  55. package/dist/src/components/Dropdown.vue.d.ts.map +1 -1
  56. package/dist/src/components/DropdownItem.vue.d.ts.map +1 -1
  57. package/dist/src/components/FileUpload.vue.d.ts.map +1 -1
  58. package/dist/src/components/Footer.vue.d.ts.map +1 -1
  59. package/dist/src/components/FormField.vue.d.ts.map +1 -1
  60. package/dist/src/components/Header.vue.d.ts.map +1 -1
  61. package/dist/src/components/Image.vue.d.ts.map +1 -1
  62. package/dist/src/components/Input.vue.d.ts.map +1 -1
  63. package/dist/src/components/InputGroup.vue.d.ts.map +1 -1
  64. package/dist/src/components/Label.vue.d.ts.map +1 -1
  65. package/dist/src/components/Link.vue.d.ts.map +1 -1
  66. package/dist/src/components/ListItem.vue.d.ts.map +1 -1
  67. package/dist/src/components/Logo.vue.d.ts.map +1 -1
  68. package/dist/src/components/MenuItem.vue.d.ts.map +1 -1
  69. package/dist/src/components/Modal.vue.d.ts.map +1 -1
  70. package/dist/src/components/ModalHeader.vue.d.ts.map +1 -1
  71. package/dist/src/components/Notification.vue.d.ts.map +1 -1
  72. package/dist/src/components/Option.vue.d.ts +2 -2
  73. package/dist/src/components/Option.vue.d.ts.map +1 -1
  74. package/dist/src/components/ProgressBar.vue.d.ts.map +1 -1
  75. package/dist/src/components/Radio.vue.d.ts +2 -2
  76. package/dist/src/components/Radio.vue.d.ts.map +1 -1
  77. package/dist/src/components/ReusableFormModal.vue.d.ts.map +1 -1
  78. package/dist/src/components/STLLoader.vue.d.ts +2 -2
  79. package/dist/src/components/STLLoader.vue.d.ts.map +1 -1
  80. package/dist/src/components/Search.vue.d.ts.map +1 -1
  81. package/dist/src/components/Sidebar.vue.d.ts.map +1 -1
  82. package/dist/src/components/Slider.vue.d.ts +2 -2
  83. package/dist/src/components/Slider.vue.d.ts.map +1 -1
  84. package/dist/src/components/Spinner.vue.d.ts.map +1 -1
  85. package/dist/src/components/StepperItem.vue.d.ts +2 -2
  86. package/dist/src/components/StepperItem.vue.d.ts.map +1 -1
  87. package/dist/src/components/Tab.vue.d.ts.map +1 -1
  88. package/dist/src/components/TabPanel.vue.d.ts.map +1 -1
  89. package/dist/src/components/Text.vue.d.ts.map +1 -1
  90. package/dist/src/components/Timeline.vue.d.ts +2 -2
  91. package/dist/src/components/Timeline.vue.d.ts.map +1 -1
  92. package/dist/src/components/TimelineItem.vue.d.ts +2 -2
  93. package/dist/src/components/TimelineItem.vue.d.ts.map +1 -1
  94. package/dist/src/components/Toast.vue.d.ts.map +1 -1
  95. package/dist/src/components/Tooltip.vue.d.ts.map +1 -1
  96. package/dist/src/layouts/DefaultLayout.vue.d.ts.map +1 -1
  97. package/dist/src/layouts/ErrorLayout.vue.d.ts +2 -2
  98. package/dist/src/views/AnalyticsPage.vue.d.ts +0 -6
  99. package/dist/src/views/authentication/ForgotPasswordPage.vue.d.ts.map +1 -1
  100. package/dist/src/views/authentication/LoginPage.vue.d.ts.map +1 -1
  101. package/dist/tsconfig.tsbuildinfo +1 -1
  102. package/dist/vue-ui.css +1 -1
  103. package/package.json +5 -2
  104. package/dist/src/components/RiskModal.vue.d.ts +0 -13
  105. package/dist/src/components/RiskModal.vue.d.ts.map +0 -1
package/README.md CHANGED
@@ -1,662 +1,2081 @@
1
- # Vue UI Component Library
1
+ # STL Horizon Vue Atomic UI Library
2
2
 
3
- A comprehensive Vue.js component library built with Tailwind CSS, featuring 60+ components for building modern web applications.
3
+ A comprehensive Vue.js component library with Tailwind CSS styling, featuring automated testing, semantic versioning, and CI/CD pipelines.
4
4
 
5
- <!-- <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.5.2/css/all.min.css" /> --> add the link in the index.html
6
- ## Installation
5
+ ## Development & Release Workflow
6
+
7
+ ### Development
7
8
 
8
9
  ```bash
9
- npm install @stlhorizon/vue-ui
10
+ # Install dependencies
11
+ npm install
12
+
13
+ # Start development server
14
+ npm run dev
15
+
16
+ # Run tests
17
+ npm run test:unit
18
+
19
+ # Run tests with coverage
20
+ npm run test:coverage
21
+
22
+ # Build for production
23
+ npm run build
24
+
25
+ # Preview production build
26
+ npm run preview
10
27
  ```
11
28
 
12
- ## Setup
29
+ ### Commit Convention
13
30
 
14
- 1. Install the required peer dependencies:
31
+ This project uses [Conventional Commits](https://conventionalcommits.org/) for automatic semantic versioning:
15
32
 
16
33
  ```bash
17
- npm install vue@^3.5.18
34
+ # Features (minor version bump: 1.2.3 → 1.3.0)
35
+ git commit -m "feat: add new component"
36
+
37
+ # Bug fixes (patch version bump: 1.2.3 → 1.2.4)
38
+ git commit -m "fix: resolve button click issue"
39
+
40
+ # Breaking changes (major version bump: 1.2.3 → 2.0.0)
41
+ git commit -m "feat!: redesign component API
42
+
43
+ BREAKING CHANGE: component props have changed"
44
+
45
+ # Other changes (patch version bump)
46
+ git commit -m "docs: update component documentation"
47
+ git commit -m "refactor: improve component performance"
48
+ git commit -m "test: add component tests"
18
49
  ```
19
50
 
20
- 2. Import the base styles in your main CSS file:
51
+ ### Automatic Versioning & Publishing
52
+
53
+ The project uses GitHub Actions for automated semantic versioning and NPM publishing:
54
+
55
+ - **Triggers**: Push to `main` branch after tests pass
56
+ - **Version Bumps**:
57
+ - `major`: Breaking changes (BREAKING CHANGE or `!:` in commit)
58
+ - `minor`: New features (`feat:` commits)
59
+ - `patch`: Bug fixes (`fix:` commits) or other changes
60
+ - **Process**:
61
+ 1. Run comprehensive test suite
62
+ 2. Analyze commits since last release
63
+ 3. Bump version automatically
64
+ 4. Create git tag and commit
65
+ 5. Publish to NPM with public access
66
+
67
+ ## Testing
68
+
69
+ This library includes comprehensive testing with both unit and integration tests.
70
+
71
+ ### Test Structure
21
72
 
22
- ```css
23
- @import '@stlhorizon/vue-ui/dist/vue-ui.css';
73
+ ```
74
+ src/__tests__/
75
+ ├── *.spec.js # Unit tests for individual components
76
+ └── integration/ # Integration tests for component combinations
77
+ ├── FormIntegration.spec.js
78
+ ├── ModalIntegration.spec.js
79
+ ├── CardIntegration.spec.js
80
+ └── NavigationIntegration.spec.js
24
81
  ```
25
82
 
26
- 3. Configure your `tailwind.config.js` to include the library's content:
83
+ ### Testing Types
27
84
 
28
- ```js
29
- /** @type {import('tailwindcss').Config} */
30
- export default {
31
- content: [
32
- "./src/**/*.{vue,js,ts,jsx,tsx}",
33
- "./node_modules/@stlhorizon/vue-ui/**/*.{vue,js,ts,jsx,tsx}"
34
- ],
35
- // ... rest of your config
36
- }
85
+ #### Unit Tests
86
+ - Individual component functionality
87
+ - Props, events, and styling validation
88
+ - Accessibility testing
89
+ - Error handling
90
+
91
+ #### Integration Tests
92
+ - **Form Integration**: Complete form workflows with Input, Button, Select, Checkbox
93
+ - **Modal Integration**: Modal with form submission and alert interactions
94
+ - **Card Integration**: Cards with headers, content, footers, and actions
95
+ - **Navigation Integration**: Dropdown menus and breadcrumb navigation
96
+
97
+ ### CI/CD Pipeline
98
+
99
+ The project uses GitHub Actions for automated testing and releases:
100
+
101
+ - **Triggers**: Push/PR to `main` and `develop` branches
102
+ - **Node.js versions**: 18.x, 20.x, 22.x
103
+ - **Checks**: Linting, unit tests, integration tests, build verification
104
+ - **Coverage**: Uploaded to Codecov with 70% threshold requirements
105
+ - **Release**: Automatic semantic versioning and NPM publishing
106
+
107
+ ### Coverage Requirements
108
+
109
+ - Branches: 70%
110
+ - Functions: 70%
111
+ - Lines: 70%
112
+ - Statements: 70%
113
+
114
+ ### Running Tests Locally
115
+
116
+ ```bash
117
+ # Run all tests
118
+ npm run test:unit
119
+
120
+ # Run tests once (CI mode)
121
+ npm run test:unit:run
122
+
123
+ # Run with coverage
124
+ npm run test:coverage
125
+
126
+ # Run only integration tests
127
+ npm run test:unit -- --testPathPattern=integration
128
+
129
+ # Run specific test file
130
+ npm run test:unit -- Button.spec.js
37
131
  ```
38
132
 
39
- 4. **Important: Vue Template Compiler Configuration**
133
+ ### Test Configuration
40
134
 
41
- If you encounter the error: *"Component provided template option but runtime compilation is not supported in this build of Vue"*, you need to configure your bundler to use the full Vue build that includes the template compiler.
135
+ - **Framework**: Vitest with jsdom environment
136
+ - **Coverage**: V8 provider with HTML, JSON, and text reports
137
+ - **Mocking**: FontAwesome icons and other external dependencies
138
+ - **Assertions**: Built-in Vitest matchers
42
139
 
43
- ### For Vite users:
140
+ ### Writing Tests
44
141
 
45
- Add this to your `vite.config.js`:
142
+ When adding new components, follow these patterns:
46
143
 
47
- ```js
48
- import { defineConfig } from 'vite'
49
- import vue from '@vitejs/plugin-vue'
144
+ 1. **Unit Tests**: Test component props, events, slots, and styling
145
+ 2. **Integration Tests**: Test component combinations and workflows
146
+ 3. **Accessibility**: Include ARIA attributes and keyboard navigation tests
147
+ 4. **Edge Cases**: Test disabled states, loading states, and error conditions
50
148
 
51
- export default defineConfig({
52
- plugins: [vue()],
53
- resolve: {
54
- alias: {
55
- 'vue': 'vue/dist/vue.esm-bundler.js'
56
- }
57
- }
149
+ Example test structure:
150
+ ```javascript
151
+ import { describe, it, expect } from 'vitest'
152
+ import { mount } from '@vue/test-utils'
153
+ import Component from '../components/Component.vue'
154
+
155
+ describe('Component', () => {
156
+ it('renders with default props', () => {
157
+ const wrapper = mount(Component)
158
+ expect(wrapper.exists()).toBe(true)
159
+ })
160
+
161
+ it('handles user interactions', async () => {
162
+ const wrapper = mount(Component)
163
+ await wrapper.find('button').trigger('click')
164
+ expect(wrapper.emitted('click')).toHaveLength(1)
165
+ })
58
166
  })
59
167
  ```
60
168
 
61
- ### For Webpack users:
169
+ ---
170
+
171
+ # Component Usage Documentation
172
+
173
+ This document provides comprehensive usage examples and API reference for all Vue components in the STL Horizon Vue Atomic UI library.
174
+
175
+ ## Table of Contents
176
+
177
+ - [Accordion](#accordion)
178
+ - [AccordionItem](#accordionitem)
179
+ - [Alert](#alert)
180
+ - [Avatar](#avatar)
181
+ - [Badge](#badge)
182
+ - [Breadcrumb](#breadcrumb)
183
+ - [Button](#button)
184
+ - [ButtonGroup](#buttongroup)
185
+ - [Calendar](#calendar)
186
+ - [Card](#card)
187
+ - [CardBody](#cardbody)
188
+ - [CardContent](#cardcontent)
189
+ - [CardFooter](#cardfooter)
190
+ - [CardHeader](#cardheader)
191
+ - [CardTitle](#cardtitle)
192
+ - [Checkbox](#checkbox)
193
+ - [DataTable](#datatable)
194
+ - [DatePicker](#datepicker)
195
+ - [Divider](#divider)
196
+ - [Dropdown](#dropdown)
197
+ - [DropdownItem](#dropdownitem)
198
+ - [FormField](#formfield)
199
+ - [Icon](#icon)
200
+ - [Image](#image)
201
+ - [Input](#input)
202
+ - [Label](#label)
203
+ - [Modal](#modal)
204
+ - [Progress](#progress)
205
+ - [Radio](#radio)
206
+ - [ReusableFormModal](#reusableformmodal)
207
+ - [Select](#select)
208
+ - [Slider](#slider)
209
+ - [Spinner](#spinner)
210
+ - [Switch](#switch)
211
+ - [Textarea](#textarea)
212
+
213
+ ## Accordion
214
+
215
+ An expandable/collapsible component for organizing content into sections.
216
+
217
+ ### Props
218
+
219
+ | Prop | Type | Default | Description |
220
+ |------|------|---------|-------------|
221
+ | `items` | `Array` | - | Array of accordion items with title and content |
222
+ | `modelValue` | `Number \| Array` | `null` | Currently expanded item(s) index(es) |
223
+ | `multiple` | `Boolean` | `false` | Allow multiple items to be expanded |
224
+ | `variant` | `String` | `'default'` | Visual style (default, bordered, filled, flush) |
225
+ | `size` | `String` | `'md'` | Size variant (sm, md, lg) |
226
+ | `disabled` | `Boolean` | `false` | Whether the accordion is disabled |
227
+
228
+ ### Events
229
+
230
+ | Event | Payload | Description |
231
+ |-------|---------|-------------|
232
+ | `update:modelValue` | `Number \| Array` | Emitted when expanded items change |
233
+ | `change` | `{ index, expanded }` | Emitted when an item is toggled |
234
+
235
+ ### Slots
236
+
237
+ | Slot | Description |
238
+ |------|-------------|
239
+ | `header-{index}` | Custom header content for specific item |
240
+ | `content-{index}` | Custom content for specific item |
241
+ | `content` | Fallback content slot |
242
+
243
+ ### Example
62
244
 
63
- Add this to your `webpack.config.js`:
245
+ ```vue
246
+ <template>
247
+ <Accordion
248
+ v-model="expandedItems"
249
+ :items="accordionItems"
250
+ variant="bordered"
251
+ size="lg"
252
+ multiple
253
+ />
254
+ </template>
64
255
 
65
- ```js
66
- module.exports = {
67
- resolve: {
68
- alias: {
69
- 'vue$': 'vue/dist/vue.esm-bundler.js'
70
- }
256
+ <script setup>
257
+ import { ref } from 'vue'
258
+ import Accordion from '@/components/Accordion.vue'
259
+
260
+ const expandedItems = ref([0])
261
+ const accordionItems = [
262
+ {
263
+ id: 'item1',
264
+ title: 'What is Vue?',
265
+ content: 'Vue is a progressive JavaScript framework for building user interfaces.'
266
+ },
267
+ {
268
+ id: 'item2',
269
+ title: 'Why use Vue?',
270
+ content: 'Vue offers a gentle learning curve, excellent performance, and great ecosystem.'
71
271
  }
72
- }
272
+ ]
273
+ </script>
73
274
  ```
74
275
 
75
- ### For Nuxt 3 users:
276
+ ## AccordionItem
76
277
 
77
- Add this to your `nuxt.config.ts`:
278
+ A single expandable item for use within an accordion structure.
78
279
 
79
- ```ts
80
- export default defineNuxtConfig({
81
- alias: {
82
- 'vue': 'vue/dist/vue.esm-bundler.js'
83
- }
84
- })
280
+ ### Props
281
+
282
+ | Prop | Type | Default | Description |
283
+ |------|------|---------|-------------|
284
+ | `variant` | `String` | `'default'` | Visual style (default, bordered, filled, flush) |
285
+ | `size` | `String` | `'md'` | Size variant (sm, md, lg) |
286
+
287
+ ### Slots
288
+
289
+ | Slot | Description |
290
+ |------|-------------|
291
+ | `header` | Header content |
292
+ | `content` | Content to show when expanded |
293
+
294
+ ### Example
295
+
296
+ ```vue
297
+ <template>
298
+ <AccordionItem variant="bordered">
299
+ <template #header>
300
+ <h3>Custom Header</h3>
301
+ </template>
302
+ <template #content>
303
+ <p>This is the content that expands.</p>
304
+ </template>
305
+ </AccordionItem>
306
+ </template>
307
+
308
+ <script setup>
309
+ import AccordionItem from '@/components/AccordionItem.vue'
310
+ </script>
85
311
  ```
86
312
 
87
- ## Usage
313
+ ## Avatar
88
314
 
89
- ### Global Registration (Recommended)
315
+ A component for displaying user avatars with image, initials, or icon fallback.
90
316
 
91
- ### Font awesome icons integration
92
- First install the icons using this commands
93
- npm install @fortawesome/vue-fontawesome@latest-3
94
- npm install @fortawesome/free-solid-svg-icons
95
- npm install @fortawesome/free-regular-svg-icons
96
- npm install @fortawesome/free-brands-svg-icons
97
- npm install @fortawesome/fontawesome-svg-core
317
+ ### Props
98
318
 
99
- <!-- then import the libraries like the code below -->
319
+ | Prop | Type | Default | Description |
320
+ |------|------|---------|-------------|
321
+ | `src` | `String` | - | Image source URL |
322
+ | `alt` | `String` | - | Alt text for image |
323
+ | `initials` | `String` | - | User initials to display |
324
+ | `size` | `String` | `'md'` | Size variant (xs, sm, md, lg, xl) |
325
+ | `variant` | `String` | `'default'` | Visual style (default, outline) |
100
326
 
101
- ```js
102
- // main.js
103
- import { createApp } from 'vue'
104
- import { createPinia } from 'pinia'
105
- import App from './App.vue'
106
- import router from './router'
107
- import VueUI from '@stlhorizon/vue-ui'
108
- import "@stlhorizon/vue-ui/dist/vue-ui.css"
109
- import VueApexCharts from 'vue3-apexcharts'
110
- import { library } from '@fortawesome/fontawesome-svg-core'
111
- import { fas } from '@fortawesome/free-solid-svg-icons'
112
- import { far } from '@fortawesome/free-regular-svg-icons'
113
- import { fab } from '@fortawesome/free-brands-svg-icons'
114
- import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome'
327
+ ### Example
115
328
 
116
- library.add(fas, far, fab)
329
+ ```vue
330
+ <template>
331
+ <div class="flex space-x-4">
332
+ <Avatar src="/path/to/avatar.jpg" alt="User Avatar" />
333
+ <Avatar initials="JD" size="lg" />
334
+ <Avatar variant="outline" />
335
+ </div>
336
+ </template>
337
+
338
+ <script setup>
339
+ import Avatar from '@/components/Avatar.vue'
340
+ </script>
341
+ ```
117
342
 
118
- const app = createApp(App)
343
+ ## Breadcrumb
119
344
 
120
- app.use(createPinia())
121
- app.use(router)
345
+ A navigation component showing the current page's location in a hierarchy.
122
346
 
123
- app.component('font-awesome-icon', FontAwesomeIcon)
124
- app.use(VueApexCharts);
125
- app.use(VueUI) // register the UI
347
+ ### Props
126
348
 
127
- app.mount('#app')
349
+ | Prop | Type | Default | Description |
350
+ |------|------|---------|-------------|
351
+ | `items` | `Array` | - | Array of breadcrumb items with label and optional href |
352
+ | `separator` | `String` | `'chevron-right'` | Icon name for separator |
353
+ | `ariaLabel` | `String` | `'Breadcrumb navigation'` | Accessibility label |
354
+ | `variant` | `String` | `'default'` | Visual style (default, ghost) |
128
355
 
356
+ ### Example
357
+
358
+ ```vue
359
+ <template>
360
+ <Breadcrumb :items="breadcrumbItems" />
361
+ </template>
362
+
363
+ <script setup>
364
+ import Breadcrumb from '@/components/Breadcrumb.vue'
365
+
366
+ const breadcrumbItems = [
367
+ { label: 'Home', href: '/' },
368
+ { label: 'Products', href: '/products' },
369
+ { label: 'Electronics' }
370
+ ]
371
+ </script>
129
372
  ```
130
373
 
131
- ### Individual Component Import
374
+ ## ButtonGroup
375
+
376
+ A container component for grouping related buttons together.
377
+
378
+ ### Props
379
+
380
+ | Prop | Type | Default | Description |
381
+ |------|------|---------|-------------|
382
+ | `orientation` | `String` | `'horizontal'` | Layout direction (horizontal, vertical) |
383
+ | `size` | `String` | `'default'` | Size variant (sm, default, lg) |
384
+ | `variant` | `String` | `'default'` | Visual style (default, outline, ghost) |
385
+ | `ariaLabel` | `String` | - | Accessibility label for the group |
386
+
387
+ ### Slots
388
+
389
+ | Slot | Description |
390
+ |------|-------------|
391
+ | `default` | Button components |
392
+
393
+ ### Example
132
394
 
133
395
  ```vue
134
396
  <template>
135
- <div>
136
- <Button variant="default" size="lg">Click me</Button>
137
- <Input placeholder="Enter text..." />
138
- <DataTable :data="tableData" :columns="columns" />
139
- </div>
397
+ <ButtonGroup variant="outline" aria-label="Text formatting">
398
+ <Button>Bold</Button>
399
+ <Button>Italic</Button>
400
+ <Button>Underline</Button>
401
+ </ButtonGroup>
140
402
  </template>
141
403
 
142
404
  <script setup>
143
- import { Button, Input, DataTable } from '@stlhorizon/vue-ui'
144
- </script>
145
- ```
146
-
147
- ## Available Components
148
-
149
- ### Basic UI Components
150
- - **Avatar** - User profile pictures with fallbacks
151
- - **Badge** - Status indicators and labels
152
- - **Button** - Interactive buttons with variants
153
- - **Checkbox** - Form checkboxes with states
154
- - **Divider** - Visual content separators
155
- - **Icon** - Lucide icon wrapper
156
- - **Image** - Enhanced image component
157
- - **Input** - Form input fields
158
- - **Label** - Form field labels
159
- - **Link** - Styled navigation links
160
- - **Logo** - Brand logo component
161
- - **Option** - Select option items
162
- - **ProgressBar** - Progress indicators
163
- - **Radio** - Radio button inputs
164
- - **Select** - Dropdown select menus
165
- - **Spinner** - Loading indicators
166
- - **Switch** - Toggle switches
167
- - **Text** - Typography component
168
- - **Textarea** - Multi-line text inputs
169
- - **Tooltip** - Hover information
170
- - **Typography** - Text styling utilities
171
-
172
- ### Layout Components
173
- - **Alert** - Notification messages
174
- - **Breadcrumb** - Navigation breadcrumbs
175
- - **ButtonGroup** - Grouped button sets
176
- - **Card** - Content containers
177
- - **CardHeader** - Card header sections
178
- - **CardBody** - Card content areas
179
- - **CardFooter** - Card footer sections
180
-
181
- ### Form Components
182
- - **DatePicker** - Date selection inputs
183
- - **Dropdown** - Dropdown menus
184
- - **DropdownItem** - Dropdown menu items
185
- - **FileUpload** - File upload interface
186
- - **FormField** - Form field wrapper
187
- - **InputGroup** - Grouped input elements
188
-
189
- ### Navigation Components
190
- - **ListItem** - List item elements
191
- - **MenuItem** - Menu item components
192
- - **Pagination** - Page navigation
193
- - **SearchBox** - Search input interface
194
-
195
- ### Modal & Overlay Components
196
- - **Modal** - Dialog overlays
197
- - **ModalHeader** - Modal header sections
198
- - **ModalBody** - Modal content areas
199
- - **ModalFooter** - Modal footer sections
200
- - **Notification** - System notifications
201
- - **Toast** - Temporary messages
202
-
203
- ### Interactive Components
204
- - **Slider** - Range input sliders
205
- - **Stepper** - Step-by-step navigation
206
- - **StepperItem** - Individual step items
207
- - **Tab** - Tab navigation
208
- - **TabPanel** - Tab content panels
209
-
210
- ### Complex Components
211
- - **Accordion** - Collapsible content sections
212
- - **AccordionItem** - Individual accordion items
213
- - **Calendar** - Date picker calendar
214
- - **Carousel** - Image/content carousels
215
- - **CarouselSlide** - Individual carousel slides
216
- - **DataTable** - Advanced data tables
217
- - **DataTableHeader** - Table header component
218
- - **DataTableRow** - Table row component
219
- - **DataTableCell** - Table cell component
220
- - **DataTablePagination** - Table pagination
221
- - **DataTableFilters** - Table filtering
222
- - **DataTableToolBar** - Table toolbar
223
-
224
- ### Layout Templates
225
- - **Footer** - Page footer sections
226
- - **Header** - Page header sections
227
- - **Hero** - Hero banner sections
228
- - **MainNavigation** - Primary navigation
229
- - **MobileNavigation** - Mobile-responsive navigation
230
- - **SidebarNavigation** - Sidebar navigation
231
- - **Sidebar** - Sidebar layout component
232
- - **Timeline** - Event timeline display
233
- - **TimelineItem** - Individual timeline items
234
-
235
- ### Form Templates
236
- - **LoginForm** - Complete login form
237
- - **RegistrationForm** - Complete registration form
238
-
239
- ### Pre-built Layouts
240
- - **DefaultLayout** - Standard app layout
241
- - **ErrorLayout** - Error page layout
242
- - **AuthLayout** - Authentication page layout
243
-
244
- ## Component Examples
245
-
246
- ### Button Variants
247
- ```vue
248
- <Button variant="default">Default</Button>
249
- <Button variant="destructive">Destructive</Button>
250
- <Button variant="outline">Outline</Button>
251
- <Button variant="secondary">Secondary</Button>
252
- <Button variant="ghost">Ghost</Button>
253
- <Button variant="link">Link</Button>
254
- ```
255
-
256
- ### DataTable Usage
257
- ```vue
258
- <template>
259
- <DataTable
260
- :data="users"
261
- :columns="columns"
262
- :filterable="true"
263
- :sortable="true"
264
- :paginated="true"
405
+ import ButtonGroup from '@/components/ButtonGroup.vue'
406
+ import Button from '@/components/Button.vue'
407
+ </script>
408
+ ```
409
+
410
+ ## Calendar
411
+
412
+ A standalone calendar component for date selection with month navigation.
413
+
414
+ ### Props
415
+
416
+ | Prop | Type | Default | Description |
417
+ |------|------|---------|-------------|
418
+ | `id` | `String` | - | Custom ID |
419
+ | `modelValue` | `String \| Date` | - | Selected date |
420
+ | `disabled` | `Boolean` | `false` | Whether disabled |
421
+ | `required` | `Boolean` | `false` | Whether required |
422
+ | `min` | `String \| Date` | - | Minimum selectable date |
423
+ | `max` | `String \| Date` | - | Maximum selectable date |
424
+ | `placeholder` | `String` | `'Select date'` | Placeholder text |
425
+ | `format` | `String` | `'MM/DD/YYYY'` | Date format |
426
+ | `clearable` | `Boolean` | `true` | Show clear button |
427
+ | `showToday` | `Boolean` | `true` | Show today button |
428
+ | `calendarPosition` | `String` | `'left-0'` | Calendar dropdown position |
429
+ | `ariaDescribedby` | `String` | - | ARIA describedby attribute |
430
+
431
+ ### Events
432
+
433
+ | Event | Payload | Description |
434
+ |-------|---------|-------------|
435
+ | `update:modelValue` | `String` | Emitted when date changes |
436
+
437
+ ### Example
438
+
439
+ ```vue
440
+ <template>
441
+ <Calendar
442
+ v-model="selectedDate"
443
+ placeholder="Pick a date"
444
+ format="YYYY-MM-DD"
445
+ :min="'2023-01-01'"
446
+ :max="'2023-12-31'"
265
447
  />
266
448
  </template>
267
449
 
268
450
  <script setup>
269
- const users = [
270
- { id: 1, name: 'John Doe', email: 'john@example.com' },
271
- { id: 2, name: 'Jane Smith', email: 'jane@example.com' }
272
- ]
451
+ import { ref } from 'vue'
452
+ import Calendar from '@/components/Calendar.vue'
273
453
 
274
- const columns = [
275
- { key: 'name', label: 'Name', sortable: true },
276
- { key: 'email', label: 'Email', sortable: true }
277
- ]
454
+ const selectedDate = ref('')
278
455
  </script>
279
456
  ```
280
457
 
281
- ### Layout Usage
458
+ ## Divider
459
+
460
+ A visual separator component for dividing content sections.
461
+
462
+ ### Props
463
+
464
+ | Prop | Type | Default | Description |
465
+ |------|------|---------|-------------|
466
+ | `orientation` | `String` | `'horizontal'` | Orientation (horizontal, vertical) |
467
+ | `size` | `String` | `'md'` | Size variant (sm, md, lg) |
468
+ | `color` | `String` | `'gray'` | Color variant (gray, primary, secondary) |
469
+ | `faded` | `Boolean` | `false` | Whether to apply opacity |
470
+ | `label` | `String` | - | Label text for horizontal dividers |
471
+ | `spacing` | `String` | - | Custom spacing classes |
472
+
473
+ ### Example
474
+
282
475
  ```vue
283
476
  <template>
284
- <DefaultLayout>
285
- <template #header>
286
- <Header title="My App" />
287
- </template>
288
-
289
- <template #sidebar>
290
- <Sidebar :items="navItems" />
291
- </template>
292
-
293
- <template #default>
294
- <Card>
295
- <CardHeader>
296
- <CardTitle>Welcome</CardTitle>
297
- </CardHeader>
298
- <CardBody>
299
- <Text>Your content here</Text>
300
- </CardBody>
301
- </Card>
477
+ <div>
478
+ <p>Content above</p>
479
+ <Divider />
480
+ <p>Content below</p>
481
+
482
+ <Divider orientation="vertical" class="h-6" />
483
+
484
+ <Divider label="Section Break" />
485
+ </div>
486
+ </template>
487
+
488
+ <script setup>
489
+ import Divider from '@/components/Divider.vue'
490
+ </script>
491
+ ```
492
+
493
+ ## Dropdown
494
+
495
+ A dropdown menu component with customizable trigger and placement.
496
+
497
+ ### Props
498
+
499
+ | Prop | Type | Default | Description |
500
+ |------|------|---------|-------------|
501
+ | `triggerText` | `String` | `'Options'` | Text for default trigger |
502
+ | `placement` | `String` | `'bottom-start'` | Dropdown position (bottom-start, bottom-end, top-start, top-end) |
503
+ | `variant` | `String` | `'default'` | Trigger button variant (default, outline, ghost) |
504
+
505
+ ### Slots
506
+
507
+ | Slot | Description |
508
+ |------|-------------|
509
+ | `trigger` | Custom trigger content |
510
+ | `default` | Dropdown menu items |
511
+
512
+ ### Example
513
+
514
+ ```vue
515
+ <template>
516
+ <Dropdown>
517
+ <template #trigger>
518
+ <Button variant="outline">Menu</Button>
302
519
  </template>
303
- </DefaultLayout>
520
+ <DropdownItem @click="action1">Action 1</DropdownItem>
521
+ <DropdownItem @click="action2">Action 2</DropdownItem>
522
+ <DropdownItem variant="destructive" @click="delete">Delete</DropdownItem>
523
+ </Dropdown>
304
524
  </template>
525
+
526
+ <script setup>
527
+ import Dropdown from '@/components/Dropdown.vue'
528
+ import DropdownItem from '@/components/DropdownItem.vue'
529
+ import Button from '@/components/Button.vue'
530
+
531
+ const action1 = () => console.log('Action 1')
532
+ const action2 = () => console.log('Action 2')
533
+ const delete = () => console.log('Delete')
534
+ </script>
305
535
  ```
306
536
 
307
- ## Troubleshooting
537
+ ## DropdownItem
308
538
 
309
- ### Common Issues
539
+ An individual item within a dropdown menu.
310
540
 
311
- 1. **Template compilation error**: Make sure you've configured the Vue alias as described in the setup section above.
541
+ ### Props
312
542
 
313
- 2. **Styles not loading**: Ensure you're importing the CSS file: `@import '@stlhorizon/vue-ui/dist/vue-ui.css';`
543
+ | Prop | Type | Default | Description |
544
+ |------|------|---------|-------------|
545
+ | `href` | `String` | - | Link URL (makes item a link) |
546
+ | `icon` | `String` | - | Icon name |
547
+ | `shortcut` | `String` | - | Keyboard shortcut text |
548
+ | `disabled` | `Boolean` | `false` | Whether disabled |
549
+ | `variant` | `String` | `'default'` | Visual variant (default, destructive) |
314
550
 
315
- 3. **Components not found**: Make sure you've either registered components globally or imported them individually.
551
+ ### Events
316
552
 
317
- 4. **Tailwind classes not working**: Verify that your `tailwind.config.js` includes the library's content path.
553
+ | Event | Payload | Description |
554
+ |-------|---------|-------------|
555
+ | `click` | `Event` | Emitted when item is clicked |
318
556
 
319
- ## Publishing to NPM
557
+ ### Slots
320
558
 
321
- 1. **Update package details in `package.json`:**
322
- - Change package name if needed
323
- - Update repository URL, author, and description
324
- - Set the correct version number
559
+ | Slot | Description |
560
+ |------|-------------|
561
+ | `default` | Item content |
325
562
 
326
- 2. **Build the library:**
327
- ```bash
328
- npm run build
329
- ```
563
+ ### Example
330
564
 
331
- 3. **Login to npm:**
332
- ```bash
333
- npm login
334
- ```
565
+ ```vue
566
+ <template>
567
+ <DropdownItem icon="user" shortcut="⌘U" @click="profile">
568
+ Profile
569
+ </DropdownItem>
570
+ </template>
335
571
 
336
- 4. **Publish:**
337
- ```bash
338
- npm publish --access public
339
- ```
572
+ <script setup>
573
+ import DropdownItem from '@/components/DropdownItem.vue'
340
574
 
341
- ## Development
575
+ const profile = () => console.log('Open profile')
576
+ </script>
577
+ ```
342
578
 
343
- ```bash
344
- # Install dependencies
345
- npm install
579
+ ## Image
346
580
 
347
- # Start development server
348
- npm run dev
581
+ An enhanced image component with loading states, aspect ratios, and error handling.
349
582
 
350
- # Build library
351
- npm run build
583
+ ### Props
352
584
 
353
- # Lint code
354
- npm run lint
355
- ```
356
-
357
- ## Requirements
358
-
359
- - Node.js: `^20.19.0 || >=22.12.0`
360
- - Vue.js: `^3.5.18`
361
-
362
- ## License
363
-
364
- MIT
365
-
366
- toast usage example in app.vue
367
-
368
- <!-- Example App.vue setup -->
369
- <template>
370
- <div id="app">
371
- <!-- Your application content -->
372
- <div class="p-8 space-y-6">
373
- <h1 class="text-3xl font-bold">Toast Examples - Sonner Style</h1>
374
-
375
- <!-- Basic Usage -->
376
- <section class="space-y-4">
377
- <h2 class="text-xl font-semibold">Basic Usage</h2>
378
- <div class="flex flex-wrap gap-2">
379
- <button
380
- @click="showBasicToast"
381
- class="px-4 py-2 bg-blue-500 text-white rounded hover:bg-blue-600"
382
- >
383
- Basic Toast
384
- </button>
385
-
386
- <button
387
- @click="showSuccessToast"
388
- class="px-4 py-2 bg-green-500 text-white rounded hover:bg-green-600"
389
- >
390
- Success
391
- </button>
392
-
393
- <button
394
- @click="showErrorToast"
395
- class="px-4 py-2 bg-red-500 text-white rounded hover:bg-red-600"
396
- >
397
- Error
398
- </button>
399
-
400
- <button
401
- @click="showWarningToast"
402
- class="px-4 py-2 bg-yellow-500 text-white rounded hover:bg-yellow-600"
403
- >
404
- Warning
405
- </button>
406
- </div>
407
- </section>
408
-
409
- <!-- With Titles and Descriptions -->
410
- <section class="space-y-4">
411
- <h2 class="text-xl font-semibold">With Titles & Descriptions</h2>
412
- <div class="flex flex-wrap gap-2">
413
- <button
414
- @click="showRichToast"
415
- class="px-4 py-2 bg-purple-500 text-white rounded hover:bg-purple-600"
416
- >
417
- Rich Toast
418
- </button>
419
-
420
- <button
421
- @click="showActionToast"
422
- class="px-4 py-2 bg-indigo-500 text-white rounded hover:bg-indigo-600"
423
- >
424
- With Action
425
- </button>
426
- </div>
427
- </section>
428
-
429
- <!-- Promise Examples -->
430
- <section class="space-y-4">
431
- <h2 class="text-xl font-semibold">Promise Toasts</h2>
432
- <div class="flex flex-wrap gap-2">
433
- <button
434
- @click="simulateSuccess"
435
- class="px-4 py-2 bg-emerald-500 text-white rounded hover:bg-emerald-600"
436
- >
437
- Promise Success
438
- </button>
439
-
440
- <button
441
- @click="simulateError"
442
- class="px-4 py-2 bg-rose-500 text-white rounded hover:bg-rose-600"
443
- >
444
- Promise Error
445
- </button>
446
-
447
- <button
448
- @click="simulateUpload"
449
- class="px-4 py-2 bg-cyan-500 text-white rounded hover:bg-cyan-600"
450
- >
451
- File Upload
452
- </button>
453
- </div>
454
- </section>
455
-
456
- <!-- Advanced -->
457
- <section class="space-y-4">
458
- <h2 class="text-xl font-semibold">Advanced</h2>
459
- <div class="flex flex-wrap gap-2">
460
- <button
461
- @click="showPersistent"
462
- class="px-4 py-2 bg-gray-500 text-white rounded hover:bg-gray-600"
463
- >
464
- Persistent
465
- </button>
466
-
467
- <button
468
- @click="showCustomDuration"
469
- class="px-4 py-2 bg-orange-500 text-white rounded hover:bg-orange-600"
470
- >
471
- 10s Duration
472
- </button>
473
-
474
- <button
475
- @click="toast.dismissAll"
476
- class="px-4 py-2 bg-gray-700 text-white rounded hover:bg-gray-800"
477
- >
478
- Clear All
479
- </button>
480
- </div>
481
- </section>
482
-
483
- <!-- Real-world Examples -->
484
- <section class="space-y-4">
485
- <h2 class="text-xl font-semibold">Real-world Examples</h2>
486
- <div class="space-y-2">
487
- <button
488
- @click="handleFormSubmit"
489
- class="block px-4 py-2 bg-blue-600 text-white rounded hover:bg-blue-700"
490
- >
491
- Submit Form
492
- </button>
493
-
494
- <button
495
- @click="handleFileUpload"
496
- class="block px-4 py-2 bg-green-600 text-white rounded hover:bg-green-700"
497
- >
498
- Upload File
499
- </button>
500
-
501
- <button
502
- @click="handleDeleteItem"
503
- class="block px-4 py-2 bg-red-600 text-white rounded hover:bg-red-700"
504
- >
505
- Delete Item
506
- </button>
507
- </div>
508
- </section>
509
- </div>
585
+ | Prop | Type | Default | Description |
586
+ |------|------|---------|-------------|
587
+ | `src` | `String` | - | Image source URL |
588
+ | `alt` | `String` | `''` | Alt text |
589
+ | `aspectRatio` | `String` | `'auto'` | Aspect ratio (auto, square, 16/9, 4/3, 3/2) |
590
+ | `objectFit` | `String` | `'cover'` | Object fit (cover, contain, fill, none, scale-down) |
591
+ | `loading` | `String` | `'lazy'` | Loading strategy (lazy, eager) |
592
+ | `showSpinner` | `Boolean` | `true` | Show loading spinner |
593
+
594
+ ### Events
510
595
 
511
- <!-- Toaster component - add once in your root -->
512
- <Toaster
513
- position="bottom-center"
514
- :rich-colors="true"
515
- :close-button="true"
596
+ | Event | Payload | Description |
597
+ |-------|---------|-------------|
598
+ | `load` | `Event` | Emitted when image loads |
599
+ | `error` | `Event` | Emitted when image fails to load |
600
+
601
+ ### Example
602
+
603
+ ```vue
604
+ <template>
605
+ <div class="grid grid-cols-3 gap-4">
606
+ <Image
607
+ src="/path/to/image1.jpg"
608
+ alt="Image 1"
609
+ aspect-ratio="square"
610
+ />
611
+ <Image
612
+ src="/path/to/image2.jpg"
613
+ alt="Image 2"
614
+ aspect-ratio="16/9"
615
+ object-fit="contain"
516
616
  />
517
617
  </div>
518
618
  </template>
519
619
 
520
620
  <script setup>
521
- import { toast } from './lib/toast.js'
522
- import Toaster from './components/Toast.vue'
621
+ import Image from '@/components/Image.vue'
622
+ </script>
623
+ ```
523
624
 
524
- // Basic examples
525
- const showBasicToast = () => {
526
- toast("Hello World!")
527
- }
625
+ ## Slider
528
626
 
529
- const showSuccessToast = () => {
530
- toast.success("Operation completed successfully!")
531
- }
627
+ A customizable range slider component for selecting numeric values.
532
628
 
533
- const showErrorToast = () => {
534
- toast.error("Something went wrong!")
535
- }
629
+ ### Props
536
630
 
537
- const showWarningToast = () => {
538
- toast.warning("Please check your input")
539
- }
631
+ | Prop | Type | Default | Description |
632
+ |------|------|---------|-------------|
633
+ | `modelValue` | `Number \| String` | `0` | The current value of the slider |
634
+ | `min` | `Number` | `0` | Minimum value |
635
+ | `max` | `Number` | `100` | Maximum value |
636
+ | `step` | `Number` | `1` | Step increment |
540
637
 
541
- // Rich content
542
- const showRichToast = () => {
543
- toast.success("Profile updated", {
544
- title: "Success",
545
- description: "Your profile has been updated successfully.",
546
- duration: 6000
547
- })
548
- }
638
+ ### Events
549
639
 
550
- const showActionToast = () => {
551
- toast("Event has been created", {
552
- action: {
553
- label: "Undo",
554
- onClick: () => toast.info("Undo clicked!")
555
- }
556
- })
557
- }
640
+ | Event | Payload | Description |
641
+ |-------|---------|-------------|
642
+ | `update:modelValue` | `Number` | Emitted when the slider value changes |
558
643
 
559
- // Promise examples
560
- const simulateSuccess = () => {
561
- const promise = new Promise((resolve) => {
562
- setTimeout(() => resolve({ name: "John Doe" }), 2000)
563
- })
644
+ ### Example
564
645
 
565
- toast.promise(promise, {
566
- loading: "Loading user data...",
567
- success: (data) => `Welcome ${data.name}!`,
568
- error: "Failed to load user"
569
- })
570
- }
646
+ ```vue
647
+ <template>
648
+ <Slider v-model="volume" :min="0" :max="100" :step="5" />
649
+ </template>
571
650
 
572
- const simulateError = () => {
573
- const promise = new Promise((_, reject) => {
574
- setTimeout(() => reject(new Error("Network timeout")), 2000)
575
- })
651
+ <script setup>
652
+ import { ref } from 'vue'
653
+ import Slider from '@/components/Slider.vue'
576
654
 
577
- toast.promise(promise, {
578
- loading: "Connecting...",
579
- success: "Connected successfully!",
580
- error: (err) => `Connection failed: ${err.message}`
581
- })
582
- }
655
+ const volume = ref(50)
656
+ </script>
657
+ ```
583
658
 
584
- const simulateUpload = () => {
585
- const promise = new Promise((resolve) => {
586
- setTimeout(() => resolve(), 3000)
587
- })
659
+ ## Input
588
660
 
589
- toast.promise(promise, {
590
- loading: "Uploading file...",
591
- success: "File uploaded successfully!",
592
- error: "Upload failed"
593
- })
594
- }
661
+ A versatile input component supporting various types and features.
595
662
 
596
- // Advanced
597
- const showPersistent = () => {
598
- toast.info("This stays until dismissed", {
599
- duration: 0,
600
- title: "Persistent Notification"
601
- })
602
- }
663
+ ### Props
603
664
 
604
- const showCustomDuration = () => {
605
- toast.warning("This will stay for 10 seconds", {
606
- duration: 10000
607
- })
665
+ | Prop | Type | Default | Description |
666
+ |------|------|---------|-------------|
667
+ | `modelValue` | `String \| Number` | `''` | The input value |
668
+ | `type` | `String` | `'text'` | Input type (text, email, password, number, tel, url, search, date, color) |
669
+ | `placeholder` | `String` | `''` | Placeholder text |
670
+ | `disabled` | `Boolean` | `false` | Whether the input is disabled |
671
+ | `readonly` | `Boolean` | `false` | Whether the input is readonly |
672
+ | `required` | `Boolean` | `false` | Whether the input is required |
673
+ | `size` | `String` | `'md'` | Size variant (sm, md, lg) |
674
+ | `variant` | `String` | `'default'` | Visual variant (default, error, success) |
675
+ | `iconLeft` | `String \| Object` | `null` | Icon component for left side |
676
+ | `iconRight` | `String \| Object` | `null` | Icon component for right side |
677
+ | `clearable` | `Boolean` | `false` | Show clear button when input has value |
678
+ | `clearLabel` | `String` | `'Clear input'` | Accessibility label for clear button |
679
+ | `autocomplete` | `String` | `null` | Autocomplete attribute |
680
+ | `error` | `String` | `null` | Error message |
681
+ | `id` | `String` | `null` | Custom ID for the input |
682
+
683
+ ### Events
684
+
685
+ | Event | Payload | Description |
686
+ |-------|---------|-------------|
687
+ | `update:modelValue` | `String \| Number` | Emitted when input value changes |
688
+ | `blur` | `Event` | Emitted on blur |
689
+ | `focus` | `Event` | Emitted on focus |
690
+ | `clear` | - | Emitted when clear button is clicked |
691
+ | `keydown` | `Event` | Emitted on keydown |
692
+
693
+ ### Exposed Methods
694
+
695
+ - `focus()`: Focus the input
696
+ - `blur()`: Blur the input
697
+ - `select()`: Select all text in the input
698
+
699
+ ### Example
700
+
701
+ ```vue
702
+ <template>
703
+ <Input
704
+ v-model="email"
705
+ type="email"
706
+ placeholder="Enter your email"
707
+ :iconLeft="MailIcon"
708
+ clearable
709
+ required
710
+ />
711
+ </template>
712
+
713
+ <script setup>
714
+ import { ref } from 'vue'
715
+ import Input from '@/components/Input.vue'
716
+ import MailIcon from '@/components/icons/MailIcon.vue'
717
+
718
+ const email = ref('')
719
+ </script>
720
+ ```
721
+
722
+ ## DatePicker
723
+
724
+ A date picker component with calendar dropdown.
725
+
726
+ ### Props
727
+
728
+ | Prop | Type | Default | Description |
729
+ |------|------|---------|-------------|
730
+ | `id` | `String` | - | Custom ID |
731
+ | `modelValue` | `String \| Date` | - | Selected date |
732
+ | `disabled` | `Boolean` | `false` | Whether disabled |
733
+ | `required` | `Boolean` | `false` | Whether required |
734
+ | `min` | `String \| Date` | - | Minimum selectable date |
735
+ | `max` | `String \| Date` | - | Maximum selectable date |
736
+ | `placeholder` | `String` | `'Select date'` | Placeholder text |
737
+ | `format` | `String` | `'MM/DD/YYYY'` | Date format |
738
+ | `clearable` | `Boolean` | `true` | Show clear button |
739
+ | `showToday` | `Boolean` | `true` | Show today button in calendar |
740
+ | `calendarPosition` | `String` | `'left-0 bottom-full'` | Calendar dropdown position |
741
+ | `ariaDescribedby` | `String` | - | ARIA describedby attribute |
742
+
743
+ ### Events
744
+
745
+ | Event | Payload | Description |
746
+ |-------|---------|-------------|
747
+ | `update:modelValue` | `String` | Emitted when date changes |
748
+
749
+ ### Example
750
+
751
+ ```vue
752
+ <template>
753
+ <DatePicker
754
+ v-model="selectedDate"
755
+ placeholder="Choose a date"
756
+ format="YYYY-MM-DD"
757
+ :min="minDate"
758
+ :max="maxDate"
759
+ />
760
+ </template>
761
+
762
+ <script setup>
763
+ import { ref } from 'vue'
764
+ import DatePicker from '@/components/DatePicker.vue'
765
+
766
+ const selectedDate = ref('')
767
+ const minDate = '2023-01-01'
768
+ const maxDate = '2023-12-31'
769
+ </script>
770
+ ```
771
+
772
+ ## ReusableFormModal
773
+
774
+ A reusable modal component for creating and editing forms with various field types.
775
+
776
+ ### Props
777
+
778
+ | Prop | Type | Default | Description |
779
+ |------|------|---------|-------------|
780
+ | `modelValue` | `Boolean` | `false` | Modal visibility |
781
+ | `modalType` | `String` | - | 'create' or 'edit' |
782
+ | `entityName` | `String` | - | Name of the entity being created/edited |
783
+ | `fields` | `Array` | - | Array of field configurations |
784
+ | `initialData` | `Object` | `null` | Initial form data for editing |
785
+ | `loading` | `Boolean` | `false` | Loading state |
786
+ | `customValidation` | `Function` | `null` | Custom validation function |
787
+ | `modalSize` | `String` | `'4xl'` | Modal size |
788
+ | `modalResizable` | `Boolean` | `false` | Whether modal is resizable |
789
+
790
+ ### Events
791
+
792
+ | Event | Payload | Description |
793
+ |-------|---------|-------------|
794
+ | `update:modelValue` | `Boolean` | Modal visibility changes |
795
+ | `submit` | `{ formData, modalType, originalData }` | Form submission |
796
+ | `close` | - | Modal close |
797
+
798
+ ### Field Configuration
799
+
800
+ Each field in the `fields` array should have:
801
+
802
+ ```javascript
803
+ {
804
+ name: 'fieldName', // Required
805
+ label: 'Field Label', // Required
806
+ type: 'text', // Required: text, number, password, textarea, select, checkbox, slider, date, color
807
+ placeholder: 'Placeholder',
808
+ required: false,
809
+ disabled: false,
810
+ min: 0, // For number/slider/date
811
+ max: 100, // For number/slider/date
812
+ step: 1, // For slider
813
+ rows: 3, // For textarea
814
+ options: [{ value: '1', label: 'Option 1' }], // For select
815
+ checkboxLabel: 'Check this', // For checkbox
816
+ format: 'MM/DD/YYYY', // For date
817
+ clearable: true, // For date
818
+ showToday: true, // For date
819
+ calendarPosition: 'left-0 bottom-full', // For date
820
+ validate: (value, formData) => errorMessage || null, // Custom validation
821
+ onChange: (value, formData) => {}, // Change handler
822
+ errorMessage: 'Custom error message'
608
823
  }
824
+ ```
825
+
826
+ ### Example
609
827
 
610
- // Real-world examples matching your use case
611
- const handleFormSubmit = () => {
612
- // Simulate validation
613
- const validationInfo = { isValid: Math.random() > 0.3 }
614
-
615
- if (!validationInfo.isValid) {
616
- toast.error("Please select a vehicle that can accommodate your passenger and luggage requirements.")
617
- return
828
+ ```vue
829
+ <template>
830
+ <ReusableFormModal
831
+ v-model="showModal"
832
+ :modalType="modalType"
833
+ entityName="User"
834
+ :fields="userFields"
835
+ :initialData="editingUser"
836
+ :loading="submitting"
837
+ @submit="handleSubmit"
838
+ />
839
+ </template>
840
+
841
+ <script setup>
842
+ import { ref } from 'vue'
843
+ import ReusableFormModal from '@/components/ReusableFormModal.vue'
844
+
845
+ const showModal = ref(false)
846
+ const modalType = ref('create')
847
+ const editingUser = ref(null)
848
+ const submitting = ref(false)
849
+
850
+ const userFields = [
851
+ {
852
+ name: 'name',
853
+ label: 'Full Name',
854
+ type: 'text',
855
+ required: true
856
+ },
857
+ {
858
+ name: 'email',
859
+ label: 'Email',
860
+ type: 'email',
861
+ required: true
862
+ },
863
+ {
864
+ name: 'age',
865
+ label: 'Age',
866
+ type: 'number',
867
+ min: 18,
868
+ max: 100
869
+ },
870
+ {
871
+ name: 'bio',
872
+ label: 'Biography',
873
+ type: 'textarea',
874
+ rows: 4
875
+ },
876
+ {
877
+ name: 'department',
878
+ label: 'Department',
879
+ type: 'select',
880
+ options: [
881
+ { value: 'engineering', label: 'Engineering' },
882
+ { value: 'design', label: 'Design' },
883
+ { value: 'marketing', label: 'Marketing' }
884
+ ]
885
+ },
886
+ {
887
+ name: 'isActive',
888
+ label: 'Active',
889
+ type: 'checkbox',
890
+ checkboxLabel: 'User is active'
891
+ },
892
+ {
893
+ name: 'rating',
894
+ label: 'Rating',
895
+ type: 'slider',
896
+ min: 1,
897
+ max: 5,
898
+ step: 1
899
+ },
900
+ {
901
+ name: 'birthDate',
902
+ label: 'Birth Date',
903
+ type: 'date',
904
+ format: 'YYYY-MM-DD'
618
905
  }
619
-
620
- // Simulate form submission
621
- const submitPromise = new Promise((resolve) => {
622
- setTimeout(() => resolve(), 2000)
623
- })
624
-
625
- toast.promise(submitPromise, {
626
- loading: "Submitting form...",
627
- success: "Form submitted successfully!",
628
- error: "Failed to submit form"
629
- })
906
+ ]
907
+
908
+ const handleSubmit = ({ formData, modalType }) => {
909
+ submitting.value = true
910
+ // Handle form submission
911
+ console.log('Submitted:', formData, modalType)
912
+ submitting.value = false
913
+ showModal.value = false
630
914
  }
915
+ </script>
916
+ ```
631
917
 
632
- const handleFileUpload = () => {
633
- const uploadPromise = new Promise((resolve, reject) => {
634
- setTimeout(() => {
635
- if (Math.random() > 0.5) {
636
- resolve({ filename: "document.pdf", size: "2.3MB" })
637
- } else {
638
- reject(new Error("File too large"))
639
- }
640
- }, 1500)
641
- })
918
+ ## Button
642
919
 
643
- toast.promise(uploadPromise, {
644
- loading: "Uploading file...",
645
- success: (data) => `${data.filename} (${data.size}) uploaded successfully!`,
646
- error: (err) => `Upload failed: ${err.message}`
647
- })
648
- }
920
+ A versatile button component with multiple variants, sizes, and states.
649
921
 
650
- const handleDeleteItem = () => {
651
- toast.error("Item will be deleted permanently", {
652
- title: "Are you sure?",
653
- action: {
654
- label: "Delete",
655
- onClick: () => {
656
- toast.success("Item deleted successfully")
657
- }
658
- }
659
- })
660
- }
922
+ ### Props
923
+
924
+ | Prop | Type | Default | Description |
925
+ |------|------|---------|-------------|
926
+ | `variant` | `String` | `'default'` | Visual style (default, destructive, outline, secondary, ghost, link, success, warning, info, subtle, dark, light, primaryOutline, destructiveOutline, successOutline, gradient) |
927
+ | `size` | `String` | `'default'` | Size variant (default, xs, sm, lg, icon) |
928
+ | `disabled` | `Boolean` | `false` | Whether the button is disabled |
929
+ | `loading` | `Boolean` | `false` | Shows loading spinner |
930
+ | `loadingText` | `String` | `null` | Text to show when loading |
931
+
932
+ ### Slots
933
+
934
+ | Slot | Description |
935
+ |------|-------------|
936
+ | `icon` | Icon content (shown before text when not loading) |
937
+ | `default` | Button text content |
938
+
939
+ ### Example
940
+
941
+ ```vue
942
+ <template>
943
+ <div class="space-x-2">
944
+ <Button variant="default">Default</Button>
945
+ <Button variant="outline" size="sm">Outline</Button>
946
+ <Button variant="destructive" :loading="true" loadingText="Deleting...">
947
+ Delete
948
+ </Button>
949
+ <Button variant="icon" size="icon">
950
+ <template #icon>
951
+ <svg class="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24">
952
+ <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 4v16m8-8H4" />
953
+ </svg>
954
+ </template>
955
+ </Button>
956
+ </div>
957
+ </template>
958
+
959
+ <script setup>
960
+ import Button from '@/components/Button.vue'
661
961
  </script>
962
+ ```
963
+
964
+ ## Alert
965
+
966
+ A notification component for displaying messages with different variants and optional actions.
967
+
968
+ ### Props
662
969
 
970
+ | Prop | Type | Default | Description |
971
+ |------|------|---------|-------------|
972
+ | `variant` | `String` | `'info'` | Alert style (info, success, warning, error, default, destructive) |
973
+ | `title` | `String` | - | Alert title |
974
+ | `message` | `String` | - | Alert message |
975
+ | `dismissible` | `Boolean` | `false` | Show dismiss button |
976
+ | `dismissLabel` | `String` | `'Dismiss alert'` | Accessibility label for dismiss button |
977
+ | `showIcon` | `Boolean` | `true` | Show variant icon |
978
+ | `actions` | `Array` | `[]` | Array of action buttons |
979
+ | `autoClose` | `Boolean \| Number` | `false` | Auto-dismiss after delay (ms) or false |
980
+
981
+ ### Events
982
+
983
+ | Event | Payload | Description |
984
+ |-------|---------|-------------|
985
+ | `dismiss` | - | Emitted when alert is dismissed |
986
+ | `action` | `action` | Emitted when an action button is clicked |
987
+
988
+ ### Slots
989
+
990
+ | Slot | Description |
991
+ |------|-------------|
992
+ | `default` | Alert content (replaces message) |
993
+ | `actions` | Custom action buttons |
994
+
995
+ ### Example
996
+
997
+ ```vue
998
+ <template>
999
+ <div class="space-y-4">
1000
+ <Alert variant="success" title="Success!" message="Your changes have been saved." dismissible />
1001
+
1002
+ <Alert variant="warning" title="Warning" :autoClose="5000">
1003
+ This action cannot be undone.
1004
+ <template #actions>
1005
+ <Button variant="outline" size="sm" @click="confirmAction">Confirm</Button>
1006
+ </template>
1007
+ </Alert>
1008
+
1009
+ <Alert variant="error" title="Error" dismissible>
1010
+ <p>Something went wrong. Please try again.</p>
1011
+ </Alert>
1012
+ </div>
1013
+ </template>
1014
+
1015
+ <script setup>
1016
+ import Alert from '@/components/Alert.vue'
1017
+ import Button from '@/components/Button.vue'
1018
+
1019
+ const confirmAction = () => {
1020
+ console.log('Action confirmed')
1021
+ }
1022
+ </script>
1023
+ ```
1024
+
1025
+ ## Badge
1026
+
1027
+ A small label component for displaying status, tags, or counts.
1028
+
1029
+ ### Props
1030
+
1031
+ | Prop | Type | Default | Description |
1032
+ |------|------|---------|-------------|
1033
+ | `variant` | `String` | `'default'` | Visual style (default, secondary, destructive, outline) |
1034
+ | `size` | `String` | `'md'` | Size variant (sm, md, lg) |
1035
+ | `shape` | `String` | `'rounded'` | Shape variant (rounded, pill, square) |
1036
+ | `icon` | `String \| Object` | `null` | Icon component |
1037
+ | `dismissible` | `Boolean` | `false` | Show dismiss button |
1038
+ | `dismissLabel` | `String` | `'Dismiss'` | Accessibility label for dismiss button |
1039
+
1040
+ ### Events
1041
+
1042
+ | Event | Payload | Description |
1043
+ |-------|---------|-------------|
1044
+ | `dismiss` | - | Emitted when badge is dismissed |
1045
+
1046
+ ### Slots
1047
+
1048
+ | Slot | Description |
1049
+ |------|-------------|
1050
+ | `default` | Badge content |
1051
+
1052
+ ### Example
1053
+
1054
+ ```vue
1055
+ <template>
1056
+ <div class="space-x-2">
1057
+ <Badge variant="default">New</Badge>
1058
+ <Badge variant="secondary" size="sm">Beta</Badge>
1059
+ <Badge variant="destructive" shape="pill" icon="ExclamationIcon">
1060
+ Error
1061
+ </Badge>
1062
+ <Badge variant="outline" dismissible @dismiss="handleDismiss">
1063
+ Dismissible
1064
+ </Badge>
1065
+ </div>
1066
+ </template>
1067
+
1068
+ <script setup>
1069
+ import Badge from '@/components/Badge.vue'
1070
+
1071
+ const handleDismiss = () => {
1072
+ console.log('Badge dismissed')
1073
+ }
1074
+ </script>
1075
+ ```
1076
+
1077
+ ## Card
1078
+
1079
+ A container component for grouping related content with optional header, image, and footer.
1080
+
1081
+ ### Props
1082
+
1083
+ | Prop | Type | Default | Description |
1084
+ |------|------|---------|-------------|
1085
+ | `variant` | `String` | `'default'` | Visual style (default, outlined, elevated, filled) |
1086
+ | `padding` | `String` | `'md'` | Padding size (none, sm, md, lg, xl) |
1087
+ | `title` | `String` | - | Card title |
1088
+ | `subtitle` | `String` | - | Card subtitle |
1089
+ | `image` | `String` | - | Image source URL |
1090
+ | `imageAlt` | `String` | `'Card image'` | Image alt text |
1091
+ | `hoverable` | `Boolean` | `false` | Add hover effect |
1092
+ | `clickable` | `Boolean` | `false` | Make card clickable |
1093
+ | `loading` | `Boolean` | `false` | Loading state |
1094
+
1095
+ ### Events
1096
+
1097
+ | Event | Payload | Description |
1098
+ |-------|---------|-------------|
1099
+ | `click` | `Event` | Emitted when card is clicked (if clickable) |
1100
+
1101
+ ### Slots
1102
+
1103
+ | Slot | Description |
1104
+ |------|-------------|
1105
+ | `header` | Card header content |
1106
+ | `image` | Card image |
1107
+ | `default` | Card content |
1108
+ | `footer` | Card footer |
1109
+ | `actions` | Header actions |
1110
+
1111
+ ### Example
1112
+
1113
+ ```vue
1114
+ <template>
1115
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4">
1116
+ <Card
1117
+ title="Card Title"
1118
+ subtitle="Card subtitle"
1119
+ image="/path/to/image.jpg"
1120
+ hoverable
1121
+ clickable
1122
+ @click="handleCardClick"
1123
+ >
1124
+ <p>This is the card content.</p>
1125
+
1126
+ <template #footer>
1127
+ <Button variant="outline" size="sm">Learn More</Button>
1128
+ </template>
1129
+ </Card>
1130
+
1131
+ <Card variant="elevated" padding="lg">
1132
+ <template #header>
1133
+ <div class="flex justify-between items-center">
1134
+ <h3 class="text-lg font-semibold">Custom Header</h3>
1135
+ <div class="space-x-2">
1136
+ <Button variant="ghost" size="sm">Edit</Button>
1137
+ <Button variant="ghost" size="sm">Delete</Button>
1138
+ </div>
1139
+ </div>
1140
+ </template>
1141
+
1142
+ <p>Card with custom header and actions.</p>
1143
+ </Card>
1144
+ </div>
1145
+ </template>
1146
+
1147
+ <script setup>
1148
+ import Card from '@/components/Card.vue'
1149
+ import Button from '@/components/Button.vue'
1150
+
1151
+ const handleCardClick = () => {
1152
+ console.log('Card clicked')
1153
+ }
1154
+ </script>
1155
+ ```
1156
+
1157
+ ## CardBody
1158
+
1159
+ A container component for card content with configurable padding.
1160
+
1161
+ ### Props
1162
+
1163
+ | Prop | Type | Default | Description |
1164
+ |------|------|---------|-------------|
1165
+ | `variant` | `String` | `'default'` | Padding variant (default, compact, spacious) |
1166
+
1167
+ ### Slots
1168
+
1169
+ | Slot | Description |
1170
+ |------|-------------|
1171
+ | `default` | Card body content |
1172
+
1173
+ ### Example
1174
+
1175
+ ```vue
1176
+ <template>
1177
+ <Card>
1178
+ <CardHeader>
1179
+ <CardTitle>Card Title</CardTitle>
1180
+ </CardHeader>
1181
+ <CardBody>
1182
+ <p>This is the main content of the card.</p>
1183
+ </CardBody>
1184
+ <CardFooter>
1185
+ <Button>Action</Button>
1186
+ </CardFooter>
1187
+ </Card>
1188
+ </template>
1189
+
1190
+ <script setup>
1191
+ import Card from '@/components/Card.vue'
1192
+ import CardHeader from '@/components/CardHeader.vue'
1193
+ import CardTitle from '@/components/CardTitle.vue'
1194
+ import CardBody from '@/components/CardBody.vue'
1195
+ import CardFooter from '@/components/CardFooter.vue'
1196
+ import Button from '@/components/Button.vue'
1197
+ </script>
1198
+ ```
1199
+
1200
+ ## CardContent
1201
+
1202
+ A container component for card content with reduced top padding.
1203
+
1204
+ ### Slots
1205
+
1206
+ | Slot | Description |
1207
+ |------|-------------|
1208
+ | `default` | Card content |
1209
+
1210
+ ### Example
1211
+
1212
+ ```vue
1213
+ <template>
1214
+ <Card>
1215
+ <CardHeader>
1216
+ <CardTitle>Card Title</CardTitle>
1217
+ </CardHeader>
1218
+ <CardContent>
1219
+ <p>This content has reduced top padding.</p>
1220
+ </CardContent>
1221
+ </Card>
1222
+ </template>
1223
+
1224
+ <script setup>
1225
+ import Card from '@/components/Card.vue'
1226
+ import CardHeader from '@/components/CardHeader.vue'
1227
+ import CardTitle from '@/components/CardTitle.vue'
1228
+ import CardContent from '@/components/CardContent.vue'
1229
+ </script>
1230
+ ```
1231
+
1232
+ ## CardFooter
1233
+
1234
+ A container component for card footer content.
1235
+
1236
+ ### Slots
1237
+
1238
+ | Slot | Description |
1239
+ |------|-------------|
1240
+ | `default` | Card footer content |
1241
+
1242
+ ### Example
1243
+
1244
+ ```vue
1245
+ <template>
1246
+ <Card>
1247
+ <CardBody>
1248
+ <p>Card content</p>
1249
+ </CardBody>
1250
+ <CardFooter>
1251
+ <div class="flex justify-end space-x-2">
1252
+ <Button variant="outline">Cancel</Button>
1253
+ <Button>Save</Button>
1254
+ </div>
1255
+ </CardFooter>
1256
+ </Card>
1257
+ </template>
1258
+
1259
+ <script setup>
1260
+ import Card from '@/components/Card.vue'
1261
+ import CardBody from '@/components/CardBody.vue'
1262
+ import CardFooter from '@/components/CardFooter.vue'
1263
+ import Button from '@/components/Button.vue'
1264
+ </script>
1265
+ ```
1266
+
1267
+ ## CardHeader
1268
+
1269
+ A container component for card header content.
1270
+
1271
+ ### Slots
1272
+
1273
+ | Slot | Description |
1274
+ |------|-------------|
1275
+ | `default` | Card header content |
1276
+
1277
+ ### Example
1278
+
1279
+ ```vue
1280
+ <template>
1281
+ <Card>
1282
+ <CardHeader>
1283
+ <CardTitle>Card Title</CardTitle>
1284
+ <p class="text-sm text-muted-foreground">Card subtitle</p>
1285
+ </CardHeader>
1286
+ <CardBody>
1287
+ <p>Card content</p>
1288
+ </CardBody>
1289
+ </Card>
1290
+ </template>
1291
+
1292
+ <script setup>
1293
+ import Card from '@/components/Card.vue'
1294
+ import CardHeader from '@/components/CardHeader.vue'
1295
+ import CardTitle from '@/components/CardTitle.vue'
1296
+ import CardBody from '@/components/CardBody.vue'
1297
+ </script>
1298
+ ```
1299
+
1300
+ ## CardTitle
1301
+
1302
+ A styled title component for card headers.
1303
+
1304
+ ### Slots
1305
+
1306
+ | Slot | Description |
1307
+ |------|-------------|
1308
+ | `default` | Title content |
1309
+
1310
+ ### Example
1311
+
1312
+ ```vue
1313
+ <template>
1314
+ <Card>
1315
+ <CardHeader>
1316
+ <CardTitle>Important Announcement</CardTitle>
1317
+ </CardHeader>
1318
+ <CardBody>
1319
+ <p>This is an important message.</p>
1320
+ </CardBody>
1321
+ </Card>
1322
+ </template>
1323
+
1324
+ <script setup>
1325
+ import Card from '@/components/Card.vue'
1326
+ import CardHeader from '@/components/CardHeader.vue'
1327
+ import CardTitle from '@/components/CardTitle.vue'
1328
+ import CardBody from '@/components/CardBody.vue'
1329
+ </script>
1330
+ ```
1331
+
1332
+ ## Checkbox
1333
+
1334
+ A customizable checkbox component with label and description support.
1335
+
1336
+ ### Props
1337
+
1338
+ | Prop | Type | Default | Description |
1339
+ |------|------|---------|-------------|
1340
+ | `modelValue` | `Boolean \| Array` | `false` | Checkbox value or array of values |
1341
+ | `value` | `String \| Number \| Boolean` | `null` | Value when used in checkbox group |
1342
+ | `label` | `String` | `null` | Checkbox label |
1343
+ | `description` | `String` | `null` | Additional description text |
1344
+ | `disabled` | `Boolean` | `false` | Whether disabled |
1345
+ | `required` | `Boolean` | `false` | Whether required |
1346
+ | `indeterminate` | `Boolean` | `false` | Indeterminate state |
1347
+ | `size` | `String` | `'md'` | Size variant (sm, md, lg) |
1348
+ | `variant` | `String` | `'default'` | Visual variant (default, error) |
1349
+ | `id` | `String` | `null` | Custom ID |
1350
+ | `error` | `String` | `null` | Error message |
1351
+
1352
+ ### Events
1353
+
1354
+ | Event | Payload | Description |
1355
+ |-------|---------|-------------|
1356
+ | `update:modelValue` | `Boolean \| Array` | Emitted when value changes |
1357
+ | `change` | `Boolean` | Emitted on change |
1358
+
1359
+ ### Slots
1360
+
1361
+ | Slot | Description |
1362
+ |------|-------------|
1363
+ | `default` | Label content (replaces label prop) |
1364
+
1365
+ ### Example
1366
+
1367
+ ```vue
1368
+ <template>
1369
+ <div class="space-y-4">
1370
+ <!-- Single checkbox -->
1371
+ <Checkbox v-model="agree" label="I agree to the terms" required />
1372
+
1373
+ <!-- Checkbox with description -->
1374
+ <Checkbox
1375
+ v-model="newsletter"
1376
+ label="Subscribe to newsletter"
1377
+ description="Receive weekly updates about our products"
1378
+ />
1379
+
1380
+ <!-- Checkbox group -->
1381
+ <div>
1382
+ <h4 class="font-medium mb-2">Select your interests:</h4>
1383
+ <div class="space-y-2">
1384
+ <Checkbox
1385
+ v-model="interests"
1386
+ value="tech"
1387
+ label="Technology"
1388
+ />
1389
+ <Checkbox
1390
+ v-model="interests"
1391
+ value="design"
1392
+ label="Design"
1393
+ />
1394
+ <Checkbox
1395
+ v-model="interests"
1396
+ value="business"
1397
+ label="Business"
1398
+ />
1399
+ </div>
1400
+ </div>
1401
+
1402
+ <!-- Indeterminate checkbox -->
1403
+ <Checkbox
1404
+ v-model="selectAll"
1405
+ :indeterminate="partialSelection"
1406
+ label="Select all"
1407
+ @change="handleSelectAll"
1408
+ />
1409
+ </div>
1410
+ </template>
1411
+
1412
+ <script setup>
1413
+ import { ref, computed } from 'vue'
1414
+ import Checkbox from '@/components/Checkbox.vue'
1415
+
1416
+ const agree = ref(false)
1417
+ const newsletter = ref(true)
1418
+ const interests = ref(['tech'])
1419
+ const selectAll = ref(false)
1420
+
1421
+ const partialSelection = computed(() => {
1422
+ return interests.value.length > 0 && interests.value.length < 3
1423
+ })
1424
+
1425
+ const handleSelectAll = (checked) => {
1426
+ if (checked) {
1427
+ interests.value = ['tech', 'design', 'business']
1428
+ } else {
1429
+ interests.value = []
1430
+ }
1431
+ }
1432
+ </script>
1433
+ ```
1434
+
1435
+ ## DataTable
1436
+
1437
+ A comprehensive data table component with sorting, pagination, selection, and loading states.
1438
+
1439
+ ### Props
1440
+
1441
+ | Prop | Type | Default | Description |
1442
+ |------|------|---------|-------------|
1443
+ | `data` | `Array` | - | Array of data items |
1444
+ | `columns` | `Array` | - | Column configuration array |
1445
+ | `title` | `String` | - | Table title |
1446
+ | `description` | `String` | - | Table description |
1447
+ | `selectable` | `Boolean` | `false` | Enable row selection |
1448
+ | `selectedItems` | `Array` | `[]` | Currently selected items |
1449
+ | `sortBy` | `String` | - | Initial sort column |
1450
+ | `sortOrder` | `String` | `'asc'` | Initial sort order |
1451
+ | `pageSize` | `Number` | `10` | Items per page |
1452
+ | `showPagination` | `Boolean` | `true` | Show pagination |
1453
+ | `striped` | `Boolean` | `false` | Striped rows |
1454
+ | `hoverable` | `Boolean` | `true` | Hover effects |
1455
+ | `clickableRows` | `Boolean` | `false` | Make rows clickable |
1456
+ | `emptyText` | `String` | `'No data available'` | Empty state text |
1457
+ | `rowKey` | `String` | `'id'` | Unique key for rows |
1458
+ | `variant` | `String` | `'default'` | Table variant |
1459
+ | `density` | `String` | `'normal'` | Row density |
1460
+ | `loading` | `Boolean` | `false` | Loading state |
1461
+ | `dataLoading` | `Boolean` | `false` | Data loading state |
1462
+ | `sortLoading` | `Boolean` | `false` | Sort loading state |
1463
+ | `bulkLoading` | `Boolean` | `false` | Bulk operation loading |
1464
+ | `rowLoading` | `Object` | `{}` | Row-specific loading states |
1465
+
1466
+ ### Events
1467
+
1468
+ | Event | Payload | Description |
1469
+ |-------|---------|-------------|
1470
+ | `selection-change` | `selectedItems` | Selection changed |
1471
+ | `sort-change` | `{ column, direction }` | Sort changed |
1472
+ | `row-click` | `rowData` | Row clicked |
1473
+ | `page-change` | `page` | Page changed |
1474
+ | `page-size-change` | `size` | Page size changed |
1475
+
1476
+ ### Slots
1477
+
1478
+ | Slot | Description |
1479
+ |------|-------------|
1480
+ | `header` | Table header content |
1481
+ | `filters` | Filter controls |
1482
+ | `cell-{columnKey}` | Custom cell content |
1483
+ | `actions` | Row actions |
1484
+ | `empty` | Empty state content |
1485
+ | `footer` | Table footer |
1486
+
1487
+ ### Example
1488
+
1489
+ ```vue
1490
+ <template>
1491
+ <DataTable
1492
+ :data="users"
1493
+ :columns="columns"
1494
+ title="Users"
1495
+ selectable
1496
+ :selected-items="selectedUsers"
1497
+ @selection-change="selectedUsers = $event"
1498
+ @row-click="handleRowClick"
1499
+ >
1500
+ <template #actions="{ item }">
1501
+ <Button variant="ghost" size="sm" @click="editUser(item)">Edit</Button>
1502
+ <Button variant="ghost" size="sm" @click="deleteUser(item)">Delete</Button>
1503
+ </template>
1504
+ </DataTable>
1505
+ </template>
1506
+
1507
+ <script setup>
1508
+ import { ref } from 'vue'
1509
+ import DataTable from '@/components/DataTable.vue'
1510
+ import Button from '@/components/Button.vue'
1511
+
1512
+ const selectedUsers = ref([])
1513
+ const users = ref([
1514
+ { id: 1, name: 'John Doe', email: 'john@example.com', role: 'Admin' },
1515
+ { id: 2, name: 'Jane Smith', email: 'jane@example.com', role: 'User' }
1516
+ ])
1517
+
1518
+ const columns = [
1519
+ { key: 'name', label: 'Name', sortable: true },
1520
+ { key: 'email', label: 'Email', sortable: true },
1521
+ { key: 'role', label: 'Role' }
1522
+ ]
1523
+
1524
+ const handleRowClick = (row) => {
1525
+ console.log('Row clicked:', row)
1526
+ }
1527
+
1528
+ const editUser = (user) => {
1529
+ console.log('Edit user:', user)
1530
+ }
1531
+
1532
+ const deleteUser = (user) => {
1533
+ console.log('Delete user:', user)
1534
+ }
1535
+ </script>
1536
+ ```
1537
+
1538
+ ## Select
1539
+
1540
+ A styled select dropdown component.
1541
+
1542
+ ### Props
1543
+
1544
+ | Prop | Type | Default | Description |
1545
+ |------|------|---------|-------------|
1546
+ | `modelValue` | `String \| Number \| Boolean` | `''` | Selected value |
1547
+ | `id` | `String` | `null` | Custom ID |
1548
+ | `name` | `String` | `null` | Form name |
1549
+ | `disabled` | `Boolean` | `false` | Whether disabled |
1550
+ | `required` | `Boolean` | `false` | Whether required |
1551
+
1552
+ ### Events
1553
+
1554
+ | Event | Payload | Description |
1555
+ |-------|---------|-------------|
1556
+ | `update:modelValue` | `String \| Number \| Boolean` | Emitted when selection changes |
1557
+
1558
+ ### Slots
1559
+
1560
+ | Slot | Description |
1561
+ |------|-------------|
1562
+ | `default` | Option elements |
1563
+
1564
+ ### Example
1565
+
1566
+ ```vue
1567
+ <template>
1568
+ <Select v-model="selectedOption">
1569
+ <option value="" disabled>Select an option</option>
1570
+ <option value="option1">Option 1</option>
1571
+ <option value="option2">Option 2</option>
1572
+ <option value="option3">Option 3</option>
1573
+ </Select>
1574
+ </template>
1575
+
1576
+ <script setup>
1577
+ import { ref } from 'vue'
1578
+ import Select from '@/components/Select.vue'
1579
+
1580
+ const selectedOption = ref('')
1581
+ </script>
1582
+ ```
1583
+
1584
+ ## Textarea
1585
+
1586
+ A multi-line text input component with auto-resize and validation support.
1587
+
1588
+ ### Props
1589
+
1590
+ | Prop | Type | Default | Description |
1591
+ |------|------|---------|-------------|
1592
+ | `modelValue` | `String` | `''` | Textarea value |
1593
+ | `placeholder` | `String` | `''` | Placeholder text |
1594
+ | `disabled` | `Boolean` | `false` | Whether disabled |
1595
+ | `readonly` | `Boolean` | `false` | Whether readonly |
1596
+ | `required` | `Boolean` | `false` | Whether required |
1597
+ | `rows` | `Number` | `3` | Number of visible rows |
1598
+ | `maxlength` | `Number` | `null` | Maximum character count |
1599
+ | `resize` | `String` | `'vertical'` | Resize behavior (none, vertical, horizontal, both) |
1600
+ | `autoResize` | `Boolean` | `false` | Auto-resize to content height |
1601
+ | `size` | `String` | `'md'` | Size variant (sm, md, lg) |
1602
+ | `variant` | `String` | `'default'` | Visual variant (default, error, success) |
1603
+ | `error` | `String` | `null` | Error message |
1604
+ | `id` | `String` | `null` | Custom ID |
1605
+
1606
+ ### Events
1607
+
1608
+ | Event | Payload | Description |
1609
+ |-------|---------|-------------|
1610
+ | `update:modelValue` | `String` | Emitted when value changes |
1611
+ | `blur` | `Event` | Emitted on blur |
1612
+ | `focus` | `Event` | Emitted on focus |
1613
+ | `keydown` | `Event` | Emitted on keydown |
1614
+
1615
+ ### Exposed Methods
1616
+
1617
+ - `focus()`: Focus the textarea
1618
+ - `blur()`: Blur the textarea
1619
+ - `select()`: Select all text
1620
+
1621
+ ### Example
1622
+
1623
+ ```vue
1624
+ <template>
1625
+ <Textarea
1626
+ v-model="message"
1627
+ placeholder="Enter your message..."
1628
+ :rows="4"
1629
+ :autoResize="true"
1630
+ maxlength="500"
1631
+ required
1632
+ />
1633
+ </template>
1634
+
1635
+ <script setup>
1636
+ import { ref } from 'vue'
1637
+ import Textarea from '@/components/Textarea.vue'
1638
+
1639
+ const message = ref('')
1640
+ </script>
1641
+ ```
1642
+
1643
+ ## Modal
1644
+
1645
+ A modal dialog component with backdrop and keyboard support.
1646
+
1647
+ ### Props
1648
+
1649
+ | Prop | Type | Default | Description |
1650
+ |------|------|---------|-------------|
1651
+ | `modelValue` | `Boolean` | - | Modal visibility |
1652
+ | `showClose` | `Boolean` | `true` | Show close button |
1653
+ | `closeOnBackdrop` | `Boolean` | `true` | Close on backdrop click |
1654
+ | `size` | `String` | `'4xl'` | Modal size (sm, md, lg, xl, 2xl, 3xl, 4xl, 5xl, 6xl, 7xl, full) |
1655
+ | `resizable` | `Boolean` | `false` | Whether modal is resizable |
1656
+
1657
+ ### Events
1658
+
1659
+ | Event | Payload | Description |
1660
+ |-------|---------|-------------|
1661
+ | `update:modelValue` | `Boolean` | Modal visibility changes |
1662
+ | `close` | - | Emitted when modal closes |
1663
+
1664
+ ### Slots
1665
+
1666
+ | Slot | Description |
1667
+ |------|-------------|
1668
+ | `default` | Modal content |
1669
+
1670
+ ### Example
1671
+
1672
+ ```vue
1673
+ <template>
1674
+ <div>
1675
+ <Button @click="showModal = true">Open Modal</Button>
1676
+
1677
+ <Modal v-model="showModal" size="lg">
1678
+ <div class="p-6">
1679
+ <h2 class="text-lg font-semibold mb-4">Modal Title</h2>
1680
+ <p class="mb-4">Modal content goes here.</p>
1681
+ <div class="flex justify-end">
1682
+ <Button @click="showModal = false">Close</Button>
1683
+ </div>
1684
+ </div>
1685
+ </Modal>
1686
+ </div>
1687
+ </template>
1688
+
1689
+ <script setup>
1690
+ import { ref } from 'vue'
1691
+ import Modal from '@/components/Modal.vue'
1692
+ import Button from '@/components/Button.vue'
1693
+
1694
+ const showModal = ref(false)
1695
+ </script>
1696
+ ```
1697
+
1698
+ ## FormField
1699
+
1700
+ A form field wrapper component that provides labels, descriptions, and validation messages.
1701
+
1702
+ ### Props
1703
+
1704
+ | Prop | Type | Default | Description |
1705
+ |------|------|---------|-------------|
1706
+ | `label` | `String` | - | Field label |
1707
+ | `description` | `String` | - | Field description |
1708
+ | `error` | `String` | - | Error message |
1709
+ | `success` | `String` | - | Success message |
1710
+ | `helpText` | `String` | - | Help text |
1711
+ | `required` | `Boolean` | `false` | Whether field is required |
1712
+ | `type` | `String` | `'text'` | Field type (for password toggle) |
1713
+ | `modelValue` | `String \| Date` | - | Field value |
1714
+ | `size` | `String` | `'md'` | Size variant (sm, md, lg) |
1715
+ | `id` | `String` | - | Custom ID |
1716
+
1717
+ ### Events
1718
+
1719
+ | Event | Payload | Description |
1720
+ |-------|---------|-------------|
1721
+ | `update:modelValue` | `String \| Date` | Emitted when value changes |
1722
+
1723
+ ### Slots
1724
+
1725
+ | Slot | Description |
1726
+ |------|-------------|
1727
+ | `default` | Field input component |
1728
+
1729
+ ### Scoped Slot Props
1730
+
1731
+ The default slot receives:
1732
+
1733
+ - `fieldId`: Unique ID for the field
1734
+ - `hasError`: Boolean indicating if field has error
1735
+ - `ariaDescribedBy`: ARIA describedby attribute
1736
+ - `showPassword`: Boolean for password visibility (password fields only)
1737
+ - `togglePasswordVisibility`: Function to toggle password visibility
1738
+
1739
+ ### Example
1740
+
1741
+ ```vue
1742
+ <template>
1743
+ <FormField
1744
+ label="Email Address"
1745
+ description="We'll never share your email with anyone else."
1746
+ :error="emailError"
1747
+ required
1748
+ >
1749
+ <template #default="{ fieldId, hasError, ariaDescribedBy }">
1750
+ <Input
1751
+ :id="fieldId"
1752
+ v-model="email"
1753
+ type="email"
1754
+ placeholder="Enter your email"
1755
+ :class="hasError ? 'border-red-500' : ''"
1756
+ :aria-describedby="ariaDescribedBy"
1757
+ />
1758
+ </template>
1759
+ </FormField>
1760
+ </template>
1761
+
1762
+ <script setup>
1763
+ import { ref } from 'vue'
1764
+ import FormField from '@/components/FormField.vue'
1765
+ import Input from '@/components/Input.vue'
1766
+
1767
+ const email = ref('')
1768
+ const emailError = ref('')
1769
+ </script>
1770
+ ```
1771
+
1772
+ ## Label
1773
+
1774
+ A styled label component for form inputs.
1775
+
1776
+ ### Props
1777
+
1778
+ | Prop | Type | Default | Description |
1779
+ |------|------|---------|-------------|
1780
+ | `htmlFor` | `String` | - | ID of associated input |
1781
+ | `size` | `String` | `'md'` | Size variant (sm, md, lg) |
1782
+ | `required` | `Boolean` | `false` | Show required indicator |
1783
+ | `disabled` | `Boolean` | `false` | Whether associated input is disabled |
1784
+
1785
+ ### Slots
1786
+
1787
+ | Slot | Description |
1788
+ |------|-------------|
1789
+ | `default` | Label text |
1790
+
1791
+ ### Example
1792
+
1793
+ ```vue
1794
+ <template>
1795
+ <div>
1796
+ <Label htmlFor="username" required>Username</Label>
1797
+ <Input id="username" v-model="username" />
1798
+ </div>
1799
+ </template>
1800
+
1801
+ <script setup>
1802
+ import { ref } from 'vue'
1803
+ import Label from '@/components/Label.vue'
1804
+ import Input from '@/components/Input.vue'
1805
+
1806
+ const username = ref('')
1807
+ </script>
1808
+ ```
1809
+
1810
+ ## Radio
1811
+
1812
+ A radio button component for single selection in a group.
1813
+
1814
+ ### Props
1815
+
1816
+ | Prop | Type | Default | Description |
1817
+ |------|------|---------|-------------|
1818
+ | `modelValue` | `Any` | - | Selected value |
1819
+ | `value` | `Any` | - | Value of this radio button |
1820
+ | `label` | `String` | - | Radio button label |
1821
+ | `disabled` | `Boolean` | `false` | Whether disabled |
1822
+ | `size` | `String` | `'md'` | Size variant (sm, md, lg) |
1823
+
1824
+ ### Events
1825
+
1826
+ | Event | Payload | Description |
1827
+ |-------|---------|-------------|
1828
+ | `update:modelValue` | `Any` | Emitted when radio is selected |
1829
+
1830
+ ### Example
1831
+
1832
+ ```vue
1833
+ <template>
1834
+ <div class="space-y-2">
1835
+ <Radio v-model="selected" value="option1" label="Option 1" />
1836
+ <Radio v-model="selected" value="option2" label="Option 2" />
1837
+ <Radio v-model="selected" value="option3" label="Option 3" />
1838
+ </div>
1839
+ <p>Selected: {{ selected }}</p>
1840
+ </template>
1841
+
1842
+ <script setup>
1843
+ import { ref } from 'vue'
1844
+ import Radio from '@/components/Radio.vue'
1845
+
1846
+ const selected = ref('option1')
1847
+ </script>
1848
+ ```
1849
+
1850
+ ## Switch
1851
+
1852
+ A toggle switch component for boolean values.
1853
+
1854
+ ### Props
1855
+
1856
+ | Prop | Type | Default | Description |
1857
+ |------|------|---------|-------------|
1858
+ | `modelValue` | `Boolean` | - | Switch state |
1859
+ | `disabled` | `Boolean` | `false` | Whether disabled |
1860
+ | `size` | `String` | `'md'` | Size variant (sm, md, lg) |
1861
+
1862
+ ### Events
1863
+
1864
+ | Event | Payload | Description |
1865
+ |-------|---------|-------------|
1866
+ | `update:modelValue` | `Boolean` | Emitted when switch toggles |
1867
+
1868
+ ### Example
1869
+
1870
+ ```vue
1871
+ <template>
1872
+ <div class="flex items-center space-x-2">
1873
+ <Switch v-model="enabled" />
1874
+ <Label>Enable feature</Label>
1875
+ </div>
1876
+ <p>Feature is {{ enabled ? 'enabled' : 'disabled' }}</p>
1877
+ </template>
1878
+
1879
+ <script setup>
1880
+ import { ref } from 'vue'
1881
+ import Switch from '@/components/Switch.vue'
1882
+ import Label from '@/components/Label.vue'
1883
+
1884
+ const enabled = ref(false)
1885
+ </script>
1886
+ ```
1887
+
1888
+ ## Progress
1889
+
1890
+ A progress bar component for showing completion status.
1891
+
1892
+ ### Props
1893
+
1894
+ | Prop | Type | Default | Description |
1895
+ |------|------|---------|-------------|
1896
+ | `value` | `Number` | `0` | Current progress value |
1897
+ | `max` | `Number` | `100` | Maximum value |
1898
+ | `size` | `String` | `'default'` | Size variant (sm, default, md, lg) |
1899
+ | `variant` | `String` | `'default'` | Color variant (default, success, warning, destructive) |
1900
+
1901
+ ### Example
1902
+
1903
+ ```vue
1904
+ <template>
1905
+ <div class="space-y-4">
1906
+ <Progress :value="progress" />
1907
+ <Progress :value="75" variant="success" size="sm" />
1908
+ <Progress :value="50" variant="warning" />
1909
+ <Progress :value="25" variant="destructive" size="lg" />
1910
+ </div>
1911
+ </template>
1912
+
1913
+ <script setup>
1914
+ import { ref } from 'vue'
1915
+ import Progress from '@/components/Progress.vue'
1916
+
1917
+ const progress = ref(60)
1918
+ </script>
1919
+ ```
1920
+
1921
+ ## Spinner
1922
+
1923
+ A loading spinner component with various sizes and colors.
1924
+
1925
+ ### Props
1926
+
1927
+ | Prop | Type | Default | Description |
1928
+ |------|------|---------|-------------|
1929
+ | `size` | `String` | `'md'` | Size variant (xs, sm, md, lg, xl) |
1930
+ | `variant` | `String` | `'default'` | Color variant (default, primary, secondary) |
1931
+ | `label` | `String` | `'Loading...'` | Accessibility label |
1932
+
1933
+ ### Example
1934
+
1935
+ ```vue
1936
+ <template>
1937
+ <div class="space-y-4">
1938
+ <Spinner />
1939
+ <Spinner size="lg" variant="primary" />
1940
+ <Spinner size="sm" variant="secondary" label="Saving..." />
1941
+ </div>
1942
+ </template>
1943
+
1944
+ <script setup>
1945
+ import Spinner from '@/components/Spinner.vue'
1946
+ </script>
1947
+ ```
1948
+
1949
+ ## Icon
1950
+
1951
+ A FontAwesome icon component with size and color options.
1952
+
1953
+ ### Props
1954
+
1955
+ | Prop | Type | Default | Description |
1956
+ |------|------|---------|-------------|
1957
+ | `icon` | `String` | - | FontAwesome icon name |
1958
+ | `prefix` | `String` | `'fas'` | FontAwesome prefix (fas, far, fab, etc.) |
1959
+ | `size` | `String` | `'md'` | Size variant (xs, sm, md, lg, xl, xxl) |
1960
+ | `color` | `String` | - | Text color class |
1961
+ | `ariaLabel` | `String` | - | Accessibility label |
1962
+
1963
+ ### Example
1964
+
1965
+ ```vue
1966
+ <template>
1967
+ <div class="space-x-4">
1968
+ <Icon icon="user" />
1969
+ <Icon icon="heart" prefix="far" color="red-500" />
1970
+ <Icon icon="github" prefix="fab" size="lg" ariaLabel="GitHub" />
1971
+ </div>
1972
+ </template>
1973
+
1974
+ <script setup>
1975
+ import Icon from '@/components/Icon.vue'
1976
+ </script>
1977
+ ```
1978
+
1979
+ <!-- Additional components (DataTableCell, DataTableFilters, DataTableHeader, DataTablePagination, DataTableRow, DataTableToolBar, FileUpload, Footer, Header, InputGroup, Link, ListItem, Logo, MainNavigation, MenuItem, ModalBody, ModalFooter, ModalHeader, Notification, Option, ProgressBar, RiskModal, Search, Sidebar, Stepper, StepperItem, STLLoader, Tab, TabPanel, Text, Timeline, TimelineItem, Toast, Tooltip, Typography) follow the same pattern. For these components, refer to their source code for props, events, and slots. -->
1980
+
1981
+ ## Testing
1982
+
1983
+ This library includes comprehensive testing with both unit and integration tests to ensure reliability and maintainability.
1984
+
1985
+ ### Test Structure
1986
+
1987
+ ```
1988
+ src/__tests__/
1989
+ ├── *.spec.js # Unit tests for individual components
1990
+ └── integration/ # Integration tests for component combinations
1991
+ ├── FormIntegration.spec.js
1992
+ ├── ModalIntegration.spec.js
1993
+ ├── CardIntegration.spec.js
1994
+ └── NavigationIntegration.spec.js
1995
+ ```
1996
+
1997
+ ### Testing Types
1998
+
1999
+ #### Unit Tests
2000
+ - Individual component functionality
2001
+ - Props, events, and styling validation
2002
+ - Accessibility testing
2003
+ - Error handling
2004
+
2005
+ #### Integration Tests
2006
+ - **Form Integration**: Complete form workflows with Input, Button, Select, Checkbox
2007
+ - **Modal Integration**: Modal with form submission and alert interactions
2008
+ - **Card Integration**: Cards with headers, content, footers, and actions
2009
+ - **Navigation Integration**: Dropdown menus and breadcrumb navigation
2010
+
2011
+ ### CI/CD Pipeline
2012
+
2013
+ The project uses GitHub Actions for automated testing:
2014
+
2015
+ - **Triggers**: Push/PR to `main` and `develop` branches
2016
+ - **Node.js versions**: 18.x, 20.x, 22.x
2017
+ - **Checks**: Linting, unit tests, integration tests, build verification
2018
+ - **Coverage**: Uploaded to Codecov with 70% threshold requirements
2019
+ - **Release**: Automatic NPM publishing on main branch pushes
2020
+
2021
+ ### Coverage Requirements
2022
+
2023
+ - Branches: 70%
2024
+ - Functions: 70%
2025
+ - Lines: 70%
2026
+ - Statements: 70%
2027
+
2028
+ ### Running Tests Locally
2029
+
2030
+ ```bash
2031
+ # Run all tests
2032
+ npm run test:unit
2033
+
2034
+ # Run tests once (CI mode)
2035
+ npm run test:unit:run
2036
+
2037
+ # Run with coverage
2038
+ npm run test:coverage
2039
+
2040
+ # Run only integration tests
2041
+ npm run test:unit -- --testPathPattern=integration
2042
+
2043
+ # Run specific test file
2044
+ npm run test:unit -- Button.spec.js
2045
+ ```
2046
+
2047
+ ### Test Configuration
2048
+
2049
+ - **Framework**: Vitest with jsdom environment
2050
+ - **Coverage**: V8 provider with HTML, JSON, and text reporters
2051
+ - **Mocking**: FontAwesome icons and other external dependencies
2052
+ - **Assertions**: Built-in Vitest matchers
2053
+
2054
+ ### Writing Tests
2055
+
2056
+ When adding new components, follow these patterns:
2057
+
2058
+ 1. **Unit Tests**: Test component props, events, slots, and styling
2059
+ 2. **Integration Tests**: Test component combinations and workflows
2060
+ 3. **Accessibility**: Include ARIA attributes and keyboard navigation tests
2061
+ 4. **Edge Cases**: Test disabled states, loading states, and error conditions
2062
+
2063
+ Example test structure:
2064
+ ```javascript
2065
+ import { describe, it, expect } from 'vitest'
2066
+ import { mount } from '@vue/test-utils'
2067
+ import Component from '../components/Component.vue'
2068
+
2069
+ describe('Component', () => {
2070
+ it('renders with default props', () => {
2071
+ const wrapper = mount(Component)
2072
+ expect(wrapper.exists()).toBe(true)
2073
+ })
2074
+
2075
+ it('handles user interactions', async () => {
2076
+ const wrapper = mount(Component)
2077
+ await wrapper.find('button').trigger('click')
2078
+ expect(wrapper.emitted('click')).toHaveLength(1)
2079
+ })
2080
+ })
2081
+ ```