@velkymx/vibeui 0.8.0 → 0.8.2
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/CLAUDE.md +48 -0
- package/dist/vibeui.css +1 -1
- package/dist/vibeui.es.js +149 -148
- package/dist/vibeui.umd.js +1 -1
- package/docs/README.md +153 -0
- package/docs/components/advanced/popover.md +150 -0
- package/docs/components/advanced/scrollspy.md +64 -0
- package/docs/components/advanced/tooltip.md +111 -0
- package/docs/components/card/card.md +215 -0
- package/docs/components/core/alert.md +72 -0
- package/docs/components/core/badge.md +81 -0
- package/docs/components/core/button-group.md +105 -0
- package/docs/components/core/button.md +127 -0
- package/docs/components/core/close-button.md +82 -0
- package/docs/components/core/link.md +36 -0
- package/docs/components/core/placeholder.md +135 -0
- package/docs/components/core/spinner.md +109 -0
- package/docs/components/data/datatable.md +416 -0
- package/docs/components/interactive/accordion.md +92 -0
- package/docs/components/interactive/carousel.md +97 -0
- package/docs/components/interactive/collapse.md +105 -0
- package/docs/components/interactive/dropdown.md +93 -0
- package/docs/components/interactive/modal.md +148 -0
- package/docs/components/interactive/offcanvas.md +89 -0
- package/docs/components/interactive/toast.md +114 -0
- package/docs/components/layout/col.md +123 -0
- package/docs/components/layout/container.md +59 -0
- package/docs/components/layout/row.md +113 -0
- package/docs/components/list/list-group.md +221 -0
- package/docs/components/navigation/breadcrumb.md +116 -0
- package/docs/components/navigation/nav.md +88 -0
- package/docs/components/navigation/navbar.md +106 -0
- package/docs/components/navigation/pagination.md +146 -0
- package/docs/components/progress/progress.md +182 -0
- package/docs/composables/back-button.md +28 -0
- package/docs/composables/breakpoints.md +54 -0
- package/docs/composables/color-mode.md +141 -0
- package/docs/forms/README.md +88 -0
- package/docs/forms/form-checkbox.md +50 -0
- package/docs/forms/form-datepicker.md +50 -0
- package/docs/forms/form-group.md +80 -0
- package/docs/forms/form-input.md +55 -0
- package/docs/forms/form-radio.md +58 -0
- package/docs/forms/form-select.md +54 -0
- package/docs/forms/form-spinbutton.md +55 -0
- package/docs/forms/form-switch.md +47 -0
- package/docs/forms/form-textarea.md +51 -0
- package/docs/forms/form-wysiwyg.md +64 -0
- package/docs/forms/input-group.md +51 -0
- package/docs/forms/validation.md +599 -0
- package/llms.txt +422 -0
- package/package.json +5 -2
package/llms.txt
ADDED
|
@@ -0,0 +1,422 @@
|
|
|
1
|
+
# VibeUI
|
|
2
|
+
|
|
3
|
+
A Vue 3 component library that wraps Bootstrap 5.3. Every Bootstrap component is exposed as a typed Vue component with reactive props, v-model support, automatic Bootstrap JS lifecycle management, and zero manual DOM work required.
|
|
4
|
+
|
|
5
|
+
**Package:** `@velkymx/vibeui`
|
|
6
|
+
**Stack:** Vue 3 (Composition API) + Bootstrap 5.3 + TypeScript + Vite
|
|
7
|
+
**Current version:** 0.8.x
|
|
8
|
+
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
## Key Mental Model
|
|
12
|
+
|
|
13
|
+
VibeUI is a thin but complete abstraction layer over Bootstrap. It does three things:
|
|
14
|
+
|
|
15
|
+
1. **Wraps Bootstrap CSS** — components apply the correct Bootstrap classes based on Vue props.
|
|
16
|
+
2. **Abstracts Bootstrap JS** — interactive components (`Modal`, `Offcanvas`, `Toast`, `Tooltip`, `Popover`, `Accordion`, `Carousel`, `Collapse`, `Dropdown`) initialize, configure, and destroy their own Bootstrap JS instances via `onMounted`/`onBeforeUnmount`. You never touch `new bootstrap.Modal(el)`.
|
|
17
|
+
3. **Adds Vue reactivity** — props drive Bootstrap re-initialization, `v-model` syncs visibility state, and Bootstrap's native events are re-emitted as Vue events.
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Project Structure
|
|
22
|
+
|
|
23
|
+
```
|
|
24
|
+
vibeui/
|
|
25
|
+
├── src/
|
|
26
|
+
│ ├── index.ts # Package entry point — exports everything
|
|
27
|
+
│ ├── types.ts # All shared TypeScript types
|
|
28
|
+
│ ├── components/
|
|
29
|
+
│ │ ├── index.ts # Component registration + Vue plugin
|
|
30
|
+
│ │ ├── VibeAlert.vue
|
|
31
|
+
│ │ ├── VibeButton.vue # Renders as <button>, <a>, or <router-link>
|
|
32
|
+
│ │ ├── VibeBadge.vue
|
|
33
|
+
│ │ ├── VibeButtonGroup.vue
|
|
34
|
+
│ │ ├── VibeCard.vue
|
|
35
|
+
│ │ ├── VibeCloseButton.vue
|
|
36
|
+
│ │ ├── VibeSpinner.vue
|
|
37
|
+
│ │ ├── VibePlaceholder.vue
|
|
38
|
+
│ │ ├── VibeContainer.vue # Layout
|
|
39
|
+
│ │ ├── VibeRow.vue
|
|
40
|
+
│ │ ├── VibeCol.vue
|
|
41
|
+
│ │ ├── VibeBreadcrumb.vue # Data-driven: accepts items[]
|
|
42
|
+
│ │ ├── VibeNav.vue
|
|
43
|
+
│ │ ├── VibeNavbar.vue
|
|
44
|
+
│ │ ├── VibeNavbarBrand.vue
|
|
45
|
+
│ │ ├── VibeNavbarToggle.vue
|
|
46
|
+
│ │ ├── VibeNavbarNav.vue
|
|
47
|
+
│ │ ├── VibePagination.vue # v-model:currentPage
|
|
48
|
+
│ │ ├── VibeTabContent.vue
|
|
49
|
+
│ │ ├── VibeListGroup.vue # Data-driven: accepts items[]
|
|
50
|
+
│ │ ├── VibeProgress.vue # Data-driven: accepts bars[]
|
|
51
|
+
│ │ ├── VibeAccordion.vue # Bootstrap JS — auto init/destroy
|
|
52
|
+
│ │ ├── VibeCollapse.vue # Bootstrap JS — v-model
|
|
53
|
+
│ │ ├── VibeDropdown.vue # Bootstrap JS — data-driven items[]
|
|
54
|
+
│ │ ├── VibeModal.vue # Bootstrap JS — v-model, Teleport to body
|
|
55
|
+
│ │ ├── VibeOffcanvas.vue # Bootstrap JS — v-model, Teleport to body
|
|
56
|
+
│ │ ├── VibeToast.vue # Bootstrap JS — v-model, Teleport to body
|
|
57
|
+
│ │ ├── VibeCarousel.vue # Bootstrap JS — v-model:activeIndex
|
|
58
|
+
│ │ ├── VibeTooltip.vue # Bootstrap JS — reactive re-init on prop change
|
|
59
|
+
│ │ ├── VibePopover.vue # Bootstrap JS — reactive re-init on prop change
|
|
60
|
+
│ │ ├── VibeScrollspy.vue
|
|
61
|
+
│ │ ├── VibeIcon.vue # Renders Bootstrap Icons (bi-*)
|
|
62
|
+
│ │ ├── VibeDataTable.vue # Sortable, searchable, paginated table
|
|
63
|
+
│ │ ├── VibeFormInput.vue
|
|
64
|
+
│ │ ├── VibeFormSelect.vue
|
|
65
|
+
│ │ ├── VibeFormTextarea.vue
|
|
66
|
+
│ │ ├── VibeFormCheckbox.vue
|
|
67
|
+
│ │ ├── VibeFormRadio.vue
|
|
68
|
+
│ │ ├── VibeFormSwitch.vue
|
|
69
|
+
│ │ ├── VibeFormSpinbutton.vue
|
|
70
|
+
│ │ ├── VibeFormDatepicker.vue
|
|
71
|
+
│ │ ├── VibeFormGroup.vue # Context-aware — auto-links label to child input
|
|
72
|
+
│ │ └── VibeFormWysiwyg.vue # Powered by QuillJS (optional peer dep)
|
|
73
|
+
│ └── composables/
|
|
74
|
+
│ ├── useId.ts # Generates unique IDs (SSR-safe)
|
|
75
|
+
│ ├── useColorMode.ts # Bootstrap color mode management (singleton)
|
|
76
|
+
│ └── useFormValidation.ts # Field-level validation + built-in validators
|
|
77
|
+
├── tests/
|
|
78
|
+
│ ├── components/ # Component tests (Vitest + @vue/test-utils)
|
|
79
|
+
│ └── composables/ # Composable tests
|
|
80
|
+
├── docs/
|
|
81
|
+
│ ├── README.md # Docs index — start here
|
|
82
|
+
│ ├── components/ # Per-component reference docs
|
|
83
|
+
│ ├── forms/ # Form + validation docs
|
|
84
|
+
│ └── composables/
|
|
85
|
+
│ └── color-mode.md
|
|
86
|
+
├── examples/ # Standalone HTML files (CDN-based, no build needed)
|
|
87
|
+
│ ├── starter.html
|
|
88
|
+
│ ├── dashboard.html
|
|
89
|
+
│ ├── album.html
|
|
90
|
+
│ └── pricing.html
|
|
91
|
+
├── vite.config.ts # Also contains Vitest config
|
|
92
|
+
└── llms.txt # This file
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
---
|
|
96
|
+
|
|
97
|
+
## Installation & Setup
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
npm install @velkymx/vibeui bootstrap
|
|
101
|
+
```
|
|
102
|
+
|
|
103
|
+
```ts
|
|
104
|
+
// main.ts
|
|
105
|
+
import { createApp } from 'vue'
|
|
106
|
+
import VibeUI, { useColorMode } from '@velkymx/vibeui'
|
|
107
|
+
import 'bootstrap/dist/css/bootstrap.min.css'
|
|
108
|
+
import App from './App.vue'
|
|
109
|
+
|
|
110
|
+
// Restore saved light/dark/auto preference before first render
|
|
111
|
+
const { initColorMode } = useColorMode()
|
|
112
|
+
initColorMode()
|
|
113
|
+
|
|
114
|
+
createApp(App).use(VibeUI).mount('#app')
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Bootstrap CSS must be imported by the consumer. VibeUI does **not** bundle it.
|
|
118
|
+
Bootstrap JS is handled internally via dynamic import — do **not** import `bootstrap/dist/js/bootstrap.bundle.min.js` yourself.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
## Exports
|
|
123
|
+
|
|
124
|
+
Everything is exported from the package root:
|
|
125
|
+
|
|
126
|
+
```ts
|
|
127
|
+
import VibeUI from '@velkymx/vibeui' // Vue plugin (app.use)
|
|
128
|
+
import { VibeButton, VibeModal, ... } from '@velkymx/vibeui' // Individual components
|
|
129
|
+
import { useColorMode, useFormValidation, useId, validators } from '@velkymx/vibeui'
|
|
130
|
+
import type { Variant, ColorMode, Size, ... } from '@velkymx/vibeui'
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
---
|
|
134
|
+
|
|
135
|
+
## Shared Types (`src/types.ts`)
|
|
136
|
+
|
|
137
|
+
These types are used across all components. Always import from `@velkymx/vibeui`.
|
|
138
|
+
|
|
139
|
+
```ts
|
|
140
|
+
type Variant = 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'light' | 'dark'
|
|
141
|
+
type Size = 'sm' | 'lg'
|
|
142
|
+
type ColorMode = 'light' | 'dark' | 'auto'
|
|
143
|
+
type ButtonType = 'button' | 'submit' | 'reset'
|
|
144
|
+
type Tag = 'div' | 'span' | 'section' | 'article' | 'nav' | 'aside' | 'header' | 'footer' | 'main'
|
|
145
|
+
type Placement = 'top' | 'bottom' | 'start' | 'end'
|
|
146
|
+
type Direction = 'up' | 'down' | 'start' | 'end'
|
|
147
|
+
type SpinnerType = 'border' | 'grow'
|
|
148
|
+
type InputType = 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'search' | 'date' | 'time' | ...
|
|
149
|
+
type ValidationState = 'valid' | 'invalid' | null
|
|
150
|
+
|
|
151
|
+
// Data-driven component item shapes
|
|
152
|
+
interface BreadcrumbItem { text, href?, to?, active? }
|
|
153
|
+
interface NavItem { text, href?, to?, active?, disabled?, children? }
|
|
154
|
+
interface DropdownItem { text?, href?, to?, active?, disabled?, divider?, header? }
|
|
155
|
+
interface ListGroupItem { text, href?, to?, active?, disabled?, variant? }
|
|
156
|
+
interface AccordionItem { id, title, content, show? }
|
|
157
|
+
interface CarouselItem { src, alt?, caption?, captionText?, active?, interval? }
|
|
158
|
+
interface ProgressBar { value, max?, variant?, striped?, animated?, label?, showValue? }
|
|
159
|
+
interface DataTableColumn { key, label, sortable?, searchable?, formatter?, class?, ... }
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
---
|
|
163
|
+
|
|
164
|
+
## Layout Components
|
|
165
|
+
|
|
166
|
+
### VibeContainer
|
|
167
|
+
|
|
168
|
+
Wraps Bootstrap's `.container`, `.container-fluid`, and `.container-{breakpoint}`.
|
|
169
|
+
|
|
170
|
+
| Prop | Type | Default | Description |
|
|
171
|
+
|------|------|---------|-------------|
|
|
172
|
+
| `fluid` | `boolean \| ContainerType` | `false` | `false` = fixed, `true` = fluid, or breakpoint string |
|
|
173
|
+
| `tag` | `Tag` | `'div'` | HTML element |
|
|
174
|
+
|
|
175
|
+
```vue
|
|
176
|
+
<VibeContainer>Fixed width</VibeContainer>
|
|
177
|
+
<VibeContainer fluid>Full width</VibeContainer>
|
|
178
|
+
<VibeContainer fluid="md">Fluid until md breakpoint</VibeContainer>
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
### VibeRow
|
|
182
|
+
|
|
183
|
+
Bootstrap grid row with gutters, row-columns, and alignment.
|
|
184
|
+
|
|
185
|
+
| Prop | Type | Default | Description |
|
|
186
|
+
|------|------|---------|-------------|
|
|
187
|
+
| `tag` | `Tag` | `'div'` | HTML element |
|
|
188
|
+
| `gutters` | `GutterSize` | — | Both-axis gutter (`0`-`5`) |
|
|
189
|
+
| `guttersX` / `guttersY` | `GutterSize` | — | Per-axis gutter |
|
|
190
|
+
| `gutters{X\|Y}{Sm\|Md\|Lg\|Xl\|Xxl}` | `GutterSize` | — | Responsive gutters |
|
|
191
|
+
| `rowCols` | `RowColsSize` | — | Columns per row (`1`-`6`) |
|
|
192
|
+
| `rowCols{Sm\|Md\|Lg\|Xl\|Xxl}` | `RowColsSize` | — | Responsive row-cols |
|
|
193
|
+
| `alignItems` | `AlignItems` | — | Vertical alignment |
|
|
194
|
+
| `justifyContent` | `JustifyContent` | — | Horizontal distribution |
|
|
195
|
+
|
|
196
|
+
Types: `GutterSize = 0-5`, `RowColsSize = 1-6`, `AlignItems = 'start' | 'center' | 'end' | 'baseline' | 'stretch'`, `JustifyContent = 'start' | 'center' | 'end' | 'around' | 'between' | 'evenly'`
|
|
197
|
+
|
|
198
|
+
### VibeCol
|
|
199
|
+
|
|
200
|
+
Bootstrap grid column with responsive sizing, offsets, ordering, and alignment.
|
|
201
|
+
|
|
202
|
+
| Prop | Type | Default | Description |
|
|
203
|
+
|------|------|---------|-------------|
|
|
204
|
+
| `tag` | `Tag` | `'div'` | HTML element |
|
|
205
|
+
| `cols` | `ColSize \| boolean` | — | Base width (`1`-`12`, `'auto'`, or `true`) |
|
|
206
|
+
| `sm` / `md` / `lg` / `xl` / `xxl` | `ColSize \| boolean` | — | Responsive width |
|
|
207
|
+
| `offset` | `Number` | — | Base offset (`0`-`11`) |
|
|
208
|
+
| `offset{Sm\|Md\|Lg\|Xl\|Xxl}` | `Number` | — | Responsive offsets |
|
|
209
|
+
| `order` | `OrderValue` | — | Visual order |
|
|
210
|
+
| `order{Sm\|Md\|Lg\|Xl\|Xxl}` | `OrderValue` | — | Responsive order |
|
|
211
|
+
| `alignSelf` | `AlignItems` | — | Individual vertical alignment |
|
|
212
|
+
|
|
213
|
+
Types: `ColSize = 1-12 | 'auto'`, `OrderValue = 0-5 | 'first' | 'last'`
|
|
214
|
+
|
|
215
|
+
When no sizing props are provided, `VibeCol` defaults to equal-width (`col` class).
|
|
216
|
+
|
|
217
|
+
```vue
|
|
218
|
+
<VibeContainer>
|
|
219
|
+
<VibeRow :gutters="3">
|
|
220
|
+
<VibeCol :cols="12" :md="6" :lg="4">Responsive</VibeCol>
|
|
221
|
+
<VibeCol :cols="12" :md="6" :lg="4">Responsive</VibeCol>
|
|
222
|
+
<VibeCol :cols="12" :md="12" :lg="4">Responsive</VibeCol>
|
|
223
|
+
</VibeRow>
|
|
224
|
+
</VibeContainer>
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Core Patterns
|
|
230
|
+
|
|
231
|
+
### v-model for visibility
|
|
232
|
+
|
|
233
|
+
All interactive components (Modal, Offcanvas, Toast, Collapse, Alert) use `v-model` to control open/closed state:
|
|
234
|
+
|
|
235
|
+
```vue
|
|
236
|
+
<script setup>
|
|
237
|
+
const show = ref(false)
|
|
238
|
+
</script>
|
|
239
|
+
|
|
240
|
+
<template>
|
|
241
|
+
<VibeButton @click="show = true">Open</VibeButton>
|
|
242
|
+
<VibeModal v-model="show" title="Hello">Content</VibeModal>
|
|
243
|
+
</template>
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### Data-driven components
|
|
247
|
+
|
|
248
|
+
Components like `VibeBreadcrumb`, `VibeListGroup`, `VibeDropdown`, `VibeAccordion`, `VibeCarousel`, and `VibeProgress` accept an `items` or `bars` array prop rather than manual slot markup:
|
|
249
|
+
|
|
250
|
+
```vue
|
|
251
|
+
<VibeBreadcrumb :items="[
|
|
252
|
+
{ text: 'Home', href: '/' },
|
|
253
|
+
{ text: 'Products', href: '/products' },
|
|
254
|
+
{ text: 'Details', active: true }
|
|
255
|
+
]" />
|
|
256
|
+
```
|
|
257
|
+
|
|
258
|
+
### VibeFormGroup — automatic label linking
|
|
259
|
+
|
|
260
|
+
`VibeFormGroup` uses Vue's `provide`/`inject` to share a generated ID with child inputs. This means `id` and `label-for` are optional — the group handles accessibility automatically:
|
|
261
|
+
|
|
262
|
+
```vue
|
|
263
|
+
<VibeFormGroup label="Email Address">
|
|
264
|
+
<VibeFormInput v-model="email" type="email" />
|
|
265
|
+
<!-- label is automatically linked to input, no id needed -->
|
|
266
|
+
</VibeFormGroup>
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### Accessing the Bootstrap instance
|
|
270
|
+
|
|
271
|
+
Every interactive component exposes its Bootstrap instance via a template ref:
|
|
272
|
+
|
|
273
|
+
```vue
|
|
274
|
+
<template>
|
|
275
|
+
<VibeModal ref="modal" v-model="show" title="Advanced" />
|
|
276
|
+
</template>
|
|
277
|
+
|
|
278
|
+
<script setup>
|
|
279
|
+
const modal = useTemplateRef('modal')
|
|
280
|
+
// modal.value.bsInstance → native Bootstrap Modal instance
|
|
281
|
+
</script>
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
### Teleportation
|
|
285
|
+
|
|
286
|
+
`VibeModal`, `VibeOffcanvas`, and `VibeToast` render via `<Teleport to="body">` by default. This prevents CSS stacking context issues. No configuration needed.
|
|
287
|
+
|
|
288
|
+
---
|
|
289
|
+
|
|
290
|
+
## Composables
|
|
291
|
+
|
|
292
|
+
### useColorMode
|
|
293
|
+
|
|
294
|
+
Singleton. Sets `data-bs-theme` on `<html>`. Persists to `localStorage`.
|
|
295
|
+
|
|
296
|
+
```ts
|
|
297
|
+
const { colorMode, setColorMode, toggleColorMode, initColorMode } = useColorMode()
|
|
298
|
+
|
|
299
|
+
// colorMode: Ref<'light' | 'dark' | 'auto'>
|
|
300
|
+
// Call initColorMode() once in main.ts — subsequent calls are no-ops
|
|
301
|
+
// toggleColorMode() cycles light → dark → auto → light
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
Full docs: `docs/composables/color-mode.md`
|
|
305
|
+
|
|
306
|
+
### useFormValidation
|
|
307
|
+
|
|
308
|
+
Per-field validation with reactive state.
|
|
309
|
+
|
|
310
|
+
```ts
|
|
311
|
+
const email = useFormValidation('')
|
|
312
|
+
|
|
313
|
+
// email.value — Ref<string>
|
|
314
|
+
// email.validationState — Ref<'valid' | 'invalid' | null>
|
|
315
|
+
// email.validationMessage — Ref<string>
|
|
316
|
+
// email.isValid / email.isInvalid — computed booleans
|
|
317
|
+
// email.isDirty / email.isTouched / email.isValidating — Ref<boolean>
|
|
318
|
+
// await email.validate(rules)
|
|
319
|
+
// email.reset()
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### validators (built-in)
|
|
323
|
+
|
|
324
|
+
```ts
|
|
325
|
+
import { validators } from '@velkymx/vibeui'
|
|
326
|
+
|
|
327
|
+
validators.required(message?)
|
|
328
|
+
validators.email(message?)
|
|
329
|
+
validators.minLength(n, message?)
|
|
330
|
+
validators.maxLength(n, message?)
|
|
331
|
+
validators.min(n, message?)
|
|
332
|
+
validators.max(n, message?)
|
|
333
|
+
validators.pattern(regex, message?)
|
|
334
|
+
validators.url(message?)
|
|
335
|
+
validators.async(fn: (value) => Promise<boolean | string>)
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
Validators return `true` on pass, or a string error message on failure.
|
|
339
|
+
Full docs: `docs/forms/validation.md`
|
|
340
|
+
|
|
341
|
+
### useId
|
|
342
|
+
|
|
343
|
+
Generates a unique, SSR-safe ID string. Used internally by form components.
|
|
344
|
+
|
|
345
|
+
```ts
|
|
346
|
+
const id = useId('prefix') // → 'prefix-3-7'
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
---
|
|
350
|
+
|
|
351
|
+
## Testing
|
|
352
|
+
|
|
353
|
+
**Stack:** Vitest + @vue/test-utils + happy-dom
|
|
354
|
+
|
|
355
|
+
**Run tests:**
|
|
356
|
+
```bash
|
|
357
|
+
npx vitest run # single run
|
|
358
|
+
npx vitest # watch mode
|
|
359
|
+
npx vitest --coverage # coverage report
|
|
360
|
+
```
|
|
361
|
+
|
|
362
|
+
**Bootstrap JS is mocked** in tests. The mock lives at `tests/mocks/bootstrap.ts` and is aliased in `vite.config.ts`. Component tests never trigger real Bootstrap JS initialization.
|
|
363
|
+
|
|
364
|
+
**Pattern for component tests:**
|
|
365
|
+
```ts
|
|
366
|
+
import { describe, it, expect } from 'vitest'
|
|
367
|
+
import { mount } from '@vue/test-utils'
|
|
368
|
+
import VibeButton from '../../src/components/VibeButton.vue'
|
|
369
|
+
|
|
370
|
+
it('applies variant class', () => {
|
|
371
|
+
const wrapper = mount(VibeButton, { props: { variant: 'danger' } })
|
|
372
|
+
expect(wrapper.classes()).toContain('btn-danger')
|
|
373
|
+
})
|
|
374
|
+
```
|
|
375
|
+
|
|
376
|
+
**Pattern for composable tests:**
|
|
377
|
+
- Use `_resetColorMode()` (exported from `useColorMode.ts`, not from the package index) to reset singleton state between tests.
|
|
378
|
+
- Use `vi.stubGlobal` + `try/finally` for environment mocking (e.g. SSR simulation).
|
|
379
|
+
|
|
380
|
+
---
|
|
381
|
+
|
|
382
|
+
## Build
|
|
383
|
+
|
|
384
|
+
```bash
|
|
385
|
+
npm run build # outputs to dist/ as ESM + UMD + type declarations
|
|
386
|
+
npm run dev # Vite dev server for the src/App.vue playground
|
|
387
|
+
```
|
|
388
|
+
|
|
389
|
+
Build output:
|
|
390
|
+
- `dist/vibeui.es.js` — ESM for bundlers
|
|
391
|
+
- `dist/vibeui.umd.js` — UMD for CDN / script tag usage
|
|
392
|
+
- `dist/vibeui.d.ts` — TypeScript declarations
|
|
393
|
+
|
|
394
|
+
Vue and Bootstrap are **external** — not bundled. Consumers provide their own.
|
|
395
|
+
|
|
396
|
+
---
|
|
397
|
+
|
|
398
|
+
## Adding a New Component
|
|
399
|
+
|
|
400
|
+
1. Create `src/components/VibeFoo.vue`
|
|
401
|
+
2. Follow the pattern: `defineProps` with typed props, `computed` for class assembly, `<component :is="tag">` if the element type is configurable
|
|
402
|
+
3. Export from `src/components/index.ts` (named export + `app.component(...)` registration)
|
|
403
|
+
4. Export from `src/index.ts` (re-export via `export * from './components'` covers it automatically)
|
|
404
|
+
5. Add types to `src/types.ts` if new shared types are needed
|
|
405
|
+
6. Add tests in `tests/components/VibeFoo.test.ts`
|
|
406
|
+
7. Add docs in `docs/components/{category}/foo.md`
|
|
407
|
+
|
|
408
|
+
If the component uses Bootstrap JS:
|
|
409
|
+
- Dynamically import: `const { Foo } = await import('bootstrap')`
|
|
410
|
+
- Initialize in `onMounted`, dispose in `onBeforeUnmount`
|
|
411
|
+
- Watch functional props and call `instance.dispose()` + reinitialize on change
|
|
412
|
+
- Expose `bsInstance` via `defineExpose`
|
|
413
|
+
|
|
414
|
+
---
|
|
415
|
+
|
|
416
|
+
## What VibeUI Does NOT Do
|
|
417
|
+
|
|
418
|
+
- Does not bundle Bootstrap CSS or JS
|
|
419
|
+
- Does not require Bootstrap Icons (optional peer dep for `VibeIcon`)
|
|
420
|
+
- Does not require Vue Router (optional peer dep for `href`/`to` props on `VibeButton`)
|
|
421
|
+
- Does not require QuillJS (optional peer dep for `VibeFormWysiwyg`)
|
|
422
|
+
- Does not provide a theme system beyond Bootstrap's `data-bs-theme` color modes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@velkymx/vibeui",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.2",
|
|
4
4
|
"description": "A lightweight Vue 3 component library for Bootstrap 5.3 with dual-mode support (shorthand props and composable slots)",
|
|
5
5
|
"main": "./dist/vibeui.umd.js",
|
|
6
6
|
"module": "./dist/vibeui.es.js",
|
|
@@ -14,7 +14,10 @@
|
|
|
14
14
|
"./dist/style.css": "./dist/vibeui.css"
|
|
15
15
|
},
|
|
16
16
|
"files": [
|
|
17
|
-
"dist"
|
|
17
|
+
"dist",
|
|
18
|
+
"llms.txt",
|
|
19
|
+
"CLAUDE.md",
|
|
20
|
+
"docs"
|
|
18
21
|
],
|
|
19
22
|
"scripts": {
|
|
20
23
|
"dev": "vite",
|