@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.
Files changed (52) hide show
  1. package/CLAUDE.md +48 -0
  2. package/dist/vibeui.css +1 -1
  3. package/dist/vibeui.es.js +149 -148
  4. package/dist/vibeui.umd.js +1 -1
  5. package/docs/README.md +153 -0
  6. package/docs/components/advanced/popover.md +150 -0
  7. package/docs/components/advanced/scrollspy.md +64 -0
  8. package/docs/components/advanced/tooltip.md +111 -0
  9. package/docs/components/card/card.md +215 -0
  10. package/docs/components/core/alert.md +72 -0
  11. package/docs/components/core/badge.md +81 -0
  12. package/docs/components/core/button-group.md +105 -0
  13. package/docs/components/core/button.md +127 -0
  14. package/docs/components/core/close-button.md +82 -0
  15. package/docs/components/core/link.md +36 -0
  16. package/docs/components/core/placeholder.md +135 -0
  17. package/docs/components/core/spinner.md +109 -0
  18. package/docs/components/data/datatable.md +416 -0
  19. package/docs/components/interactive/accordion.md +92 -0
  20. package/docs/components/interactive/carousel.md +97 -0
  21. package/docs/components/interactive/collapse.md +105 -0
  22. package/docs/components/interactive/dropdown.md +93 -0
  23. package/docs/components/interactive/modal.md +148 -0
  24. package/docs/components/interactive/offcanvas.md +89 -0
  25. package/docs/components/interactive/toast.md +114 -0
  26. package/docs/components/layout/col.md +123 -0
  27. package/docs/components/layout/container.md +59 -0
  28. package/docs/components/layout/row.md +113 -0
  29. package/docs/components/list/list-group.md +221 -0
  30. package/docs/components/navigation/breadcrumb.md +116 -0
  31. package/docs/components/navigation/nav.md +88 -0
  32. package/docs/components/navigation/navbar.md +106 -0
  33. package/docs/components/navigation/pagination.md +146 -0
  34. package/docs/components/progress/progress.md +182 -0
  35. package/docs/composables/back-button.md +28 -0
  36. package/docs/composables/breakpoints.md +54 -0
  37. package/docs/composables/color-mode.md +141 -0
  38. package/docs/forms/README.md +88 -0
  39. package/docs/forms/form-checkbox.md +50 -0
  40. package/docs/forms/form-datepicker.md +50 -0
  41. package/docs/forms/form-group.md +80 -0
  42. package/docs/forms/form-input.md +55 -0
  43. package/docs/forms/form-radio.md +58 -0
  44. package/docs/forms/form-select.md +54 -0
  45. package/docs/forms/form-spinbutton.md +55 -0
  46. package/docs/forms/form-switch.md +47 -0
  47. package/docs/forms/form-textarea.md +51 -0
  48. package/docs/forms/form-wysiwyg.md +64 -0
  49. package/docs/forms/input-group.md +51 -0
  50. package/docs/forms/validation.md +599 -0
  51. package/llms.txt +422 -0
  52. 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.0",
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",