@velkymx/vibeui 0.8.2 → 1.0.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/AGENTS.md +44 -0
- package/README.md +245 -58
- package/dist/purify.es-1D-VntFD.mjs +679 -0
- package/dist/src/App.vue.d.ts +3 -0
- package/dist/src/components/HelloWorld.vue.d.ts +6 -0
- package/dist/src/components/VibeAccordion.vue.d.ts +89 -0
- package/dist/{components → src/components}/VibeAlert.vue.d.ts +24 -30
- package/dist/src/components/VibeAutocomplete.vue.d.ts +74 -0
- package/dist/{components → src/components}/VibeBadge.vue.d.ts +10 -18
- package/dist/src/components/VibeBreadcrumb.vue.d.ts +51 -0
- package/dist/{components → src/components}/VibeButton.vue.d.ts +16 -20
- package/dist/{components → src/components}/VibeButtonGroup.vue.d.ts +10 -18
- package/dist/{components → src/components}/VibeCard.vue.d.ts +51 -24
- package/dist/{components → src/components}/VibeCarousel.vue.d.ts +27 -49
- package/dist/src/components/VibeChartBar.vue.d.ts +61 -0
- package/dist/src/components/VibeChartLine.vue.d.ts +70 -0
- package/dist/src/components/VibeChartPie.vue.d.ts +34 -0
- package/dist/{components → src/components}/VibeCloseButton.vue.d.ts +9 -7
- package/dist/{components → src/components}/VibeCol.vue.d.ts +9 -17
- package/dist/src/components/VibeCollapse.vue.d.ts +76 -0
- package/dist/src/components/VibeContainer.vue.d.ts +36 -0
- package/dist/src/components/VibeDataTable.vue.d.ts +131 -0
- package/dist/src/components/VibeDatePicker.vue.d.ts +120 -0
- package/dist/src/components/VibeDraggable.vue.d.ts +77 -0
- package/dist/{components → src/components}/VibeDropdown.vue.d.ts +46 -43
- package/dist/src/components/VibeDroppable.vue.d.ts +70 -0
- package/dist/src/components/VibeFileInput.vue.d.ts +127 -0
- package/dist/{components → src/components}/VibeFormCheckbox.vue.d.ts +30 -22
- package/dist/{components → src/components}/VibeFormDatepicker.vue.d.ts +27 -30
- package/dist/{components → src/components}/VibeFormGroup.vue.d.ts +11 -14
- package/dist/{components → src/components}/VibeFormInput.vue.d.ts +22 -23
- package/dist/{components → src/components}/VibeFormRadio.vue.d.ts +23 -24
- package/dist/{components → src/components}/VibeFormSelect.vue.d.ts +28 -34
- package/dist/{components → src/components}/VibeFormSpinbutton.vue.d.ts +31 -34
- package/dist/{components → src/components}/VibeFormSwitch.vue.d.ts +22 -23
- package/dist/{components → src/components}/VibeFormTextarea.vue.d.ts +24 -25
- package/dist/{components → src/components}/VibeFormWysiwyg.vue.d.ts +24 -23
- package/dist/src/components/VibeHero.vue.d.ts +108 -0
- package/dist/{components → src/components}/VibeIcon.vue.d.ts +27 -7
- package/dist/{components → src/components}/VibeInputGroup.vue.d.ts +11 -13
- package/dist/{components → src/components}/VibeLink.vue.d.ts +14 -18
- package/dist/{components → src/components}/VibeListGroup.vue.d.ts +26 -22
- package/dist/{components → src/components}/VibeModal.vue.d.ts +29 -45
- package/dist/{components → src/components}/VibeNav.vue.d.ts +40 -20
- package/dist/{components → src/components}/VibeNavbar.vue.d.ts +12 -19
- package/dist/src/components/VibeNavbarBrand.vue.d.ts +34 -0
- package/dist/src/components/VibeNavbarNav.vue.d.ts +80 -0
- package/dist/{components → src/components}/VibeNavbarToggle.vue.d.ts +7 -5
- package/dist/{components → src/components}/VibeOffcanvas.vue.d.ts +28 -43
- package/dist/{components → src/components}/VibePagination.vue.d.ts +38 -29
- package/dist/{components → src/components}/VibePlaceholder.vue.d.ts +9 -17
- package/dist/src/components/VibePopover.vue.d.ts +72 -0
- package/dist/src/components/VibeProgress.vue.d.ts +37 -0
- package/dist/src/components/VibeResizable.vue.d.ts +140 -0
- package/dist/{components → src/components}/VibeRow.vue.d.ts +9 -17
- package/dist/src/components/VibeScrollspy.vue.d.ts +89 -0
- package/dist/src/components/VibeSkeleton.vue.d.ts +54 -0
- package/dist/src/components/VibeSlider.vue.d.ts +77 -0
- package/dist/src/components/VibeSortable.vue.d.ts +59 -0
- package/dist/{components → src/components}/VibeSpinner.vue.d.ts +4 -7
- package/dist/src/components/VibeStepper.vue.d.ts +133 -0
- package/dist/src/components/VibeTab.vue.d.ts +41 -0
- package/dist/src/components/VibeTabContent.vue.d.ts +56 -0
- package/dist/src/components/VibeTabs.vue.d.ts +78 -0
- package/dist/{components → src/components}/VibeToast.vue.d.ts +40 -42
- package/dist/src/components/VibeToastHost.vue.d.ts +16 -0
- package/dist/src/components/VibeTooltip.vue.d.ts +63 -0
- package/dist/src/components/chart/chartColors.d.ts +3 -0
- package/dist/src/components/chart/chartResize.d.ts +2 -0
- package/dist/src/components/chart/chartTooltip.d.ts +2 -0
- package/dist/src/components/chart/chartTypes.d.ts +6 -0
- package/dist/src/components/chart/drawBar.d.ts +5 -0
- package/dist/src/components/chart/drawLine.d.ts +18 -0
- package/dist/src/components/chart/drawPie.d.ts +4 -0
- package/dist/src/components/dndStore.d.ts +7 -0
- package/dist/{components → src/components}/index.d.ts +18 -1
- package/dist/{composables → src/composables}/useBreakpoints.d.ts +1 -0
- package/dist/{composables → src/composables}/useColorMode.d.ts +1 -1
- package/dist/src/composables/useForm.d.ts +22 -0
- package/dist/src/composables/useId.d.ts +2 -0
- package/dist/src/composables/usePosition.d.ts +20 -0
- package/dist/src/composables/useToast.d.ts +52 -0
- package/dist/src/directives/vTooltip.d.ts +24 -0
- package/dist/{index.d.ts → src/index.d.ts} +6 -0
- package/dist/src/injectionKeys.d.ts +28 -0
- package/dist/{types.d.ts → src/types.d.ts} +32 -6
- package/dist/src/utils/safeCss.d.ts +16 -0
- package/dist/src/utils/safeHref.d.ts +7 -0
- package/dist/src/utils/sanitizeHtml.d.ts +13 -0
- package/dist/vibeui.css +2 -1
- package/dist/vibeui.es.js +8351 -3508
- package/dist/vibeui.umd.js +3 -1
- package/docs/README.md +85 -13
- package/docs/components/advanced/popover.md +27 -52
- package/docs/components/advanced/scrollspy.md +57 -15
- package/docs/components/advanced/tooltip.md +26 -47
- package/docs/components/card/card.md +9 -1
- package/docs/components/charts/chart-bar.md +129 -0
- package/docs/components/charts/chart-line.md +136 -0
- package/docs/components/charts/chart-pie.md +102 -0
- package/docs/components/core/alert.md +27 -5
- package/docs/components/core/badge.md +0 -6
- package/docs/components/core/button-group.md +0 -6
- package/docs/components/core/button.md +1 -1
- package/docs/components/core/close-button.md +5 -5
- package/docs/components/core/link.md +60 -17
- package/docs/components/core/placeholder.md +0 -6
- package/docs/components/core/skeleton.md +40 -0
- package/docs/components/core/spinner.md +0 -6
- package/docs/components/data/datatable.md +29 -10
- package/docs/components/hero/hero.md +64 -0
- package/docs/components/interactive/accordion.md +29 -0
- package/docs/components/interactive/carousel.md +19 -4
- package/docs/components/interactive/collapse.md +3 -2
- package/docs/components/interactive/date-picker.md +78 -0
- package/docs/components/interactive/draggable.md +91 -0
- package/docs/components/interactive/dropdown.md +54 -18
- package/docs/components/interactive/modal.md +15 -20
- package/docs/components/interactive/offcanvas.md +4 -1
- package/docs/components/interactive/resizable.md +73 -0
- package/docs/components/interactive/slider.md +57 -0
- package/docs/components/interactive/sortable.md +52 -0
- package/docs/components/interactive/stepper.md +83 -0
- package/docs/components/interactive/tabs.md +66 -0
- package/docs/components/interactive/toast.md +93 -30
- package/docs/components/layout/col.md +0 -6
- package/docs/components/layout/container.md +0 -6
- package/docs/components/layout/row.md +0 -6
- package/docs/components/list/list-group.md +4 -0
- package/docs/components/navigation/breadcrumb.md +4 -0
- package/docs/components/navigation/nav.md +64 -1
- package/docs/components/navigation/navbar.md +2 -0
- package/docs/components/navigation/pagination.md +16 -0
- package/docs/components/progress/progress.md +7 -1
- package/docs/composables/color-mode.md +44 -6
- package/docs/composables/use-form.md +78 -0
- package/docs/composables/use-position.md +68 -0
- package/docs/composables/use-toast.md +91 -0
- package/docs/directives/v-tooltip.md +58 -0
- package/docs/forms/README.md +60 -61
- package/docs/forms/autocomplete.md +96 -0
- package/docs/forms/file-input.md +97 -0
- package/docs/forms/form-checkbox.md +75 -25
- package/docs/forms/form-datepicker.md +58 -28
- package/docs/forms/form-group.md +79 -44
- package/docs/forms/form-input.md +88 -31
- package/docs/forms/form-radio.md +60 -36
- package/docs/forms/form-select.md +75 -31
- package/docs/forms/form-spinbutton.md +72 -33
- package/docs/forms/form-switch.md +53 -25
- package/docs/forms/form-textarea.md +60 -29
- package/docs/forms/form-wysiwyg.md +73 -38
- package/docs/forms/input-group.md +53 -34
- package/docs/forms/validation.md +135 -521
- package/docs/getting-started/starter-template.md +136 -0
- package/docs/superpowers/plans/2026-05-12-vibe-charts.md +1999 -0
- package/docs/superpowers/plans/2026-05-29-e2e-browser-testing.md +615 -0
- package/docs/superpowers/specs/2026-05-12-charting-design.md +185 -0
- package/docs/superpowers/specs/2026-05-29-e2e-browser-testing-design.md +168 -0
- package/docs/utilities/position.md +82 -0
- package/docs/versioning.md +57 -0
- package/examples/README.md +201 -0
- package/examples/album.html +262 -0
- package/examples/blog.html +166 -0
- package/examples/carousel.html +114 -0
- package/examples/checkout.html +275 -0
- package/examples/cover.html +89 -0
- package/examples/dashboard.html +156 -0
- package/examples/index.html +129 -0
- package/examples/jumbotron.html +56 -0
- package/examples/mobile-dashboard.html +138 -0
- package/examples/pricing.html +172 -0
- package/examples/product.html +145 -0
- package/examples/sidebars.html +166 -0
- package/examples/sign-in.html +119 -0
- package/examples/starter.html +314 -0
- package/examples/sticky-footer-navbar.html +70 -0
- package/examples/sticky-footer.html +60 -0
- package/examples/test-simple.html +91 -0
- package/llms.txt +407 -47
- package/package.json +42 -13
- package/dist/App.vue.d.ts +0 -2
- package/dist/components/HelloWorld.vue.d.ts +0 -5
- package/dist/components/VibeAccordion.vue.d.ts +0 -90
- package/dist/components/VibeBreadcrumb.vue.d.ts +0 -47
- package/dist/components/VibeCollapse.vue.d.ts +0 -84
- package/dist/components/VibeContainer.vue.d.ts +0 -44
- package/dist/components/VibeDataTable.vue.d.ts +0 -76
- package/dist/components/VibeNavbarBrand.vue.d.ts +0 -42
- package/dist/components/VibeNavbarNav.vue.d.ts +0 -61
- package/dist/components/VibePopover.vue.d.ts +0 -95
- package/dist/components/VibeProgress.vue.d.ts +0 -45
- package/dist/components/VibeScrollspy.vue.d.ts +0 -77
- package/dist/components/VibeTabContent.vue.d.ts +0 -74
- package/dist/components/VibeTooltip.vue.d.ts +0 -86
- package/dist/composables/useId.d.ts +0 -5
- package/dist/types/index.d.ts +0 -6
- /package/dist/{composables → src/composables}/useBackButton.d.ts +0 -0
- /package/dist/{composables → src/composables}/useFormValidation.d.ts +0 -0
- /package/dist/{main.d.ts → src/main.d.ts} +0 -0
package/llms.txt
CHANGED
|
@@ -4,7 +4,7 @@ A Vue 3 component library that wraps Bootstrap 5.3. Every Bootstrap component is
|
|
|
4
4
|
|
|
5
5
|
**Package:** `@velkymx/vibeui`
|
|
6
6
|
**Stack:** Vue 3 (Composition API) + Bootstrap 5.3 + TypeScript + Vite
|
|
7
|
-
**Current version:** 0.
|
|
7
|
+
**Current version:** 1.0.0
|
|
8
8
|
|
|
9
9
|
---
|
|
10
10
|
|
|
@@ -18,6 +18,64 @@ VibeUI is a thin but complete abstraction layer over Bootstrap. It does three th
|
|
|
18
18
|
|
|
19
19
|
---
|
|
20
20
|
|
|
21
|
+
## Building With VibeUI — start here
|
|
22
|
+
|
|
23
|
+
This is the whole workflow: **load → use → leverage**. Follow it and you won't fight the library. (Detailed reference sections follow; the per-component docs are linked in the Documentation Index at the end — read a component's doc before using it.)
|
|
24
|
+
|
|
25
|
+
### 1. Load
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm install @velkymx/vibeui bootstrap
|
|
29
|
+
```
|
|
30
|
+
```ts
|
|
31
|
+
import { createApp } from 'vue'
|
|
32
|
+
import VibeUI from '@velkymx/vibeui'
|
|
33
|
+
import 'bootstrap/dist/css/bootstrap.min.css' // YOU import the CSS
|
|
34
|
+
createApp(App).use(VibeUI).mount('#app') // registers every component + the v-vibe-tooltip directive
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
- **Import Bootstrap CSS yourself. Never import Bootstrap JS** — VibeUI loads it internally, on demand, per component.
|
|
38
|
+
- `app.use(VibeUI)` registers everything globally. Or import by name for tree-shaking **and** full template type-checking: `import { VibeButton, VibeModal } from '@velkymx/vibeui'`.
|
|
39
|
+
- **Non-bundler / UMD / CDN pages:** the internal `import('bootstrap')` is a bare specifier, so add an import map or interactive components silently fail:
|
|
40
|
+
`<script type="importmap">{ "imports": { "bootstrap": "https://esm.sh/bootstrap@5.3" } }</script>`
|
|
41
|
+
|
|
42
|
+
### 2. Use — props, `v-model`, `:items`, slots
|
|
43
|
+
|
|
44
|
+
- **Style with props:** `variant`, `size`, `outline` (boolean). For one-offs pass `class`/`style` — they merge onto the component root.
|
|
45
|
+
- **Visibility is `v-model`:** `<VibeModal v-model="open" />` (also Offcanvas / Toast / Collapse / Alert). Do not call Bootstrap `show`/`hide`.
|
|
46
|
+
- **Data-driven components take arrays — never hand-write the Bootstrap markup:**
|
|
47
|
+
- `:items` → `VibeNav`, `VibeDropdown`, `VibeListGroup`, `VibeBreadcrumb`, `VibeNavbarNav`
|
|
48
|
+
- `:items` (`CarouselItem[]`, each needs `src`) → `VibeCarousel`
|
|
49
|
+
- `:options` → `VibeFormSelect`
|
|
50
|
+
- `:bars` → `VibeProgress`
|
|
51
|
+
- `:columns` + `:items` → `VibeDataTable`
|
|
52
|
+
- **Custom content uses slots:** `#item` (Nav/Dropdown/ListGroup), `#header`/`#footer`/`#image` (Card), `cell(<key>)` (DataTable), default slot for body.
|
|
53
|
+
- **Imperative actions use the exposed methods via a template ref:** `modal.value?.show()` / `.hide()` / `.toggle()` / `.refresh()`. Drive the component — never reach around it to Bootstrap.
|
|
54
|
+
|
|
55
|
+
### 3. Leverage
|
|
56
|
+
|
|
57
|
+
- **Forms:** wrap controls in `<VibeFormGroup label="…">` (auto-links label + id + a11y). Validate with `useForm` + `validators` (`required`/`email`/`minLength`/…) and bind `:validation-state` / `:validation-message` per field.
|
|
58
|
+
- **Composables:** `useToast` (global toasts; mount `<VibeToastHost/>` once), `useColorMode` (light/dark/auto), `useBreakpoints` (`isMobile`/`isTablet`/…), `useForm`, `usePosition`.
|
|
59
|
+
- **Layout & sections:** `VibeContainer` / `VibeRow` (`:gutters`) / `VibeCol` (`:cols`/`:md`/…/`:order`); `VibeHero` for banner/hero sections; `VibeCard` (with `headerClass`/`bodyClass`/`#image`).
|
|
60
|
+
- **Copy whole patterns** from the full-page templates in `examples/` (Album, Pricing, Checkout, Sign-in, Dashboard, Sidebars, Cover, Product, Carousel, Blog).
|
|
61
|
+
|
|
62
|
+
### Read the doc first
|
|
63
|
+
|
|
64
|
+
A component's exact props/events/slots live in its doc page (Documentation Index, bottom). **Read it before building — do not guess props or reverse-engineer from `dist/`.** The documented API is the source of truth.
|
|
65
|
+
|
|
66
|
+
### Common mistakes — do NOT do these
|
|
67
|
+
|
|
68
|
+
- ❌ `variant="outline-secondary"` → ✅ `variant="secondary" outline` (outline is a boolean prop)
|
|
69
|
+
- ❌ `<VibeIcon name="house" />` → ✅ `<VibeIcon icon="house" />`
|
|
70
|
+
- ❌ `<VibeCarousel :slides="…" />` → ✅ `<VibeCarousel :items="…" />` (each `CarouselItem` needs `src`)
|
|
71
|
+
- ❌ `<vibe-card-body>`, `<vibe-list-group-item>`, `<vibe-nav-item>`, `<vibe-dropdown-item>`, `<vibe-progress-bar>` — **none of these exist.** Use the default / `#item` slot and `:items` / `:bars`.
|
|
72
|
+
- ❌ hand-written `<ul class="nav">` / `<div class="card">` → ✅ `<VibeNav :items>` / `<VibeCard>`
|
|
73
|
+
- ❌ `import 'bootstrap/dist/js/…'` or `new bootstrap.Modal()` → ✅ never; use props, `v-model`, and exposed methods
|
|
74
|
+
- ❌ UMD/CDN page with no `bootstrap` import map → interactive components silently fall back / fail
|
|
75
|
+
- ❌ guessing a prop name → ✅ open the component's doc page first
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
21
79
|
## Project Structure
|
|
22
80
|
|
|
23
81
|
```
|
|
@@ -28,13 +86,15 @@ vibeui/
|
|
|
28
86
|
│ ├── components/
|
|
29
87
|
│ │ ├── index.ts # Component registration + Vue plugin
|
|
30
88
|
│ │ ├── VibeAlert.vue
|
|
31
|
-
│ │ ├── VibeButton.vue # Renders as <button>, <a>, or <router-link
|
|
89
|
+
│ │ ├── VibeButton.vue # Renders as <button>, <a>, or <router-link>; variant="link"
|
|
32
90
|
│ │ ├── VibeBadge.vue
|
|
33
91
|
│ │ ├── VibeButtonGroup.vue
|
|
34
|
-
│ │ ├── VibeCard.vue
|
|
92
|
+
│ │ ├── VibeCard.vue # headerClass/bodyClass/footerClass + #image slot
|
|
93
|
+
│ │ ├── VibeHero.vue # hero/banner section (variant/bordered/bgImage/gradient)
|
|
35
94
|
│ │ ├── VibeCloseButton.vue
|
|
36
95
|
│ │ ├── VibeSpinner.vue
|
|
37
96
|
│ │ ├── VibePlaceholder.vue
|
|
97
|
+
│ │ ├── VibeSkeleton.vue # text/rect/circle/card loading placeholder
|
|
38
98
|
│ │ ├── VibeContainer.vue # Layout
|
|
39
99
|
│ │ ├── VibeRow.vue
|
|
40
100
|
│ │ ├── VibeCol.vue
|
|
@@ -46,48 +106,81 @@ vibeui/
|
|
|
46
106
|
│ │ ├── VibeNavbarNav.vue
|
|
47
107
|
│ │ ├── VibePagination.vue # v-model:currentPage
|
|
48
108
|
│ │ ├── VibeTabContent.vue
|
|
109
|
+
│ │ ├── VibeTabs.vue # tab container w/ content switching
|
|
110
|
+
│ │ ├── VibeTab.vue # child of VibeTabs
|
|
49
111
|
│ │ ├── VibeListGroup.vue # Data-driven: accepts items[]
|
|
50
112
|
│ │ ├── VibeProgress.vue # Data-driven: accepts bars[]
|
|
113
|
+
│ │ ├── VibeStepper.vue # multi-step wizard w/ guards
|
|
51
114
|
│ │ ├── VibeAccordion.vue # Bootstrap JS — auto init/destroy
|
|
52
115
|
│ │ ├── VibeCollapse.vue # Bootstrap JS — v-model
|
|
53
116
|
│ │ ├── VibeDropdown.vue # Bootstrap JS — data-driven items[]
|
|
54
|
-
│ │ ├── VibeModal.vue # Bootstrap JS — v-model, Teleport
|
|
117
|
+
│ │ ├── VibeModal.vue # Bootstrap JS — v-model, Teleport, size xl/fullscreen
|
|
55
118
|
│ │ ├── VibeOffcanvas.vue # Bootstrap JS — v-model, Teleport to body
|
|
56
|
-
│ │ ├── VibeToast.vue # Bootstrap JS — v-model
|
|
57
|
-
│ │ ├──
|
|
119
|
+
│ │ ├── VibeToast.vue # Bootstrap JS — v-model OR no-container mode for host
|
|
120
|
+
│ │ ├── VibeToastHost.vue # hosts queued toasts from useToast()
|
|
121
|
+
│ │ ├── VibeCarousel.vue # Bootstrap JS — v-model (active slide index)
|
|
58
122
|
│ │ ├── VibeTooltip.vue # Bootstrap JS — reactive re-init on prop change
|
|
59
123
|
│ │ ├── VibePopover.vue # Bootstrap JS — reactive re-init on prop change
|
|
60
124
|
│ │ ├── VibeScrollspy.vue
|
|
61
125
|
│ │ ├── VibeIcon.vue # Renders Bootstrap Icons (bi-*)
|
|
62
|
-
│ │ ├── VibeDataTable.vue #
|
|
126
|
+
│ │ ├── VibeDataTable.vue # Generic <T>: sortable, searchable, paginated
|
|
127
|
+
│ │ ├── VibeDatePicker.vue # calendar popover, single + range, keyboard nav
|
|
128
|
+
│ │ ├── VibeAutocomplete.vue # search-as-you-type, sync or async source
|
|
129
|
+
│ │ ├── VibeFileInput.vue # file picker w/ drag-drop, accept enforcement
|
|
130
|
+
│ │ ├── VibeSlider.vue # single + range slider, keyboard, track click
|
|
131
|
+
│ │ ├── VibeResizable.vue # corner / edge handle resizing
|
|
132
|
+
│ │ ├── VibeSortable.vue # drag-to-reorder list (single-list)
|
|
133
|
+
│ │ ├── VibeDraggable.vue # free-drag source, pairs with VibeDroppable
|
|
134
|
+
│ │ ├── VibeDroppable.vue # drop zone, group / acceptGroups matching
|
|
135
|
+
│ │ ├── dndStore.ts # shared payload store between drag/drop
|
|
63
136
|
│ │ ├── VibeFormInput.vue
|
|
64
|
-
│ │ ├── VibeFormSelect.vue
|
|
137
|
+
│ │ ├── VibeFormSelect.vue # typed primitive option values
|
|
65
138
|
│ │ ├── VibeFormTextarea.vue
|
|
66
139
|
│ │ ├── VibeFormCheckbox.vue
|
|
67
140
|
│ │ ├── VibeFormRadio.vue
|
|
68
141
|
│ │ ├── VibeFormSwitch.vue
|
|
69
142
|
│ │ ├── VibeFormSpinbutton.vue
|
|
70
|
-
│ │ ├── VibeFormDatepicker.vue
|
|
143
|
+
│ │ ├── VibeFormDatepicker.vue # Native <input type=date> wrapper
|
|
71
144
|
│ │ ├── VibeFormGroup.vue # Context-aware — auto-links label to child input
|
|
72
|
-
│ │
|
|
73
|
-
│
|
|
74
|
-
│
|
|
75
|
-
│
|
|
76
|
-
│
|
|
145
|
+
│ │ ├── VibeInputGroup.vue # prepend/append slots; pairs with noWrapper inputs
|
|
146
|
+
│ │ ├── VibeLink.vue
|
|
147
|
+
│ │ ├── VibeFormWysiwyg.vue # Quill 2.x — toolbar string presets
|
|
148
|
+
│ │ ├── VibeChartLine.vue # canvas line chart, smooth/fill, Bootstrap color cycling
|
|
149
|
+
│ │ ├── VibeChartBar.vue # canvas bar chart, grouped + stacked
|
|
150
|
+
│ │ └── VibeChartPie.vue # canvas pie chart, Bootstrap color cycling
|
|
151
|
+
│ ├── composables/
|
|
152
|
+
│ │ ├── useId.ts # Generates unique IDs (SSR-safe)
|
|
153
|
+
│ │ ├── useColorMode.ts # Bootstrap color mode management (singleton)
|
|
154
|
+
│ │ ├── useFormValidation.ts # Field-level validation + built-in validators
|
|
155
|
+
│ │ ├── useForm.ts # multi-field form state w/ deep-clone reset
|
|
156
|
+
│ │ ├── useToast.ts # global toast service (use w/ <VibeToastHost />)
|
|
157
|
+
│ │ ├── usePosition.ts # floating-ui anchor positioning
|
|
158
|
+
│ │ ├── useBackButton.ts # Android hardware back button
|
|
159
|
+
│ │ └── useBreakpoints.ts # programmatic breakpoint detection
|
|
160
|
+
│ └── directives/
|
|
161
|
+
│ └── vTooltip.ts # v-vibe-tooltip directive
|
|
77
162
|
├── tests/
|
|
78
163
|
│ ├── components/ # Component tests (Vitest + @vue/test-utils)
|
|
79
|
-
│
|
|
164
|
+
│ ├── composables/ # Composable tests
|
|
165
|
+
│ ├── directives/ # Directive tests
|
|
166
|
+
│ └── mocks/bootstrap.ts # Aliased in vite.config.ts test block
|
|
80
167
|
├── docs/
|
|
81
168
|
│ ├── README.md # Docs index — start here
|
|
82
169
|
│ ├── components/ # Per-component reference docs
|
|
83
170
|
│ ├── forms/ # Form + validation docs
|
|
171
|
+
│ ├── directives/ # v-vibe-tooltip
|
|
172
|
+
│ ├── utilities/position.md # Bootstrap position-* class reference
|
|
84
173
|
│ └── composables/
|
|
85
|
-
│
|
|
86
|
-
├──
|
|
87
|
-
│
|
|
88
|
-
│
|
|
89
|
-
│
|
|
90
|
-
│
|
|
174
|
+
│ ├── color-mode.md
|
|
175
|
+
│ ├── breakpoints.md
|
|
176
|
+
│ ├── back-button.md
|
|
177
|
+
│ ├── use-form.md
|
|
178
|
+
│ ├── use-position.md
|
|
179
|
+
│ └── use-toast.md
|
|
180
|
+
├── examples/ # Standalone HTML demo pages (load ../dist + CDNs; run `npm run build` first, or `npm run examples`)
|
|
181
|
+
├── smoke/ # manual smoke test page
|
|
182
|
+
│ ├── index.html # `npm run smoke` builds + serves on :8001
|
|
183
|
+
│ └── dist/ # gitignored; populated by `npm run smoke`
|
|
91
184
|
├── vite.config.ts # Also contains Vitest config
|
|
92
185
|
└── llms.txt # This file
|
|
93
186
|
```
|
|
@@ -124,10 +217,42 @@ Bootstrap JS is handled internally via dynamic import — do **not** import `boo
|
|
|
124
217
|
Everything is exported from the package root:
|
|
125
218
|
|
|
126
219
|
```ts
|
|
127
|
-
|
|
128
|
-
import
|
|
129
|
-
|
|
130
|
-
|
|
220
|
+
// Plugin (registers all components + the v-vibe-tooltip directive)
|
|
221
|
+
import VibeUI from '@velkymx/vibeui'
|
|
222
|
+
app.use(VibeUI)
|
|
223
|
+
|
|
224
|
+
// Individual components
|
|
225
|
+
import {
|
|
226
|
+
VibeButton, VibeAlert, VibeModal, VibeOffcanvas,
|
|
227
|
+
VibeCard, VibeHero,
|
|
228
|
+
VibeFileInput, VibeSkeleton, VibeDatePicker, VibeAutocomplete,
|
|
229
|
+
VibeTabs, VibeTab, VibeStepper,
|
|
230
|
+
VibeSortable, VibeDraggable, VibeDroppable,
|
|
231
|
+
VibeResizable, VibeSlider,
|
|
232
|
+
VibeToast, VibeToastHost,
|
|
233
|
+
VibeChartLine, VibeChartBar, VibeChartPie
|
|
234
|
+
/* ... */
|
|
235
|
+
} from '@velkymx/vibeui'
|
|
236
|
+
|
|
237
|
+
// Composables
|
|
238
|
+
import {
|
|
239
|
+
useColorMode, useFormValidation, validators,
|
|
240
|
+
useId, useBreakpoints, useBackButton,
|
|
241
|
+
useForm, useToast, usePosition, resetToastStoreForSSR
|
|
242
|
+
} from '@velkymx/vibeui'
|
|
243
|
+
|
|
244
|
+
// Directives (also registered globally by app.use(VibeUI))
|
|
245
|
+
import { vTooltip } from '@velkymx/vibeui'
|
|
246
|
+
|
|
247
|
+
// Types
|
|
248
|
+
import type {
|
|
249
|
+
Variant, ButtonVariant, ColorMode, Size,
|
|
250
|
+
DataTableColumn, DataTableCellSlotProps,
|
|
251
|
+
FormSelectOption, FormSelectOptionValue,
|
|
252
|
+
ToastSpec, ToastShowOptions, UseToastReturn,
|
|
253
|
+
UsePositionOptions, UsePositionReturn,
|
|
254
|
+
ChartData, ChartDataset, ChartLegendPosition
|
|
255
|
+
} from '@velkymx/vibeui'
|
|
131
256
|
```
|
|
132
257
|
|
|
133
258
|
---
|
|
@@ -137,26 +262,48 @@ import type { Variant, ColorMode, Size, ... } from '@velkymx/vibeui'
|
|
|
137
262
|
These types are used across all components. Always import from `@velkymx/vibeui`.
|
|
138
263
|
|
|
139
264
|
```ts
|
|
140
|
-
type Variant
|
|
141
|
-
type
|
|
142
|
-
type
|
|
143
|
-
type
|
|
144
|
-
type
|
|
145
|
-
type
|
|
146
|
-
type
|
|
147
|
-
type
|
|
148
|
-
type
|
|
265
|
+
type Variant = 'primary' | 'secondary' | 'success' | 'danger' | 'warning' | 'info' | 'light' | 'dark'
|
|
266
|
+
type ButtonVariant = Variant | 'link'
|
|
267
|
+
type Size = 'sm' | 'lg'
|
|
268
|
+
type ColorMode = 'light' | 'dark' | 'auto'
|
|
269
|
+
type ButtonType = 'button' | 'submit' | 'reset'
|
|
270
|
+
type Tag = 'div' | 'span' | 'section' | 'article' | 'nav' | 'aside' | 'header' | 'footer' | 'main'
|
|
271
|
+
type TooltipPlacement = 'top' | 'bottom' | 'start' | 'end' // also OffcanvasPlacement, NavbarPosition, ToastPlacement exist
|
|
272
|
+
type ToastPlacement = 'top-start' | 'top-center' | 'top-end' | 'middle-...' | 'bottom-...'
|
|
273
|
+
type Direction = 'up' | 'down' | 'start' | 'end'
|
|
274
|
+
type SpinnerType = 'border' | 'grow'
|
|
275
|
+
type InputType = 'text' | 'email' | 'password' | 'number' | 'tel' | 'url' | 'search' | 'date' | 'time' | ...
|
|
149
276
|
type ValidationState = 'valid' | 'invalid' | null
|
|
150
277
|
|
|
151
278
|
// Data-driven component item shapes
|
|
152
279
|
interface BreadcrumbItem { text, href?, to?, active? }
|
|
153
|
-
interface NavItem { text, href?, to?, active?, disabled?, children? }
|
|
280
|
+
interface NavItem { text, href?, to?, target?, active?, disabled?, children? }
|
|
281
|
+
// target?: string — tab panel selector (e.g. '#panel-id') for tabs/pills mode with router-link items
|
|
154
282
|
interface DropdownItem { text?, href?, to?, active?, disabled?, divider?, header? }
|
|
155
283
|
interface ListGroupItem { text, href?, to?, active?, disabled?, variant? }
|
|
156
284
|
interface AccordionItem { id, title, content, show? }
|
|
157
285
|
interface CarouselItem { src, alt?, caption?, captionText?, active?, interval? }
|
|
158
286
|
interface ProgressBar { value, max?, variant?, striped?, animated?, label?, showValue? }
|
|
159
|
-
|
|
287
|
+
|
|
288
|
+
// Generic over the row type T (default Record<string, unknown>)
|
|
289
|
+
interface DataTableColumn<T> { key: keyof T & string, label, sortable?, searchable?,
|
|
290
|
+
formatter?: (value: T[keyof T], row: T) => string | number, ... }
|
|
291
|
+
interface DataTableCellSlotProps<T> { item: T, value: T[keyof T], index: number }
|
|
292
|
+
|
|
293
|
+
// Form select primitive — accepts null / undefined / boolean
|
|
294
|
+
type FormSelectOptionValue = string | number | boolean | null | undefined
|
|
295
|
+
interface FormSelectOption { value: FormSelectOptionValue, text, disabled? }
|
|
296
|
+
|
|
297
|
+
// charts
|
|
298
|
+
interface ChartDataset { label: string, data: number[], color?: string }
|
|
299
|
+
interface ChartData { labels: string[], datasets: ChartDataset[] }
|
|
300
|
+
type ChartLegendPosition = 'top' | 'bottom' | 'none'
|
|
301
|
+
|
|
302
|
+
// stepper / toast / position
|
|
303
|
+
interface StepperStep { label, description?, disabled?, icon? }
|
|
304
|
+
interface ToastSpec { id, title?, body, variant?, placement?, autohide?, delay? }
|
|
305
|
+
interface ToastShowOptions { id?, title?, variant?, placement?, autohide?, delay? }
|
|
306
|
+
interface UsePositionOptions { my?, at?, offset?, collision?, autoUpdate?, strategy? }
|
|
160
307
|
```
|
|
161
308
|
|
|
162
309
|
---
|
|
@@ -266,9 +413,13 @@ Components like `VibeBreadcrumb`, `VibeListGroup`, `VibeDropdown`, `VibeAccordio
|
|
|
266
413
|
</VibeFormGroup>
|
|
267
414
|
```
|
|
268
415
|
|
|
269
|
-
###
|
|
416
|
+
### Programmatic control (template ref)
|
|
417
|
+
|
|
418
|
+
Visibility is normally driven by `v-model` — prefer that. When you must trigger an action imperatively (e.g. open a modal from a non-template handler), interactive components expose **safe methods** via a template ref. Use these, not the underlying Bootstrap object:
|
|
270
419
|
|
|
271
|
-
|
|
420
|
+
- `VibeModal` / `VibeOffcanvas` / `VibeToast` → `show()`, `hide()`
|
|
421
|
+
- `VibeDropdown` → `show()`, `hide()`, `toggle()`
|
|
422
|
+
- `VibeCarousel` / `VibeAccordion` / `VibeNav` / `VibeScrollspy` → `refresh()`
|
|
272
423
|
|
|
273
424
|
```vue
|
|
274
425
|
<template>
|
|
@@ -277,14 +428,72 @@ Every interactive component exposes its Bootstrap instance via a template ref:
|
|
|
277
428
|
|
|
278
429
|
<script setup>
|
|
279
430
|
const modal = useTemplateRef('modal')
|
|
280
|
-
// modal.value
|
|
431
|
+
modal.value?.show() // or modal.value?.hide()
|
|
281
432
|
</script>
|
|
282
433
|
```
|
|
283
434
|
|
|
435
|
+
Drive every component through its props, `v-model`, slots, and these exposed methods. Do not reach around the component to Bootstrap's own JS — VibeUI owns that lifecycle, and bypassing it desyncs component state.
|
|
436
|
+
|
|
284
437
|
### Teleportation
|
|
285
438
|
|
|
286
439
|
`VibeModal`, `VibeOffcanvas`, and `VibeToast` render via `<Teleport to="body">` by default. This prevents CSS stacking context issues. No configuration needed.
|
|
287
440
|
|
|
441
|
+
### Toast service
|
|
442
|
+
|
|
443
|
+
Mount `<VibeToastHost />` once at the app root, then dispatch from anywhere via the `useToast` composable. Toasts at the same placement stack inside one shared `.toast-container`.
|
|
444
|
+
|
|
445
|
+
```vue
|
|
446
|
+
<!-- App.vue -->
|
|
447
|
+
<template>
|
|
448
|
+
<RouterView />
|
|
449
|
+
<VibeToastHost />
|
|
450
|
+
</template>
|
|
451
|
+
```
|
|
452
|
+
|
|
453
|
+
```ts
|
|
454
|
+
import { useToast } from '@velkymx/vibeui'
|
|
455
|
+
const toast = useToast()
|
|
456
|
+
toast.success('Saved')
|
|
457
|
+
toast.error('Network error', { delay: 8000 })
|
|
458
|
+
const sticky = toast.warn('Long export…', { autohide: false })
|
|
459
|
+
toast.dismiss(sticky.id)
|
|
460
|
+
```
|
|
461
|
+
|
|
462
|
+
The component-form `<VibeToast v-model="show">` still works for app-local toasts.
|
|
463
|
+
|
|
464
|
+
### Drag & drop
|
|
465
|
+
|
|
466
|
+
Two layers depending on use case:
|
|
467
|
+
|
|
468
|
+
- **Single-list reorder** → `<VibeSortable v-model="items">` with a scoped slot per item.
|
|
469
|
+
- **Cross-list moves** (kanban, builders) → `<VibeDraggable :payload>` paired with `<VibeDroppable @drop>`. Match by `group` (default `'default'`) or `acceptGroups` whitelist. Payloads pass through a shared module store, so they can be typed objects, refs, or non-serializable values — no DataTransfer string round-trip.
|
|
470
|
+
|
|
471
|
+
A document-level `dragend` / `drop` listener installed by `setActiveDrag` clears stale payloads if a drag aborts (escape, page nav, browser bug).
|
|
472
|
+
|
|
473
|
+
### Calendar popover
|
|
474
|
+
|
|
475
|
+
`VibeDatePicker` is a fully custom calendar (distinct from `VibeFormDatepicker` which wraps `<input type=date>`). ISO `YYYY-MM-DD` model, `range` mode emits `[start, end]`, full keyboard nav (arrows / PageUp+Down / Home+End / Enter / Escape), click-outside-to-close.
|
|
476
|
+
|
|
477
|
+
```vue
|
|
478
|
+
<VibeDatePicker v-model="due" :min="'2026-01-01'" :max="'2026-12-31'" />
|
|
479
|
+
<VibeDatePicker v-model="window" range />
|
|
480
|
+
```
|
|
481
|
+
|
|
482
|
+
### Floating UI anchoring
|
|
483
|
+
|
|
484
|
+
For ad-hoc anchoring when CSS position utilities aren't enough. Wraps `@floating-ui/dom` with a natural-language anchor-point API.
|
|
485
|
+
|
|
486
|
+
```ts
|
|
487
|
+
const { x, y, placement, update, stop } = usePosition(targetRef, anchorRef, () => ({
|
|
488
|
+
my: 'top center',
|
|
489
|
+
at: 'bottom center',
|
|
490
|
+
offset: [0, 8],
|
|
491
|
+
collision: 'flip+shift'
|
|
492
|
+
}))
|
|
493
|
+
```
|
|
494
|
+
|
|
495
|
+
Pass options as a getter to keep `my` / `at` reactive.
|
|
496
|
+
|
|
288
497
|
---
|
|
289
498
|
|
|
290
499
|
## Composables
|
|
@@ -346,20 +555,95 @@ Generates a unique, SSR-safe ID string. Used internally by form components.
|
|
|
346
555
|
const id = useId('prefix') // → 'prefix-3-7'
|
|
347
556
|
```
|
|
348
557
|
|
|
558
|
+
### useForm
|
|
559
|
+
|
|
560
|
+
Multi-field form state with reactive `fields`, `errors`, `touched` maps. `fields` is a Vue `reactive` so its properties auto-unwrap in templates.
|
|
561
|
+
|
|
562
|
+
```ts
|
|
563
|
+
const { fields, errors, touched, isDirty, isValid, validate, validateField, reset, markAllTouched, setField, values }
|
|
564
|
+
= useForm({ name: '', email: '', age: 0 })
|
|
565
|
+
|
|
566
|
+
const result = await validate({
|
|
567
|
+
name: [validators.required('Name is required')],
|
|
568
|
+
email: [validators.required(), validators.email()],
|
|
569
|
+
age: [validators.min(18, 'Must be 18+')]
|
|
570
|
+
})
|
|
571
|
+
// result.valid: boolean
|
|
572
|
+
// result.errors: Partial<Record<K, string>>
|
|
573
|
+
```
|
|
574
|
+
|
|
575
|
+
`isValid` is `false` until the first `validate()` or `validateField()` call; then `true` if no field has an error. Use this to guard submit buttons without showing errors on a fresh form.
|
|
576
|
+
|
|
577
|
+
`reset` deep-clones the initial values back in (works for object / array fields). Dirty tracking uses structural compare (`JSON.stringify`) so non-primitive fields don't read as permanently dirty.
|
|
578
|
+
|
|
579
|
+
For **single-field** validation, prefer `useFormValidation` (older API) and destructure at the call site to keep templates clean.
|
|
580
|
+
|
|
581
|
+
### useToast
|
|
582
|
+
|
|
583
|
+
```ts
|
|
584
|
+
const { show, success, error, warn, info, dismiss, clear, toasts } = useToast()
|
|
585
|
+
|
|
586
|
+
success(body, { id?, title?, placement?, autohide?, delay? })
|
|
587
|
+
toasts // DeepReadonly<ToastSpec[]>
|
|
588
|
+
```
|
|
589
|
+
|
|
590
|
+
The store is a module singleton (per app per JS realm). For SSR, call `resetToastStoreForSSR()` from the server entry's per-request reset hook. Multi-app browser usage shares the same queue — use the component form for app-local notifications.
|
|
591
|
+
|
|
592
|
+
### usePosition
|
|
593
|
+
|
|
594
|
+
```ts
|
|
595
|
+
const { x, y, placement, update, stop } = usePosition(target, anchor, options)
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
`options` accepts a plain object (static) **or** a getter `() => UsePositionOptions` (reactive). The getter is re-evaluated on every `update()` and is part of the watch dependency set.
|
|
599
|
+
|
|
600
|
+
The composable owns `position` / `left` / `top` on the target element while alive. `stop()` (and `onBeforeUnmount`) restore the previous inline values.
|
|
601
|
+
|
|
602
|
+
### useBreakpoints
|
|
603
|
+
|
|
604
|
+
```ts
|
|
605
|
+
const { isXs, isSm, isMd, isLg, isXl, isXxl, isMobile, isTablet } = useBreakpoints()
|
|
606
|
+
```
|
|
607
|
+
|
|
608
|
+
Reactive booleans driven by `window.matchMedia` against Bootstrap's standard breakpoints.
|
|
609
|
+
|
|
610
|
+
### useBackButton
|
|
611
|
+
|
|
612
|
+
Hooks Android's hardware back button (Capacitor / Cordova) into Vue components — `VibeModal` and `VibeOffcanvas` register their close handlers automatically.
|
|
613
|
+
|
|
614
|
+
---
|
|
615
|
+
|
|
616
|
+
## Directives
|
|
617
|
+
|
|
618
|
+
### v-vibe-tooltip
|
|
619
|
+
|
|
620
|
+
Inline tooltip directive registered globally by `app.use(VibeUI)`.
|
|
621
|
+
|
|
622
|
+
```vue
|
|
623
|
+
<button v-vibe-tooltip="'Save changes'">Save</button>
|
|
624
|
+
<span v-vibe-tooltip="{ title: 'Open in new tab', placement: 'right', html: true }">↗</span>
|
|
625
|
+
```
|
|
626
|
+
|
|
627
|
+
Re-creates the underlying Bootstrap Tooltip when `placement` / `trigger` / `html` change; title-only changes use the cheap `setContent` path. Touch devices auto-swap `hover focus` → `click`.
|
|
628
|
+
|
|
629
|
+
For component-form usage with rich slot content, use `<VibeTooltip>`.
|
|
630
|
+
|
|
349
631
|
---
|
|
350
632
|
|
|
351
633
|
## Testing
|
|
352
634
|
|
|
353
|
-
|
|
635
|
+
Two Vitest projects share one Vite pipeline:
|
|
636
|
+
- **`unit`** — `@vue/test-utils` + happy-dom, with **Bootstrap JS mocked** (`tests/mocks/bootstrap.ts`, aliased only in this project). Fast.
|
|
637
|
+
- **`browser`** — real headless Chromium (Playwright provider) running the **real** Bootstrap JS + Quill — the integration paths happy-dom can't reach.
|
|
354
638
|
|
|
355
|
-
**Run tests:**
|
|
356
639
|
```bash
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
640
|
+
npm run test:run # unit suite (what CI runs)
|
|
641
|
+
npm run test:browser # browser suite, real Chromium
|
|
642
|
+
npm run test:all # both projects
|
|
643
|
+
npm run test:examples # Playwright: load every examples/*.html and assert it mounts (needs CDN network)
|
|
360
644
|
```
|
|
361
645
|
|
|
362
|
-
|
|
646
|
+
So unit tests never trigger real Bootstrap JS; the browser tests deliberately do.
|
|
363
647
|
|
|
364
648
|
**Pattern for component tests:**
|
|
365
649
|
```ts
|
|
@@ -391,7 +675,15 @@ Build output:
|
|
|
391
675
|
- `dist/vibeui.umd.js` — UMD for CDN / script tag usage
|
|
392
676
|
- `dist/vibeui.d.ts` — TypeScript declarations
|
|
393
677
|
|
|
394
|
-
Vue and Bootstrap are **external** — not bundled. Consumers provide their own.
|
|
678
|
+
Vue and Bootstrap are **external** — not bundled. Consumers provide their own. `@floating-ui/dom` is a runtime dependency (used by `usePosition`).
|
|
679
|
+
|
|
680
|
+
### Smoke testing
|
|
681
|
+
|
|
682
|
+
```bash
|
|
683
|
+
npm run smoke # rebuilds the lib + serves smoke/ on :8001
|
|
684
|
+
```
|
|
685
|
+
|
|
686
|
+
`smoke/index.html` mounts every component with realistic data and a status badge for runtime errors. Bootstrap, Quill, and Vue are loaded from CDN via an importmap (Bootstrap and Quill via `esm.sh` so transitive deps like `@popperjs/core` resolve automatically).
|
|
395
687
|
|
|
396
688
|
---
|
|
397
689
|
|
|
@@ -409,7 +701,45 @@ If the component uses Bootstrap JS:
|
|
|
409
701
|
- Dynamically import: `const { Foo } = await import('bootstrap')`
|
|
410
702
|
- Initialize in `onMounted`, dispose in `onBeforeUnmount`
|
|
411
703
|
- Watch functional props and call `instance.dispose()` + reinitialize on change
|
|
412
|
-
- Expose `
|
|
704
|
+
- Expose safe imperative methods (`show()` / `hide()` / `refresh()`) via `defineExpose`. Follow the existing convention of also exposing the raw instance only under the `_unsafe_bsInstance` name (escape hatch — never a plain `bsInstance`)
|
|
705
|
+
|
|
706
|
+
---
|
|
707
|
+
|
|
708
|
+
## Canvas Charts
|
|
709
|
+
|
|
710
|
+
Three chart components drawn directly on `<canvas>` — no Chart.js or other dependency.
|
|
711
|
+
|
|
712
|
+
```vue
|
|
713
|
+
<VibeChartLine :data="data" smooth fill legend="top" />
|
|
714
|
+
<VibeChartBar :data="data" stacked />
|
|
715
|
+
<VibeChartPie :data="data" />
|
|
716
|
+
```
|
|
717
|
+
|
|
718
|
+
All three share the same `ChartData` shape:
|
|
719
|
+
|
|
720
|
+
```ts
|
|
721
|
+
const data: ChartData = {
|
|
722
|
+
labels: ['Jan', 'Feb', 'Mar'],
|
|
723
|
+
datasets: [
|
|
724
|
+
{ label: 'Revenue', data: [100, 150, 130], color: '#0d6efd' } // color optional
|
|
725
|
+
]
|
|
726
|
+
}
|
|
727
|
+
```
|
|
728
|
+
|
|
729
|
+
When `color` is omitted, colors cycle through Bootstrap CSS variables (`--bs-primary`, `--bs-success`, `--bs-danger`, ...) from the component's computed style — automatically matching your Bootstrap theme and dark mode.
|
|
730
|
+
|
|
731
|
+
| Prop | Line | Bar | Pie | Description |
|
|
732
|
+
|------|------|-----|-----|-------------|
|
|
733
|
+
| `data` | ✓ | ✓ | ✓ | `ChartData` — required |
|
|
734
|
+
| `legend` | ✓ | ✓ | ✓ | `'top' \| 'bottom' \| 'none'` (default `'bottom'`) |
|
|
735
|
+
| `height` | ✓ | ✓ | ✓ | Number/String px or `'auto'` (default). Line/Bar → 16:9, Pie → 1:1 |
|
|
736
|
+
| `showAxes` | ✓ | ✓ | — | Show X/Y axes (default `true`) |
|
|
737
|
+
| `showGrid` | ✓ | ✓ | — | Show grid lines (default `true`) |
|
|
738
|
+
| `smooth` | ✓ | — | — | Bezier curves instead of straight lines |
|
|
739
|
+
| `fill` | ✓ | — | — | Fill area under line |
|
|
740
|
+
| `stacked` | — | ✓ | — | Stack datasets instead of grouping |
|
|
741
|
+
|
|
742
|
+
All charts are responsive via `ResizeObserver`, render at device pixel ratio for crisp HiDPI output, and show hover tooltips on data points/slices/bars.
|
|
413
743
|
|
|
414
744
|
---
|
|
415
745
|
|
|
@@ -420,3 +750,33 @@ If the component uses Bootstrap JS:
|
|
|
420
750
|
- Does not require Vue Router (optional peer dep for `href`/`to` props on `VibeButton`)
|
|
421
751
|
- Does not require QuillJS (optional peer dep for `VibeFormWysiwyg`)
|
|
422
752
|
- Does not provide a theme system beyond Bootstrap's `data-bs-theme` color modes
|
|
753
|
+
|
|
754
|
+
## Documentation Index
|
|
755
|
+
|
|
756
|
+
Per-component and per-API reference. **Read the relevant page before building with a component.**
|
|
757
|
+
|
|
758
|
+
**Start here:** [docs/README.md](docs/README.md) · [Getting started / starter template](docs/getting-started/starter-template.md) · [Versioning & stability policy](docs/versioning.md)
|
|
759
|
+
|
|
760
|
+
**Layout:** [VibeContainer](docs/components/layout/container.md) · [VibeRow](docs/components/layout/row.md) · [VibeCol](docs/components/layout/col.md)
|
|
761
|
+
|
|
762
|
+
**Core:** [VibeAlert](docs/components/core/alert.md) · [VibeBadge](docs/components/core/badge.md) · [VibeButton](docs/components/core/button.md) · [VibeButtonGroup](docs/components/core/button-group.md) · [VibeCloseButton](docs/components/core/close-button.md) · [VibeLink](docs/components/core/link.md) · [VibePlaceholder](docs/components/core/placeholder.md) · [VibeSkeleton](docs/components/core/skeleton.md) · [VibeSpinner](docs/components/core/spinner.md)
|
|
763
|
+
|
|
764
|
+
**Card / Hero / List:** [VibeCard](docs/components/card/card.md) · [VibeHero](docs/components/hero/hero.md) · [VibeListGroup](docs/components/list/list-group.md)
|
|
765
|
+
|
|
766
|
+
**Navigation:** [VibeBreadcrumb](docs/components/navigation/breadcrumb.md) · [VibeNav](docs/components/navigation/nav.md) · [VibeNavbar](docs/components/navigation/navbar.md) · [VibePagination](docs/components/navigation/pagination.md)
|
|
767
|
+
|
|
768
|
+
**Interactive:** [VibeAccordion](docs/components/interactive/accordion.md) · [VibeCarousel](docs/components/interactive/carousel.md) · [VibeCollapse](docs/components/interactive/collapse.md) · [VibeDatePicker](docs/components/interactive/date-picker.md) · [VibeDraggable / VibeDroppable](docs/components/interactive/draggable.md) · [VibeDropdown](docs/components/interactive/dropdown.md) · [VibeModal](docs/components/interactive/modal.md) · [VibeOffcanvas](docs/components/interactive/offcanvas.md) · [VibeResizable](docs/components/interactive/resizable.md) · [VibeSlider](docs/components/interactive/slider.md) · [VibeSortable](docs/components/interactive/sortable.md) · [VibeStepper](docs/components/interactive/stepper.md) · [VibeTabs / VibeTab](docs/components/interactive/tabs.md) · [VibeToast](docs/components/interactive/toast.md)
|
|
769
|
+
|
|
770
|
+
**Advanced:** [VibePopover](docs/components/advanced/popover.md) · [VibeScrollspy](docs/components/advanced/scrollspy.md) · [VibeTooltip](docs/components/advanced/tooltip.md)
|
|
771
|
+
|
|
772
|
+
**Data & Charts:** [VibeDataTable](docs/components/data/datatable.md) · [VibeChartBar](docs/components/charts/chart-bar.md) · [VibeChartLine](docs/components/charts/chart-line.md) · [VibeChartPie](docs/components/charts/chart-pie.md)
|
|
773
|
+
|
|
774
|
+
**Progress:** [VibeProgress](docs/components/progress/progress.md)
|
|
775
|
+
|
|
776
|
+
**Forms:** [overview](docs/forms/README.md) · [VibeAutocomplete](docs/forms/autocomplete.md) · [VibeFileInput](docs/forms/file-input.md) · [VibeFormCheckbox](docs/forms/form-checkbox.md) · [VibeFormDatepicker](docs/forms/form-datepicker.md) · [VibeFormGroup](docs/forms/form-group.md) · [VibeFormInput](docs/forms/form-input.md) · [VibeFormRadio](docs/forms/form-radio.md) · [VibeFormSelect](docs/forms/form-select.md) · [VibeFormSpinbutton](docs/forms/form-spinbutton.md) · [VibeFormSwitch](docs/forms/form-switch.md) · [VibeFormTextarea](docs/forms/form-textarea.md) · [VibeFormWysiwyg](docs/forms/form-wysiwyg.md) · [VibeInputGroup](docs/forms/input-group.md) · [Validation & useForm](docs/forms/validation.md)
|
|
777
|
+
|
|
778
|
+
**Composables:** [useBackButton](docs/composables/back-button.md) · [useBreakpoints](docs/composables/breakpoints.md) · [useColorMode](docs/composables/color-mode.md) · [useForm](docs/composables/use-form.md) · [usePosition](docs/composables/use-position.md) · [useToast](docs/composables/use-toast.md)
|
|
779
|
+
|
|
780
|
+
**Directives:** [v-vibe-tooltip](docs/directives/v-tooltip.md)
|
|
781
|
+
|
|
782
|
+
**Utilities:** [Position utility classes](docs/utilities/position.md)
|