@stlhorizon/vue-ui 2.5.4 → 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.
- package/README.md +1971 -552
- package/dist/index.esm.js +1839 -1854
- package/dist/index.js +15 -15
- package/dist/src/__tests__/Alert.spec.d.ts +2 -0
- package/dist/src/__tests__/Alert.spec.d.ts.map +1 -0
- package/dist/src/__tests__/Badge.spec.d.ts +2 -0
- package/dist/src/__tests__/Badge.spec.d.ts.map +1 -0
- package/dist/src/__tests__/Button.spec.d.ts +2 -0
- package/dist/src/__tests__/Button.spec.d.ts.map +1 -0
- package/dist/src/__tests__/Card.spec.d.ts +2 -0
- package/dist/src/__tests__/Card.spec.d.ts.map +1 -0
- package/dist/src/__tests__/Checkbox.spec.d.ts +2 -0
- package/dist/src/__tests__/Checkbox.spec.d.ts.map +1 -0
- package/dist/src/__tests__/Dropdown.spec.d.ts +2 -0
- package/dist/src/__tests__/Dropdown.spec.d.ts.map +1 -0
- package/dist/src/__tests__/Input.spec.d.ts +2 -0
- package/dist/src/__tests__/Input.spec.d.ts.map +1 -0
- package/dist/src/__tests__/Modal.spec.d.ts +2 -0
- package/dist/src/__tests__/Modal.spec.d.ts.map +1 -0
- package/dist/src/__tests__/Radio.spec.d.ts +2 -0
- package/dist/src/__tests__/Radio.spec.d.ts.map +1 -0
- package/dist/src/__tests__/Select.spec.d.ts +2 -0
- package/dist/src/__tests__/Select.spec.d.ts.map +1 -0
- package/dist/src/__tests__/Tabs.spec.d.ts +2 -0
- package/dist/src/__tests__/Tabs.spec.d.ts.map +1 -0
- package/dist/src/__tests__/integration/CardIntegration.spec.d.ts +2 -0
- package/dist/src/__tests__/integration/CardIntegration.spec.d.ts.map +1 -0
- package/dist/src/__tests__/integration/FormIntegration.spec.d.ts +2 -0
- package/dist/src/__tests__/integration/FormIntegration.spec.d.ts.map +1 -0
- package/dist/src/__tests__/integration/ModalIntegration.spec.d.ts +2 -0
- package/dist/src/__tests__/integration/ModalIntegration.spec.d.ts.map +1 -0
- package/dist/src/__tests__/integration/NavigationIntegration.spec.d.ts +2 -0
- package/dist/src/__tests__/integration/NavigationIntegration.spec.d.ts.map +1 -0
- package/dist/src/components/Accordion.vue.d.ts.map +1 -1
- package/dist/src/components/AccordionItem.vue.d.ts.map +1 -1
- package/dist/src/components/Alert.vue.d.ts.map +1 -1
- package/dist/src/components/Avatar.vue.d.ts.map +1 -1
- package/dist/src/components/Badge.vue.d.ts.map +1 -1
- package/dist/src/components/Breadcrumb.vue.d.ts.map +1 -1
- package/dist/src/components/Button.vue.d.ts +2 -2
- package/dist/src/components/Button.vue.d.ts.map +1 -1
- package/dist/src/components/ButtonGroup.vue.d.ts.map +1 -1
- package/dist/src/components/Calendar.vue.d.ts.map +1 -1
- package/dist/src/components/Card.vue.d.ts.map +1 -1
- package/dist/src/components/Checkbox.vue.d.ts.map +1 -1
- package/dist/src/components/DataTable.vue.d.ts +1 -1
- package/dist/src/components/DataTable.vue.d.ts.map +1 -1
- package/dist/src/components/DataTableFilters.vue.d.ts.map +1 -1
- package/dist/src/components/DataTableHeader.vue.d.ts.map +1 -1
- package/dist/src/components/DataTablePagination.vue.d.ts +2 -2
- package/dist/src/components/DataTablePagination.vue.d.ts.map +1 -1
- package/dist/src/components/DataTableRow.vue.d.ts.map +1 -1
- package/dist/src/components/DataTableToolBar.vue.d.ts.map +1 -1
- package/dist/src/components/DatePicker.vue.d.ts.map +1 -1
- package/dist/src/components/Dropdown.vue.d.ts.map +1 -1
- package/dist/src/components/DropdownItem.vue.d.ts.map +1 -1
- package/dist/src/components/FileUpload.vue.d.ts.map +1 -1
- package/dist/src/components/Footer.vue.d.ts.map +1 -1
- package/dist/src/components/FormField.vue.d.ts.map +1 -1
- package/dist/src/components/Header.vue.d.ts.map +1 -1
- package/dist/src/components/Image.vue.d.ts.map +1 -1
- package/dist/src/components/Input.vue.d.ts.map +1 -1
- package/dist/src/components/InputGroup.vue.d.ts.map +1 -1
- package/dist/src/components/Label.vue.d.ts.map +1 -1
- package/dist/src/components/Link.vue.d.ts.map +1 -1
- package/dist/src/components/ListItem.vue.d.ts.map +1 -1
- package/dist/src/components/Logo.vue.d.ts.map +1 -1
- package/dist/src/components/MenuItem.vue.d.ts.map +1 -1
- package/dist/src/components/Modal.vue.d.ts.map +1 -1
- package/dist/src/components/ModalHeader.vue.d.ts.map +1 -1
- package/dist/src/components/Notification.vue.d.ts.map +1 -1
- package/dist/src/components/Option.vue.d.ts +2 -2
- package/dist/src/components/Option.vue.d.ts.map +1 -1
- package/dist/src/components/ProgressBar.vue.d.ts.map +1 -1
- package/dist/src/components/Radio.vue.d.ts +2 -2
- package/dist/src/components/Radio.vue.d.ts.map +1 -1
- package/dist/src/components/ReusableFormModal.vue.d.ts.map +1 -1
- package/dist/src/components/STLLoader.vue.d.ts +2 -2
- package/dist/src/components/STLLoader.vue.d.ts.map +1 -1
- package/dist/src/components/Search.vue.d.ts.map +1 -1
- package/dist/src/components/Sidebar.vue.d.ts.map +1 -1
- package/dist/src/components/Slider.vue.d.ts +2 -2
- package/dist/src/components/Slider.vue.d.ts.map +1 -1
- package/dist/src/components/Spinner.vue.d.ts.map +1 -1
- package/dist/src/components/StepperItem.vue.d.ts +2 -2
- package/dist/src/components/StepperItem.vue.d.ts.map +1 -1
- package/dist/src/components/Tab.vue.d.ts.map +1 -1
- package/dist/src/components/TabPanel.vue.d.ts.map +1 -1
- package/dist/src/components/Text.vue.d.ts.map +1 -1
- package/dist/src/components/Timeline.vue.d.ts +2 -2
- package/dist/src/components/Timeline.vue.d.ts.map +1 -1
- package/dist/src/components/TimelineItem.vue.d.ts +2 -2
- package/dist/src/components/TimelineItem.vue.d.ts.map +1 -1
- package/dist/src/components/Toast.vue.d.ts.map +1 -1
- package/dist/src/components/Tooltip.vue.d.ts.map +1 -1
- package/dist/src/layouts/DefaultLayout.vue.d.ts.map +1 -1
- package/dist/src/layouts/ErrorLayout.vue.d.ts +2 -2
- package/dist/src/views/AnalyticsPage.vue.d.ts +0 -6
- package/dist/src/views/authentication/ForgotPasswordPage.vue.d.ts.map +1 -1
- package/dist/src/views/authentication/LoginPage.vue.d.ts.map +1 -1
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/dist/vue-ui.css +1 -1
- package/package.json +5 -2
- package/dist/src/components/RiskModal.vue.d.ts +0 -13
- package/dist/src/components/RiskModal.vue.d.ts.map +0 -1
package/README.md
CHANGED
@@ -1,662 +1,2081 @@
|
|
1
|
-
# Vue UI
|
1
|
+
# STL Horizon Vue Atomic UI Library
|
2
2
|
|
3
|
-
A comprehensive Vue.js component library
|
3
|
+
A comprehensive Vue.js component library with Tailwind CSS styling, featuring automated testing, semantic versioning, and CI/CD pipelines.
|
4
4
|
|
5
|
-
|
6
|
-
|
5
|
+
## Development & Release Workflow
|
6
|
+
|
7
|
+
### Development
|
7
8
|
|
8
9
|
```bash
|
9
|
-
|
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
|
-
|
29
|
+
### Commit Convention
|
13
30
|
|
14
|
-
|
31
|
+
This project uses [Conventional Commits](https://conventionalcommits.org/) for automatic semantic versioning:
|
15
32
|
|
16
33
|
```bash
|
17
|
-
|
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
|
-
|
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
|
-
```
|
23
|
-
|
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
|
-
|
83
|
+
### Testing Types
|
27
84
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
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
|
-
|
133
|
+
### Test Configuration
|
40
134
|
|
41
|
-
|
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
|
-
###
|
140
|
+
### Writing Tests
|
44
141
|
|
45
|
-
|
142
|
+
When adding new components, follow these patterns:
|
46
143
|
|
47
|
-
|
48
|
-
|
49
|
-
|
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
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
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
|
-
|
276
|
+
## AccordionItem
|
76
277
|
|
77
|
-
|
278
|
+
A single expandable item for use within an accordion structure.
|
78
279
|
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
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
|
-
##
|
313
|
+
## Avatar
|
88
314
|
|
89
|
-
|
315
|
+
A component for displaying user avatars with image, initials, or icon fallback.
|
90
316
|
|
91
|
-
###
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
343
|
+
## Breadcrumb
|
119
344
|
|
120
|
-
|
121
|
-
app.use(router)
|
345
|
+
A navigation component showing the current page's location in a hierarchy.
|
122
346
|
|
123
|
-
|
124
|
-
app.use(VueApexCharts);
|
125
|
-
app.use(VueUI) // register the UI
|
347
|
+
### Props
|
126
348
|
|
127
|
-
|
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
|
-
|
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
|
-
<
|
136
|
-
<Button
|
137
|
-
<
|
138
|
-
<
|
139
|
-
</
|
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
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
-
|
183
|
-
-
|
184
|
-
-
|
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
|
-
|
270
|
-
|
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
|
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
|
-
|
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
|
-
<
|
285
|
-
<
|
286
|
-
|
287
|
-
</
|
288
|
-
|
289
|
-
<
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
|
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
|
-
|
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
|
-
##
|
537
|
+
## DropdownItem
|
308
538
|
|
309
|
-
|
539
|
+
An individual item within a dropdown menu.
|
310
540
|
|
311
|
-
|
541
|
+
### Props
|
312
542
|
|
313
|
-
|
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
|
-
|
551
|
+
### Events
|
316
552
|
|
317
|
-
|
553
|
+
| Event | Payload | Description |
|
554
|
+
|-------|---------|-------------|
|
555
|
+
| `click` | `Event` | Emitted when item is clicked |
|
318
556
|
|
319
|
-
|
557
|
+
### Slots
|
320
558
|
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
- Set the correct version number
|
559
|
+
| Slot | Description |
|
560
|
+
|------|-------------|
|
561
|
+
| `default` | Item content |
|
325
562
|
|
326
|
-
|
327
|
-
```bash
|
328
|
-
npm run build
|
329
|
-
```
|
563
|
+
### Example
|
330
564
|
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
565
|
+
```vue
|
566
|
+
<template>
|
567
|
+
<DropdownItem icon="user" shortcut="⌘U" @click="profile">
|
568
|
+
Profile
|
569
|
+
</DropdownItem>
|
570
|
+
</template>
|
335
571
|
|
336
|
-
|
337
|
-
|
338
|
-
npm publish --access public
|
339
|
-
```
|
572
|
+
<script setup>
|
573
|
+
import DropdownItem from '@/components/DropdownItem.vue'
|
340
574
|
|
341
|
-
|
575
|
+
const profile = () => console.log('Open profile')
|
576
|
+
</script>
|
577
|
+
```
|
342
578
|
|
343
|
-
|
344
|
-
# Install dependencies
|
345
|
-
npm install
|
579
|
+
## Image
|
346
580
|
|
347
|
-
|
348
|
-
npm run dev
|
581
|
+
An enhanced image component with loading states, aspect ratios, and error handling.
|
349
582
|
|
350
|
-
|
351
|
-
npm run build
|
583
|
+
### Props
|
352
584
|
|
353
|
-
|
354
|
-
|
355
|
-
|
356
|
-
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
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
|
-
|
512
|
-
|
513
|
-
|
514
|
-
|
515
|
-
|
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
|
522
|
-
|
621
|
+
import Image from '@/components/Image.vue'
|
622
|
+
</script>
|
623
|
+
```
|
523
624
|
|
524
|
-
|
525
|
-
const showBasicToast = () => {
|
526
|
-
toast("Hello World!")
|
527
|
-
}
|
625
|
+
## Slider
|
528
626
|
|
529
|
-
|
530
|
-
toast.success("Operation completed successfully!")
|
531
|
-
}
|
627
|
+
A customizable range slider component for selecting numeric values.
|
532
628
|
|
533
|
-
|
534
|
-
toast.error("Something went wrong!")
|
535
|
-
}
|
629
|
+
### Props
|
536
630
|
|
537
|
-
|
538
|
-
|
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
|
-
|
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
|
-
|
551
|
-
|
552
|
-
|
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
|
-
|
560
|
-
const simulateSuccess = () => {
|
561
|
-
const promise = new Promise((resolve) => {
|
562
|
-
setTimeout(() => resolve({ name: "John Doe" }), 2000)
|
563
|
-
})
|
644
|
+
### Example
|
564
645
|
|
565
|
-
|
566
|
-
|
567
|
-
|
568
|
-
|
569
|
-
})
|
570
|
-
}
|
646
|
+
```vue
|
647
|
+
<template>
|
648
|
+
<Slider v-model="volume" :min="0" :max="100" :step="5" />
|
649
|
+
</template>
|
571
650
|
|
572
|
-
|
573
|
-
|
574
|
-
|
575
|
-
})
|
651
|
+
<script setup>
|
652
|
+
import { ref } from 'vue'
|
653
|
+
import Slider from '@/components/Slider.vue'
|
576
654
|
|
577
|
-
|
578
|
-
|
579
|
-
|
580
|
-
error: (err) => `Connection failed: ${err.message}`
|
581
|
-
})
|
582
|
-
}
|
655
|
+
const volume = ref(50)
|
656
|
+
</script>
|
657
|
+
```
|
583
658
|
|
584
|
-
|
585
|
-
const promise = new Promise((resolve) => {
|
586
|
-
setTimeout(() => resolve(), 3000)
|
587
|
-
})
|
659
|
+
## Input
|
588
660
|
|
589
|
-
|
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
|
-
|
597
|
-
const showPersistent = () => {
|
598
|
-
toast.info("This stays until dismissed", {
|
599
|
-
duration: 0,
|
600
|
-
title: "Persistent Notification"
|
601
|
-
})
|
602
|
-
}
|
663
|
+
### Props
|
603
664
|
|
604
|
-
|
605
|
-
|
606
|
-
|
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
|
-
|
611
|
-
|
612
|
-
|
613
|
-
|
614
|
-
|
615
|
-
|
616
|
-
|
617
|
-
|
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
|
-
|
621
|
-
|
622
|
-
|
623
|
-
|
624
|
-
|
625
|
-
|
626
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
651
|
-
|
652
|
-
|
653
|
-
|
654
|
-
|
655
|
-
|
656
|
-
|
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
|
+
```
|