@velkymx/vibeui 0.9.0 → 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/CLAUDE.md +48 -0
- package/README.md +222 -197
- 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 +18 -34
- 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 +13 -17
- 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/{components → src/components}/VibeDatePicker.vue.d.ts +4 -6
- package/dist/{components → src/components}/VibeDraggable.vue.d.ts +9 -13
- package/dist/{components → src/components}/VibeDropdown.vue.d.ts +46 -43
- package/dist/{components → src/components}/VibeDroppable.vue.d.ts +9 -13
- package/dist/{components → src/components}/VibeFileInput.vue.d.ts +14 -20
- package/dist/{components → src/components}/VibeFormCheckbox.vue.d.ts +29 -21
- package/dist/{components → src/components}/VibeFormDatepicker.vue.d.ts +26 -29
- package/dist/{components → src/components}/VibeFormGroup.vue.d.ts +10 -13
- package/dist/{components → src/components}/VibeFormInput.vue.d.ts +22 -23
- package/dist/{components → src/components}/VibeFormRadio.vue.d.ts +22 -23
- package/dist/{components → src/components}/VibeFormSelect.vue.d.ts +27 -33
- package/dist/{components → src/components}/VibeFormSpinbutton.vue.d.ts +30 -33
- package/dist/{components → src/components}/VibeFormSwitch.vue.d.ts +21 -22
- package/dist/{components → src/components}/VibeFormTextarea.vue.d.ts +23 -24
- package/dist/{components → src/components}/VibeFormWysiwyg.vue.d.ts +22 -21
- 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/{components → src/components}/VibeResizable.vue.d.ts +10 -14
- package/dist/{components → src/components}/VibeRow.vue.d.ts +9 -17
- package/dist/src/components/VibeScrollspy.vue.d.ts +89 -0
- package/dist/{components → src/components}/VibeSkeleton.vue.d.ts +2 -1
- package/dist/{components → src/components}/VibeSlider.vue.d.ts +4 -5
- package/dist/src/components/VibeSortable.vue.d.ts +59 -0
- package/dist/{components → src/components}/VibeSpinner.vue.d.ts +4 -7
- package/dist/{components → src/components}/VibeStepper.vue.d.ts +32 -31
- package/dist/{components → src/components}/VibeTab.vue.d.ts +7 -11
- package/dist/src/components/VibeTabContent.vue.d.ts +56 -0
- package/dist/{components → src/components}/VibeTabs.vue.d.ts +9 -13
- package/dist/{components → src/components}/VibeToast.vue.d.ts +31 -44
- package/dist/{components → src/components}/VibeToastHost.vue.d.ts +2 -1
- 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/{components → src/components}/dndStore.d.ts +1 -0
- package/dist/{components → src/components}/index.d.ts +5 -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/useId.d.ts +2 -0
- package/dist/{directives → src/directives}/vTooltip.d.ts +2 -3
- package/dist/src/injectionKeys.d.ts +28 -0
- package/dist/{types.d.ts → src/types.d.ts} +21 -2
- 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 +8269 -5855
- package/dist/vibeui.umd.js +3 -1
- package/docs/README.md +225 -0
- package/docs/components/advanced/popover.md +125 -0
- package/docs/components/advanced/scrollspy.md +106 -0
- package/docs/components/advanced/tooltip.md +90 -0
- package/docs/components/card/card.md +223 -0
- 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 +94 -0
- package/docs/components/core/badge.md +75 -0
- package/docs/components/core/button-group.md +99 -0
- package/docs/components/core/button.md +127 -0
- package/docs/components/core/close-button.md +82 -0
- package/docs/components/core/link.md +79 -0
- package/docs/components/core/placeholder.md +129 -0
- package/docs/components/core/skeleton.md +40 -0
- package/docs/components/core/spinner.md +103 -0
- package/docs/components/data/datatable.md +435 -0
- package/docs/components/hero/hero.md +64 -0
- package/docs/components/interactive/accordion.md +121 -0
- package/docs/components/interactive/carousel.md +112 -0
- package/docs/components/interactive/collapse.md +106 -0
- package/docs/components/interactive/date-picker.md +78 -0
- package/docs/components/interactive/draggable.md +91 -0
- package/docs/components/interactive/dropdown.md +129 -0
- package/docs/components/interactive/modal.md +143 -0
- package/docs/components/interactive/offcanvas.md +92 -0
- 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 +177 -0
- package/docs/components/layout/col.md +117 -0
- package/docs/components/layout/container.md +53 -0
- package/docs/components/layout/row.md +107 -0
- package/docs/components/list/list-group.md +225 -0
- package/docs/components/navigation/breadcrumb.md +120 -0
- package/docs/components/navigation/nav.md +151 -0
- package/docs/components/navigation/navbar.md +108 -0
- package/docs/components/navigation/pagination.md +162 -0
- package/docs/components/progress/progress.md +188 -0
- package/docs/composables/back-button.md +28 -0
- package/docs/composables/breakpoints.md +54 -0
- package/docs/composables/color-mode.md +179 -0
- 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 +87 -0
- package/docs/forms/autocomplete.md +96 -0
- package/docs/forms/file-input.md +97 -0
- package/docs/forms/form-checkbox.md +100 -0
- package/docs/forms/form-datepicker.md +80 -0
- package/docs/forms/form-group.md +115 -0
- package/docs/forms/form-input.md +112 -0
- package/docs/forms/form-radio.md +82 -0
- package/docs/forms/form-select.md +98 -0
- package/docs/forms/form-spinbutton.md +94 -0
- package/docs/forms/form-switch.md +75 -0
- package/docs/forms/form-textarea.md +82 -0
- package/docs/forms/form-wysiwyg.md +99 -0
- package/docs/forms/input-group.md +70 -0
- package/docs/forms/validation.md +213 -0
- 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 +782 -0
- package/package.json +44 -14
- 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/VibeAutocomplete.vue.d.ts +0 -46
- 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/VibeSortable.vue.d.ts +0 -40
- 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}/useForm.d.ts +0 -0
- /package/dist/{composables → src/composables}/useFormValidation.d.ts +0 -0
- /package/dist/{composables → src/composables}/usePosition.d.ts +0 -0
- /package/dist/{composables → src/composables}/useToast.d.ts +0 -0
- /package/dist/{index.d.ts → src/index.d.ts} +0 -0
- /package/dist/{main.d.ts → src/main.d.ts} +0 -0
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
# VibeModal
|
|
2
|
+
|
|
3
|
+
Modal dialogs for lightboxes, user notifications, or custom content.
|
|
4
|
+
|
|
5
|
+
## Props
|
|
6
|
+
|
|
7
|
+
| Prop | Type | Default | Description |
|
|
8
|
+
|------|------|---------|-------------|
|
|
9
|
+
| `id` | `String` | `Auto-generated` | Unique identifier for the modal |
|
|
10
|
+
| `modelValue` | `Boolean` | `false` | Control visibility (v-model) |
|
|
11
|
+
| `title` | `String` | `''` | Modal title |
|
|
12
|
+
| `size` | `Size\|'xl'` | `undefined` | Modal size: `'sm'`, `'lg'`, `'xl'` |
|
|
13
|
+
| `centered` | `Boolean` | `false` | Vertically center modal |
|
|
14
|
+
| `scrollable` | `Boolean` | `false` | Scrollable modal body |
|
|
15
|
+
| `fullscreen` | `Boolean\|String` | `false` | Fullscreen: `true` or breakpoint |
|
|
16
|
+
| `staticBackdrop` | `Boolean` | `false` | Don't close on backdrop click |
|
|
17
|
+
| `hideHeader` | `Boolean` | `false` | Hide header section |
|
|
18
|
+
| `hideFooter` | `Boolean` | `false` | Hide footer section |
|
|
19
|
+
| `teleport` | `Boolean\|String` | `'body'` | Destination for Vue Teleport |
|
|
20
|
+
|
|
21
|
+
## Events
|
|
22
|
+
|
|
23
|
+
| Event | Payload | Description |
|
|
24
|
+
|-------|---------|-------------|
|
|
25
|
+
| `update:modelValue` | `Boolean` | Emitted when modal visibility changes |
|
|
26
|
+
| `show` | - | Emitted when modal starts showing |
|
|
27
|
+
| `shown` | - | Emitted when modal is fully shown |
|
|
28
|
+
| `hide` | - | Emitted when modal starts hiding |
|
|
29
|
+
| `hidden` | - | Emitted when modal is fully hidden |
|
|
30
|
+
| `component-error` | `ComponentError` | Emitted if Bootstrap JS fails to load |
|
|
31
|
+
|
|
32
|
+
## Slots
|
|
33
|
+
|
|
34
|
+
| Slot | Description |
|
|
35
|
+
|------|-------------|
|
|
36
|
+
| `default` | Modal body content |
|
|
37
|
+
| `header` | Custom header content |
|
|
38
|
+
| `footer` | Custom footer content |
|
|
39
|
+
|
|
40
|
+
## Usage
|
|
41
|
+
|
|
42
|
+
### Reactive Usage (v-model)
|
|
43
|
+
|
|
44
|
+
```vue
|
|
45
|
+
<template>
|
|
46
|
+
<div>
|
|
47
|
+
<VibeButton variant="primary" @click="showModal = true">
|
|
48
|
+
Open Modal
|
|
49
|
+
</VibeButton>
|
|
50
|
+
|
|
51
|
+
<VibeModal v-model="showModal" title="Reactive Modal">
|
|
52
|
+
<p>This modal is controlled via Vue state.</p>
|
|
53
|
+
</VibeModal>
|
|
54
|
+
</div>
|
|
55
|
+
</template>
|
|
56
|
+
|
|
57
|
+
<script setup>
|
|
58
|
+
import { ref } from 'vue'
|
|
59
|
+
const showModal = ref(false)
|
|
60
|
+
</script>
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### Sized Modals
|
|
64
|
+
|
|
65
|
+
```vue
|
|
66
|
+
<template>
|
|
67
|
+
<div>
|
|
68
|
+
<VibeModal title="Small Modal" size="sm">
|
|
69
|
+
Small modal content
|
|
70
|
+
</VibeModal>
|
|
71
|
+
|
|
72
|
+
<VibeModal title="Large Modal" size="lg">
|
|
73
|
+
Large modal content
|
|
74
|
+
</VibeModal>
|
|
75
|
+
</div>
|
|
76
|
+
</template>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Centered Modal
|
|
80
|
+
|
|
81
|
+
```vue
|
|
82
|
+
<template>
|
|
83
|
+
<VibeModal title="Centered Modal" centered>
|
|
84
|
+
This modal is vertically centered.
|
|
85
|
+
</VibeModal>
|
|
86
|
+
</template>
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Custom Footer
|
|
90
|
+
|
|
91
|
+
```vue
|
|
92
|
+
<template>
|
|
93
|
+
<VibeModal v-model="showModal" title="Custom Footer">
|
|
94
|
+
<p>Modal with custom footer buttons.</p>
|
|
95
|
+
|
|
96
|
+
<template #footer>
|
|
97
|
+
<VibeButton variant="secondary" @click="showModal = false">Close</VibeButton>
|
|
98
|
+
<VibeButton variant="primary" @click="save">Save changes</VibeButton>
|
|
99
|
+
</template>
|
|
100
|
+
</VibeModal>
|
|
101
|
+
</template>
|
|
102
|
+
|
|
103
|
+
<script setup>
|
|
104
|
+
import { ref } from 'vue'
|
|
105
|
+
const showModal = ref(true)
|
|
106
|
+
function save() {
|
|
107
|
+
// persist changes...
|
|
108
|
+
showModal.value = false
|
|
109
|
+
}
|
|
110
|
+
</script>
|
|
111
|
+
```
|
|
112
|
+
|
|
113
|
+
## Important Notes
|
|
114
|
+
|
|
115
|
+
**Automatic Initialization:** This component automatically initializes Bootstrap's Modal functionality when it is mounted, provided that Bootstrap's JavaScript is available in your project.
|
|
116
|
+
|
|
117
|
+
**Teleportation:** By default, this component teleports its DOM elements to the `<body>` to avoid stacking context issues. You can customize this with the `teleport` prop.
|
|
118
|
+
|
|
119
|
+
**Focus Return (WCAG 2.4.3):** When the modal closes, focus is automatically returned to the element that opened it, including for programmatically opened modals.
|
|
120
|
+
|
|
121
|
+
**Escape Hatch:** The exposed `_unsafe_bsInstance` template ref gives raw access to the underlying Bootstrap Modal instance. It is **not** part of the stable API — calling `dispose()` or other lifecycle methods on it directly **will** break the component. Prefer `v-model` and the exposed `show()` / `hide()` methods.
|
|
122
|
+
|
|
123
|
+
## Mobile Optimization
|
|
124
|
+
|
|
125
|
+
**Safe Areas:** In fullscreen mode, the modal header and footer automatically respect device safe areas (notches) in hybrid apps.
|
|
126
|
+
|
|
127
|
+
**Hardware Back Button:** On Android devices in hybrid environments, the hardware back button will automatically close the modal if it is open.
|
|
128
|
+
|
|
129
|
+
**Dynamic Height:** Fullscreen modals use `dvh` (dynamic viewport height) units to ensure they occupy the full screen height even when mobile browser bars are visible.
|
|
130
|
+
|
|
131
|
+
## Bootstrap CSS Classes
|
|
132
|
+
|
|
133
|
+
- `.modal`
|
|
134
|
+
- `.modal-dialog`
|
|
135
|
+
- `.modal-content`
|
|
136
|
+
- `.modal-header`
|
|
137
|
+
- `.modal-title`
|
|
138
|
+
- `.modal-body`
|
|
139
|
+
- `.modal-footer`
|
|
140
|
+
- `.modal-{size}`
|
|
141
|
+
- `.modal-dialog-centered`
|
|
142
|
+
- `.modal-dialog-scrollable`
|
|
143
|
+
- `.modal-fullscreen`
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
# VibeOffcanvas
|
|
2
|
+
|
|
3
|
+
Hidden sidebar for navigation or additional content.
|
|
4
|
+
|
|
5
|
+
## Props
|
|
6
|
+
|
|
7
|
+
| Prop | Type | Default | Description |
|
|
8
|
+
|------|------|---------|-------------|
|
|
9
|
+
| `id` | `String` | `Auto-generated` | Unique identifier |
|
|
10
|
+
| `modelValue` | `Boolean` | `false` | Control visibility (v-model) |
|
|
11
|
+
| `title` | `String` | `''` | Offcanvas title |
|
|
12
|
+
| `placement` | `OffcanvasPlacement` | `'start'` | Placement: `'start'`, `'end'`, `'top'`, `'bottom'` |
|
|
13
|
+
| `backdrop` | `Boolean\|String` | `true` | Backdrop: `true`, `false`, or `'static'` |
|
|
14
|
+
| `scroll` | `Boolean` | `false` | Allow body scrolling |
|
|
15
|
+
| `teleport` | `Boolean\|String` | `'body'` | Destination for Vue Teleport |
|
|
16
|
+
|
|
17
|
+
## Events
|
|
18
|
+
|
|
19
|
+
| Event | Payload | Description |
|
|
20
|
+
|-------|---------|-------------|
|
|
21
|
+
| `update:modelValue` | `Boolean` | Emitted when visibility changes |
|
|
22
|
+
| `show` | - | Emitted when offcanvas starts showing |
|
|
23
|
+
| `shown` | - | Emitted when offcanvas is fully shown |
|
|
24
|
+
| `hide` | - | Emitted when offcanvas starts hiding |
|
|
25
|
+
| `hidden` | - | Emitted when offcanvas is fully hidden |
|
|
26
|
+
| `component-error` | `ComponentError` | Emitted if Bootstrap JS fails to load |
|
|
27
|
+
|
|
28
|
+
## Slots
|
|
29
|
+
|
|
30
|
+
| Slot | Description |
|
|
31
|
+
|------|-------------|
|
|
32
|
+
| `default` | Offcanvas body content |
|
|
33
|
+
| `header` | Custom header content |
|
|
34
|
+
|
|
35
|
+
## Usage
|
|
36
|
+
|
|
37
|
+
### Reactive Usage (v-model)
|
|
38
|
+
|
|
39
|
+
```vue
|
|
40
|
+
<template>
|
|
41
|
+
<div>
|
|
42
|
+
<VibeButton variant="primary" @click="showOffcanvas = true">
|
|
43
|
+
Open Offcanvas
|
|
44
|
+
</VibeButton>
|
|
45
|
+
|
|
46
|
+
<VibeOffcanvas v-model="showOffcanvas" title="Reactive Offcanvas">
|
|
47
|
+
This offcanvas is controlled via Vue state.
|
|
48
|
+
</VibeOffcanvas>
|
|
49
|
+
</div>
|
|
50
|
+
</template>
|
|
51
|
+
|
|
52
|
+
<script setup>
|
|
53
|
+
import { ref } from 'vue'
|
|
54
|
+
const showOffcanvas = ref(false)
|
|
55
|
+
</script>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Placement Options
|
|
59
|
+
|
|
60
|
+
```vue
|
|
61
|
+
<template>
|
|
62
|
+
<VibeOffcanvas title="Right Side" placement="end">
|
|
63
|
+
Content on the right
|
|
64
|
+
</VibeOffcanvas>
|
|
65
|
+
</template>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Important Notes
|
|
69
|
+
|
|
70
|
+
**Automatic Initialization:** This component automatically initializes Bootstrap's Offcanvas functionality when it is mounted, provided that Bootstrap's JavaScript is available in your project.
|
|
71
|
+
|
|
72
|
+
**Teleportation:** By default, this component teleports its DOM elements to the `<body>` to avoid stacking context issues. You can customize this with the `teleport` prop.
|
|
73
|
+
|
|
74
|
+
**Focus Return (WCAG 2.4.3):** When the offcanvas closes, focus is automatically returned to the element that opened it, including for programmatically opened panels.
|
|
75
|
+
|
|
76
|
+
**Escape Hatch:** The exposed `_unsafe_bsInstance` template ref gives raw access to the underlying Bootstrap Offcanvas instance. It is **not** part of the stable API — calling `dispose()` or other lifecycle methods on it directly **will** break the component. Prefer `v-model` and the exposed `show()` / `hide()` methods.
|
|
77
|
+
|
|
78
|
+
## Mobile Optimization
|
|
79
|
+
|
|
80
|
+
**Safe Areas:** When used in hybrid apps with `viewport-fit=cover`, the offcanvas header automatically adds padding to account for device notches.
|
|
81
|
+
|
|
82
|
+
**Hardware Back Button:** On Android devices in hybrid environments, the hardware back button will automatically close the offcanvas if it is open.
|
|
83
|
+
|
|
84
|
+
**Dynamic Height:** The offcanvas uses `dvh` (dynamic viewport height) units to ensure it occupies the full screen height even when mobile browser bars are visible.
|
|
85
|
+
|
|
86
|
+
## Bootstrap CSS Classes
|
|
87
|
+
|
|
88
|
+
- `.offcanvas`
|
|
89
|
+
- `.offcanvas-{placement}`
|
|
90
|
+
- `.offcanvas-header`
|
|
91
|
+
- `.offcanvas-title`
|
|
92
|
+
- `.offcanvas-body`
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# VibeResizable
|
|
2
|
+
|
|
3
|
+
Wrap a child element with up to 8 directional handles for user-driven resizing. Useful for dashboard panels, image crops, draggable widgets.
|
|
4
|
+
|
|
5
|
+
## Props
|
|
6
|
+
|
|
7
|
+
| Prop | Type | Default | Description |
|
|
8
|
+
|------|------|---------|-------------|
|
|
9
|
+
| `handles` | `Handle[]` | `['se']` | Subset of `'n' \| 's' \| 'e' \| 'w' \| 'ne' \| 'nw' \| 'se' \| 'sw'` |
|
|
10
|
+
| `width` | `Number` | `200` | Initial width in px (use `update:width` v-model) |
|
|
11
|
+
| `height` | `Number` | `150` | Initial height in px (use `update:height` v-model) |
|
|
12
|
+
| `minWidth` | `Number` | `20` | |
|
|
13
|
+
| `maxWidth` | `Number` | `Infinity` | |
|
|
14
|
+
| `minHeight` | `Number` | `20` | |
|
|
15
|
+
| `maxHeight` | `Number` | `Infinity` | |
|
|
16
|
+
| `aspectRatio` | `Number` | `undefined` | Lock width/height ratio (e.g. `16/9`) |
|
|
17
|
+
| `grid` | `Number` | `1` | Snap step in px |
|
|
18
|
+
| `disabled` | `Boolean` | `false` | Hide handles, ignore drags |
|
|
19
|
+
|
|
20
|
+
### Events
|
|
21
|
+
|
|
22
|
+
| Event | Payload | Description |
|
|
23
|
+
|-------|---------|-------------|
|
|
24
|
+
| `update:width` | `Number` | New width (use with `v-model:width`) |
|
|
25
|
+
| `update:height` | `Number` | New height |
|
|
26
|
+
| `resizestart` | `{ width, height }` | Drag began |
|
|
27
|
+
| `resize` | `{ width, height, handle }` | Continuous during drag |
|
|
28
|
+
| `resizeend` | `{ width, height }` | Drag committed |
|
|
29
|
+
|
|
30
|
+
## Examples
|
|
31
|
+
|
|
32
|
+
### Resizable card
|
|
33
|
+
|
|
34
|
+
```vue
|
|
35
|
+
<script setup>
|
|
36
|
+
import { ref } from 'vue'
|
|
37
|
+
const w = ref(320)
|
|
38
|
+
const h = ref(200)
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<template>
|
|
42
|
+
<VibeResizable
|
|
43
|
+
v-model:width="w"
|
|
44
|
+
v-model:height="h"
|
|
45
|
+
:handles="['se', 's', 'e']"
|
|
46
|
+
:grid="10"
|
|
47
|
+
:min-width="160"
|
|
48
|
+
>
|
|
49
|
+
<div class="card h-100">
|
|
50
|
+
<div class="card-body">
|
|
51
|
+
Content reflows: {{ w }}×{{ h }}
|
|
52
|
+
</div>
|
|
53
|
+
</div>
|
|
54
|
+
</VibeResizable>
|
|
55
|
+
</template>
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
## Layout caveat
|
|
59
|
+
|
|
60
|
+
Handles are positioned just outside the box (negative top/right/bottom/left) so they sit *on* the edge for easier grabbing. If the resizable lives inside a parent with `overflow: hidden`, or sits at the viewport edge, the handles may clip. Either lift `overflow` from the parent or wrap the resizable in extra padding.
|
|
61
|
+
|
|
62
|
+
### Aspect-locked image preview
|
|
63
|
+
|
|
64
|
+
```vue
|
|
65
|
+
<VibeResizable
|
|
66
|
+
v-model:width="w"
|
|
67
|
+
v-model:height="h"
|
|
68
|
+
:aspect-ratio="16/9"
|
|
69
|
+
:handles="['nw', 'ne', 'sw', 'se']"
|
|
70
|
+
>
|
|
71
|
+
<img :src="src" class="w-100 h-100" />
|
|
72
|
+
</VibeResizable>
|
|
73
|
+
```
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# VibeSlider
|
|
2
|
+
|
|
3
|
+
Cross-browser range slider with consistent look and full keyboard support. Single mode binds a number; range mode binds `[low, high]` with handles that cannot cross.
|
|
4
|
+
|
|
5
|
+
## Props
|
|
6
|
+
|
|
7
|
+
| Prop | Type | Default | Description |
|
|
8
|
+
|------|------|---------|-------------|
|
|
9
|
+
| `modelValue` | `Number \| [Number, Number]` | `0` | Slider value (v-model) |
|
|
10
|
+
| `min` | `Number` | `0` | |
|
|
11
|
+
| `max` | `Number` | `100` | |
|
|
12
|
+
| `step` | `Number` | `1` | Snap step |
|
|
13
|
+
| `range` | `Boolean` | `false` | Two-handle range mode |
|
|
14
|
+
| `vertical` | `Boolean` | `false` | Vertical orientation |
|
|
15
|
+
| `disabled` | `Boolean` | `false` | |
|
|
16
|
+
|
|
17
|
+
### Events
|
|
18
|
+
|
|
19
|
+
| Event | Payload | Description |
|
|
20
|
+
|-------|---------|-------------|
|
|
21
|
+
| `update:modelValue` | `Number \| [Number, Number]` | New value |
|
|
22
|
+
| `change` | Same | Alias |
|
|
23
|
+
|
|
24
|
+
## Keyboard
|
|
25
|
+
|
|
26
|
+
| Key | Action |
|
|
27
|
+
|-----|--------|
|
|
28
|
+
| `ArrowRight` / `ArrowUp` | +1 step |
|
|
29
|
+
| `ArrowLeft` / `ArrowDown` | –1 step |
|
|
30
|
+
| `Home` | Jump to `min` |
|
|
31
|
+
| `End` | Jump to `max` |
|
|
32
|
+
| `PageUp` | +10 steps |
|
|
33
|
+
| `PageDown` | –10 steps |
|
|
34
|
+
|
|
35
|
+
## Examples
|
|
36
|
+
|
|
37
|
+
### Single value
|
|
38
|
+
|
|
39
|
+
```vue
|
|
40
|
+
<VibeSlider v-model="volume" :min="0" :max="100" :step="5" />
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
### Range
|
|
44
|
+
|
|
45
|
+
```vue
|
|
46
|
+
<VibeSlider v-model="priceRange" range :min="0" :max="500" />
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
### Vertical
|
|
50
|
+
|
|
51
|
+
```vue
|
|
52
|
+
<VibeSlider v-model="value" vertical />
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
## Accessibility
|
|
56
|
+
|
|
57
|
+
Each handle has `role="slider"`, `aria-valuemin`, `aria-valuemax`, `aria-valuenow`, and `tabindex="0"`. Disabled state sets `aria-disabled="true"`.
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
# VibeSortable
|
|
2
|
+
|
|
3
|
+
Drag-and-drop reorderable list. Generic over the row type; binds an ordered array via `v-model`.
|
|
4
|
+
|
|
5
|
+
## Props
|
|
6
|
+
|
|
7
|
+
| Prop | Type | Default | Description |
|
|
8
|
+
|------|------|---------|-------------|
|
|
9
|
+
| `modelValue` | `T[]` | required | Ordered array (v-model) |
|
|
10
|
+
| `itemKey` | `String` | `undefined` | Property name on each item to use as the `:key`. When omitted, index is used as key. Set this when items have a stable unique identifier to avoid key conflicts during reorder. |
|
|
11
|
+
| `disabled` | `Boolean` | `false` | Disable dragging |
|
|
12
|
+
| `tag` | `String` | `'div'` | Container element |
|
|
13
|
+
| `itemTag` | `String` | `'div'` | Element wrapping each item |
|
|
14
|
+
|
|
15
|
+
### Events
|
|
16
|
+
|
|
17
|
+
| Event | Payload | Description |
|
|
18
|
+
|-------|---------|-------------|
|
|
19
|
+
| `update:modelValue` | `T[]` | New ordered array after a successful drop |
|
|
20
|
+
| `reorder` | `{ from, to, item }` | Convenience event for persisting moves |
|
|
21
|
+
|
|
22
|
+
### Slots
|
|
23
|
+
|
|
24
|
+
The default slot is scoped per item with `{ item, index }`.
|
|
25
|
+
|
|
26
|
+
## Examples
|
|
27
|
+
|
|
28
|
+
```vue
|
|
29
|
+
<script setup>
|
|
30
|
+
import { ref } from 'vue'
|
|
31
|
+
const tasks = ref(['Wireframes', 'Backend', 'QA', 'Launch'])
|
|
32
|
+
</script>
|
|
33
|
+
|
|
34
|
+
<template>
|
|
35
|
+
<VibeSortable v-model="tasks">
|
|
36
|
+
<template #default="{ item, index }">
|
|
37
|
+
<div class="card p-2 mb-2">
|
|
38
|
+
{{ index + 1 }}. {{ item }}
|
|
39
|
+
</div>
|
|
40
|
+
</template>
|
|
41
|
+
</VibeSortable>
|
|
42
|
+
</template>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Items get `data-vibe-sortable-item` for testability and styling. The currently dragging item gets a `vibe-sortable-dragging` class.
|
|
46
|
+
|
|
47
|
+
## When to use VibeSortable vs VibeDraggable
|
|
48
|
+
|
|
49
|
+
- **VibeSortable**: a single ordered list whose only operation is reorder.
|
|
50
|
+
- **VibeDraggable + VibeDroppable**: cross-list moves, kanban boards, builders, anywhere the source and target are different containers.
|
|
51
|
+
|
|
52
|
+
> **Scope:** VibeSortable handles in-list reorder only. Cross-list moves between two `<VibeSortable>` instances are not supported — use `VibeDraggable` + `VibeDroppable` for that.
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
# VibeStepper
|
|
2
|
+
|
|
3
|
+
Multi-step wizard with linear / non-linear modes and per-step validation guards. Use for sprint setup, initiative gates, onboarding flows.
|
|
4
|
+
|
|
5
|
+
## Props
|
|
6
|
+
|
|
7
|
+
| Prop | Type | Default | Description |
|
|
8
|
+
|------|------|---------|-------------|
|
|
9
|
+
| `modelValue` | `Number` | `0` | Active step index (v-model) |
|
|
10
|
+
| `steps` | `StepperStep[]` | required | Step descriptors (see below) |
|
|
11
|
+
| `linear` | `Boolean` | `true` | Forbid clicking ahead of current step |
|
|
12
|
+
| `vertical` | `Boolean` | `false` | Vertical layout |
|
|
13
|
+
| `beforeNext` | `(currentIndex, 'next') => boolean \| Promise<boolean>` | `undefined` | Guard for advancing |
|
|
14
|
+
| `beforePrev` | `(currentIndex, 'prev') => boolean \| Promise<boolean>` | `undefined` | Guard for going back |
|
|
15
|
+
| `nextText` | `String` | `'Next'` | Default action button label |
|
|
16
|
+
| `prevText` | `String` | `'Back'` | |
|
|
17
|
+
| `finishText` | `String` | `'Finish'` | Replaces `nextText` on the last step |
|
|
18
|
+
|
|
19
|
+
### Step descriptor
|
|
20
|
+
|
|
21
|
+
```ts
|
|
22
|
+
interface StepperStep {
|
|
23
|
+
label: string
|
|
24
|
+
description?: string // small caption under the label
|
|
25
|
+
disabled?: boolean
|
|
26
|
+
icon?: string // reserved; use marker slot for now
|
|
27
|
+
}
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
### Events
|
|
31
|
+
|
|
32
|
+
| Event | Payload | Description |
|
|
33
|
+
|-------|---------|-------------|
|
|
34
|
+
| `update:modelValue` | `Number` | Active step changed |
|
|
35
|
+
| `finish` | — | Emitted when next is clicked on the last step |
|
|
36
|
+
| `component-error` | `unknown` | Emitted if a `beforeNext` / `beforePrev` guard throws |
|
|
37
|
+
|
|
38
|
+
### Slots
|
|
39
|
+
|
|
40
|
+
| Slot | Scope | Description |
|
|
41
|
+
|------|-------|-------------|
|
|
42
|
+
| `step` | `{ index, step }` | Body for the active step |
|
|
43
|
+
| `marker` | `{ index, step, active }` | Override the step's marker (default: number) |
|
|
44
|
+
| `label` | `{ index, step }` | Override the step header label |
|
|
45
|
+
| `actions` | `{ next, prev, isFirst, isLast }` | Replace default footer buttons |
|
|
46
|
+
|
|
47
|
+
## Examples
|
|
48
|
+
|
|
49
|
+
```vue
|
|
50
|
+
<script setup>
|
|
51
|
+
import { ref } from 'vue'
|
|
52
|
+
const active = ref(0)
|
|
53
|
+
const steps = [
|
|
54
|
+
{ label: 'Account', description: 'Basics' },
|
|
55
|
+
{ label: 'Profile' },
|
|
56
|
+
{ label: 'Confirm' }
|
|
57
|
+
]
|
|
58
|
+
|
|
59
|
+
async function validateStep(index) {
|
|
60
|
+
// call server, validate fields...
|
|
61
|
+
return true
|
|
62
|
+
}
|
|
63
|
+
</script>
|
|
64
|
+
|
|
65
|
+
<template>
|
|
66
|
+
<VibeStepper
|
|
67
|
+
v-model="active"
|
|
68
|
+
:steps="steps"
|
|
69
|
+
:before-next="validateStep"
|
|
70
|
+
@finish="submit"
|
|
71
|
+
>
|
|
72
|
+
<template #step="{ index }">
|
|
73
|
+
<component :is="forms[index]" />
|
|
74
|
+
</template>
|
|
75
|
+
</VibeStepper>
|
|
76
|
+
</template>
|
|
77
|
+
```
|
|
78
|
+
|
|
79
|
+
### Non-linear (free navigation)
|
|
80
|
+
|
|
81
|
+
```vue
|
|
82
|
+
<VibeStepper :steps="steps" v-model="active" :linear="false" />
|
|
83
|
+
```
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
# VibeTabs / VibeTab
|
|
2
|
+
|
|
3
|
+
Self-contained tab container with content switching. Distinct from `VibeNav` (which is a pure `.nav` rendering primitive) — `VibeTabs` manages active state and renders tab panes.
|
|
4
|
+
|
|
5
|
+
## VibeTabs Props
|
|
6
|
+
|
|
7
|
+
| Prop | Type | Default | Description |
|
|
8
|
+
|------|------|---------|-------------|
|
|
9
|
+
| `modelValue` | `String` | `undefined` | Active tab `name` (v-model). Auto-defaults to first non-disabled tab. |
|
|
10
|
+
| `variant` | `'tabs' \| 'pills' \| 'underline'` | `'tabs'` | Bootstrap nav style |
|
|
11
|
+
| `fill` | `Boolean` | `false` | Apply `.nav-fill` |
|
|
12
|
+
| `justified` | `Boolean` | `false` | Apply `.nav-justified` |
|
|
13
|
+
| `vertical` | `Boolean` | `false` | Render nav vertically alongside content |
|
|
14
|
+
| `lazy` | `Boolean` | `false` | Defer rendering of inactive tabs until first activation |
|
|
15
|
+
|
|
16
|
+
### Events
|
|
17
|
+
|
|
18
|
+
| Event | Payload | Description |
|
|
19
|
+
|-------|---------|-------------|
|
|
20
|
+
| `update:modelValue` | `String` | Emitted when active tab changes |
|
|
21
|
+
| `change` | `String` | Same payload, alias for non-v-model usage |
|
|
22
|
+
|
|
23
|
+
## VibeTab Props
|
|
24
|
+
|
|
25
|
+
| Prop | Type | Default | Description |
|
|
26
|
+
|------|------|---------|-------------|
|
|
27
|
+
| `name` | `String` | required | Stable identifier matching `modelValue` |
|
|
28
|
+
| `label` | `String` | required | Tab nav button text |
|
|
29
|
+
| `disabled` | `Boolean` | `false` | Skip activation; appears greyed out |
|
|
30
|
+
|
|
31
|
+
The default slot is the tab body.
|
|
32
|
+
|
|
33
|
+
## Examples
|
|
34
|
+
|
|
35
|
+
```vue
|
|
36
|
+
<script setup>
|
|
37
|
+
import { ref } from 'vue'
|
|
38
|
+
const active = ref('details')
|
|
39
|
+
</script>
|
|
40
|
+
|
|
41
|
+
<template>
|
|
42
|
+
<VibeTabs v-model="active" variant="pills">
|
|
43
|
+
<VibeTab name="details" label="Details">
|
|
44
|
+
<p>Issue body, status, assignee...</p>
|
|
45
|
+
</VibeTab>
|
|
46
|
+
<VibeTab name="activity" label="Activity">
|
|
47
|
+
<ActivityTimeline />
|
|
48
|
+
</VibeTab>
|
|
49
|
+
<VibeTab name="links" label="Linked Issues" disabled>
|
|
50
|
+
<p>Link feature coming soon.</p>
|
|
51
|
+
</VibeTab>
|
|
52
|
+
</VibeTabs>
|
|
53
|
+
</template>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Lazy mounting for heavy panes
|
|
57
|
+
|
|
58
|
+
```vue
|
|
59
|
+
<VibeTabs v-model="active" lazy>
|
|
60
|
+
<VibeTab name="metrics" label="Metrics">
|
|
61
|
+
<ExpensiveChart />
|
|
62
|
+
</VibeTab>
|
|
63
|
+
</VibeTabs>
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
`<ExpensiveChart>` is not mounted until the user clicks the Metrics tab. Once activated, it stays mounted across switches so internal state isn't lost.
|