@velkymx/vibeui 0.9.0 → 1.1.0

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 (184) hide show
  1. package/AGENTS.md +44 -0
  2. package/CLAUDE.md +48 -0
  3. package/README.md +222 -197
  4. package/dist/App.vue.d.ts +2 -1
  5. package/dist/components/HelloWorld.vue.d.ts +2 -1
  6. package/dist/components/VibeAccordion.vue.d.ts +39 -40
  7. package/dist/components/VibeAlert.vue.d.ts +21 -37
  8. package/dist/components/VibeAutocomplete.vue.d.ts +59 -31
  9. package/dist/components/VibeBadge.vue.d.ts +10 -18
  10. package/dist/components/VibeBreadcrumb.vue.d.ts +25 -21
  11. package/dist/components/VibeButton.vue.d.ts +13 -17
  12. package/dist/components/VibeButtonGroup.vue.d.ts +11 -19
  13. package/dist/components/VibeCard.vue.d.ts +51 -24
  14. package/dist/components/VibeCarousel.vue.d.ts +27 -49
  15. package/dist/components/VibeChartBar.vue.d.ts +61 -0
  16. package/dist/components/VibeChartLine.vue.d.ts +70 -0
  17. package/dist/components/VibeChartPie.vue.d.ts +34 -0
  18. package/dist/components/VibeCloseButton.vue.d.ts +9 -7
  19. package/dist/components/VibeCol.vue.d.ts +9 -17
  20. package/dist/components/VibeCollapse.vue.d.ts +24 -32
  21. package/dist/components/VibeContainer.vue.d.ts +9 -17
  22. package/dist/components/VibeDataTable.vue.d.ts +122 -63
  23. package/dist/components/VibeDatePicker.vue.d.ts +4 -6
  24. package/dist/components/VibeDraggable.vue.d.ts +9 -13
  25. package/dist/components/VibeDropdown.vue.d.ts +46 -43
  26. package/dist/components/VibeDroppable.vue.d.ts +9 -13
  27. package/dist/components/VibeFileInput.vue.d.ts +14 -20
  28. package/dist/components/VibeFormCheckbox.vue.d.ts +30 -22
  29. package/dist/components/VibeFormDatepicker.vue.d.ts +27 -30
  30. package/dist/components/VibeFormErrorSummary.vue.d.ts +17 -0
  31. package/dist/components/VibeFormGroup.vue.d.ts +10 -13
  32. package/dist/components/VibeFormInput.vue.d.ts +60 -25
  33. package/dist/components/VibeFormRadio.vue.d.ts +23 -24
  34. package/dist/components/VibeFormSelect.vue.d.ts +28 -34
  35. package/dist/components/VibeFormSpinbutton.vue.d.ts +31 -34
  36. package/dist/components/VibeFormSwitch.vue.d.ts +22 -23
  37. package/dist/components/VibeFormTextarea.vue.d.ts +24 -25
  38. package/dist/components/VibeFormWysiwyg.vue.d.ts +23 -22
  39. package/dist/components/VibeHero.vue.d.ts +117 -0
  40. package/dist/components/VibeIcon.vue.d.ts +27 -7
  41. package/dist/components/VibeInputGroup.vue.d.ts +12 -14
  42. package/dist/components/VibeLink.vue.d.ts +14 -18
  43. package/dist/components/VibeListGroup.vue.d.ts +26 -22
  44. package/dist/components/VibeModal.vue.d.ts +47 -45
  45. package/dist/components/VibeNav.vue.d.ts +40 -20
  46. package/dist/components/VibeNavbar.vue.d.ts +12 -19
  47. package/dist/components/VibeNavbarBrand.vue.d.ts +9 -17
  48. package/dist/components/VibeNavbarNav.vue.d.ts +52 -33
  49. package/dist/components/VibeNavbarToggle.vue.d.ts +7 -5
  50. package/dist/components/VibeOffcanvas.vue.d.ts +28 -43
  51. package/dist/components/VibePagination.vue.d.ts +38 -29
  52. package/dist/components/VibePlaceholder.vue.d.ts +9 -17
  53. package/dist/components/VibePopover.vue.d.ts +17 -40
  54. package/dist/components/VibeProgress.vue.d.ts +13 -21
  55. package/dist/components/VibeResizable.vue.d.ts +10 -14
  56. package/dist/components/VibeRow.vue.d.ts +9 -17
  57. package/dist/components/VibeScrollspy.vue.d.ts +37 -25
  58. package/dist/components/VibeSkeleton.vue.d.ts +2 -1
  59. package/dist/components/VibeSlider.vue.d.ts +4 -5
  60. package/dist/components/VibeSortable.vue.d.ts +37 -18
  61. package/dist/components/VibeSpinner.vue.d.ts +4 -7
  62. package/dist/components/VibeStepper.vue.d.ts +32 -31
  63. package/dist/components/VibeTab.vue.d.ts +7 -11
  64. package/dist/components/VibeTabContent.vue.d.ts +13 -31
  65. package/dist/components/VibeTabs.vue.d.ts +9 -13
  66. package/dist/components/VibeToast.vue.d.ts +31 -44
  67. package/dist/components/VibeToastHost.vue.d.ts +2 -1
  68. package/dist/components/VibeTooltip.vue.d.ts +16 -39
  69. package/dist/components/chart/chartColors.d.ts +3 -0
  70. package/dist/components/chart/chartResize.d.ts +2 -0
  71. package/dist/components/chart/chartTooltip.d.ts +2 -0
  72. package/dist/components/chart/chartTypes.d.ts +6 -0
  73. package/dist/components/chart/drawBar.d.ts +5 -0
  74. package/dist/components/chart/drawLine.d.ts +18 -0
  75. package/dist/components/chart/drawPie.d.ts +4 -0
  76. package/dist/components/dndStore.d.ts +1 -0
  77. package/dist/components/index.d.ts +6 -1
  78. package/dist/composables/useBreakpoints.d.ts +1 -0
  79. package/dist/composables/useColorMode.d.ts +1 -1
  80. package/dist/composables/useId.d.ts +1 -4
  81. package/dist/directives/vTooltip.d.ts +2 -3
  82. package/dist/injectionKeys.d.ts +34 -0
  83. package/dist/purify.es-eYghtX9j.mjs +735 -0
  84. package/dist/types.d.ts +23 -2
  85. package/dist/utils/routeKey.d.ts +11 -0
  86. package/dist/utils/safeCss.d.ts +16 -0
  87. package/dist/utils/safeHref.d.ts +7 -0
  88. package/dist/utils/sanitizeHtml.d.ts +13 -0
  89. package/dist/vibeui.css +2 -1
  90. package/dist/vibeui.es.js +8527 -5855
  91. package/dist/vibeui.umd.js +3 -1
  92. package/docs/README.md +225 -0
  93. package/docs/components/advanced/popover.md +125 -0
  94. package/docs/components/advanced/scrollspy.md +106 -0
  95. package/docs/components/advanced/tooltip.md +90 -0
  96. package/docs/components/card/card.md +223 -0
  97. package/docs/components/charts/chart-bar.md +129 -0
  98. package/docs/components/charts/chart-line.md +136 -0
  99. package/docs/components/charts/chart-pie.md +102 -0
  100. package/docs/components/core/alert.md +94 -0
  101. package/docs/components/core/badge.md +75 -0
  102. package/docs/components/core/button-group.md +99 -0
  103. package/docs/components/core/button.md +145 -0
  104. package/docs/components/core/close-button.md +82 -0
  105. package/docs/components/core/link.md +79 -0
  106. package/docs/components/core/placeholder.md +129 -0
  107. package/docs/components/core/skeleton.md +40 -0
  108. package/docs/components/core/spinner.md +103 -0
  109. package/docs/components/data/datatable.md +437 -0
  110. package/docs/components/hero/hero.md +65 -0
  111. package/docs/components/interactive/accordion.md +121 -0
  112. package/docs/components/interactive/carousel.md +112 -0
  113. package/docs/components/interactive/collapse.md +106 -0
  114. package/docs/components/interactive/date-picker.md +78 -0
  115. package/docs/components/interactive/draggable.md +91 -0
  116. package/docs/components/interactive/dropdown.md +129 -0
  117. package/docs/components/interactive/modal.md +151 -0
  118. package/docs/components/interactive/offcanvas.md +92 -0
  119. package/docs/components/interactive/resizable.md +73 -0
  120. package/docs/components/interactive/slider.md +57 -0
  121. package/docs/components/interactive/sortable.md +52 -0
  122. package/docs/components/interactive/stepper.md +83 -0
  123. package/docs/components/interactive/tabs.md +66 -0
  124. package/docs/components/interactive/toast.md +177 -0
  125. package/docs/components/layout/col.md +117 -0
  126. package/docs/components/layout/container.md +53 -0
  127. package/docs/components/layout/row.md +107 -0
  128. package/docs/components/list/list-group.md +225 -0
  129. package/docs/components/navigation/breadcrumb.md +120 -0
  130. package/docs/components/navigation/nav.md +151 -0
  131. package/docs/components/navigation/navbar.md +114 -0
  132. package/docs/components/navigation/pagination.md +163 -0
  133. package/docs/components/progress/progress.md +188 -0
  134. package/docs/composables/back-button.md +28 -0
  135. package/docs/composables/breakpoints.md +54 -0
  136. package/docs/composables/color-mode.md +179 -0
  137. package/docs/composables/use-form.md +78 -0
  138. package/docs/composables/use-position.md +68 -0
  139. package/docs/composables/use-toast.md +91 -0
  140. package/docs/directives/v-tooltip.md +58 -0
  141. package/docs/forms/README.md +87 -0
  142. package/docs/forms/autocomplete.md +96 -0
  143. package/docs/forms/file-input.md +97 -0
  144. package/docs/forms/form-checkbox.md +100 -0
  145. package/docs/forms/form-datepicker.md +80 -0
  146. package/docs/forms/form-error-summary.md +96 -0
  147. package/docs/forms/form-group.md +118 -0
  148. package/docs/forms/form-input.md +140 -0
  149. package/docs/forms/form-radio.md +82 -0
  150. package/docs/forms/form-select.md +98 -0
  151. package/docs/forms/form-spinbutton.md +94 -0
  152. package/docs/forms/form-switch.md +75 -0
  153. package/docs/forms/form-textarea.md +82 -0
  154. package/docs/forms/form-wysiwyg.md +99 -0
  155. package/docs/forms/input-group.md +70 -0
  156. package/docs/forms/validation.md +213 -0
  157. package/docs/getting-started/starter-template.md +136 -0
  158. package/docs/superpowers/plans/2026-05-12-vibe-charts.md +1999 -0
  159. package/docs/superpowers/plans/2026-05-29-e2e-browser-testing.md +615 -0
  160. package/docs/superpowers/specs/2026-05-12-charting-design.md +185 -0
  161. package/docs/superpowers/specs/2026-05-29-e2e-browser-testing-design.md +168 -0
  162. package/docs/utilities/position.md +82 -0
  163. package/docs/versioning.md +57 -0
  164. package/examples/README.md +201 -0
  165. package/examples/album.html +262 -0
  166. package/examples/blog.html +166 -0
  167. package/examples/carousel.html +114 -0
  168. package/examples/checkout.html +275 -0
  169. package/examples/cover.html +89 -0
  170. package/examples/dashboard.html +156 -0
  171. package/examples/index.html +129 -0
  172. package/examples/jumbotron.html +56 -0
  173. package/examples/mobile-dashboard.html +138 -0
  174. package/examples/pricing.html +172 -0
  175. package/examples/product.html +145 -0
  176. package/examples/sidebars.html +166 -0
  177. package/examples/sign-in.html +119 -0
  178. package/examples/starter.html +314 -0
  179. package/examples/sticky-footer-navbar.html +70 -0
  180. package/examples/sticky-footer.html +60 -0
  181. package/examples/test-simple.html +91 -0
  182. package/llms.txt +801 -0
  183. package/package.json +44 -14
  184. package/dist/types/index.d.ts +0 -6
@@ -0,0 +1,151 @@
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
+ | `autoFocus` | `Boolean` | `true` | Focus the first focusable descendant when the modal opens (WCAG 2.4.3). |
21
+ | `submitOnMetaEnter` | `Boolean` | `true` | Submit the first `<form>` inside the modal on `Cmd+Enter` / `Ctrl+Enter` (WCAG 2.1.1). |
22
+
23
+ ## Events
24
+
25
+ | Event | Payload | Description |
26
+ |-------|---------|-------------|
27
+ | `update:modelValue` | `Boolean` | Emitted when modal visibility changes |
28
+ | `show` | - | Emitted when modal starts showing |
29
+ | `shown` | - | Emitted when modal is fully shown |
30
+ | `hide` | - | Emitted when modal starts hiding |
31
+ | `hidden` | - | Emitted when modal is fully hidden |
32
+ | `component-error` | `ComponentError` | Emitted if Bootstrap JS fails to load |
33
+
34
+ ## Slots
35
+
36
+ | Slot | Description |
37
+ |------|-------------|
38
+ | `default` | Modal body content |
39
+ | `header` | Custom header content |
40
+ | `footer` | Custom footer content |
41
+
42
+ ## Usage
43
+
44
+ ### Reactive Usage (v-model)
45
+
46
+ ```vue
47
+ <template>
48
+ <div>
49
+ <VibeButton variant="primary" @click="showModal = true">
50
+ Open Modal
51
+ </VibeButton>
52
+
53
+ <VibeModal v-model="showModal" title="Reactive Modal">
54
+ <p>This modal is controlled via Vue state.</p>
55
+ </VibeModal>
56
+ </div>
57
+ </template>
58
+
59
+ <script setup>
60
+ import { ref } from 'vue'
61
+ const showModal = ref(false)
62
+ </script>
63
+ ```
64
+
65
+ ### Sized Modals
66
+
67
+ ```vue
68
+ <template>
69
+ <div>
70
+ <VibeModal title="Small Modal" size="sm">
71
+ Small modal content
72
+ </VibeModal>
73
+
74
+ <VibeModal title="Large Modal" size="lg">
75
+ Large modal content
76
+ </VibeModal>
77
+ </div>
78
+ </template>
79
+ ```
80
+
81
+ ### Centered Modal
82
+
83
+ ```vue
84
+ <template>
85
+ <VibeModal title="Centered Modal" centered>
86
+ This modal is vertically centered.
87
+ </VibeModal>
88
+ </template>
89
+ ```
90
+
91
+ ### Custom Footer
92
+
93
+ ```vue
94
+ <template>
95
+ <VibeModal v-model="showModal" title="Custom Footer">
96
+ <p>Modal with custom footer buttons.</p>
97
+
98
+ <template #footer>
99
+ <VibeButton variant="secondary" @click="showModal = false">Close</VibeButton>
100
+ <VibeButton variant="primary" @click="save">Save changes</VibeButton>
101
+ </template>
102
+ </VibeModal>
103
+ </template>
104
+
105
+ <script setup>
106
+ import { ref } from 'vue'
107
+ const showModal = ref(true)
108
+ function save() {
109
+ // persist changes...
110
+ showModal.value = false
111
+ }
112
+ </script>
113
+ ```
114
+
115
+ ## Important Notes
116
+
117
+ **Automatic Initialization:** This component automatically initializes Bootstrap's Modal functionality when it is mounted, provided that Bootstrap's JavaScript is available in your project.
118
+
119
+ **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.
120
+
121
+ **Auto-focus (WCAG 2.4.3):** On open, focus moves to the first focusable descendant (input, select, button, etc.). Repeated opens re-focus. Disable with `:auto-focus="false"` when you need to control focus yourself.
122
+
123
+ **Focus trap (WCAG 2.1.2):** While the modal is open, `Tab` and `Shift+Tab` cycle within the modal only. All sibling elements receive the `inert` attribute so screen readers cannot reach the page behind the modal. `inert` is cleared on close and on unmount.
124
+
125
+ **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.
126
+
127
+ **Cmd/Ctrl+Enter submit (WCAG 2.1.1):** Pressing `Cmd+Enter` (macOS) or `Ctrl+Enter` (Windows/Linux) inside the modal submits the first `<form>` descendant via `requestSubmit()`. Disable with `:submit-on-meta-enter="false"` for non-form modals.
128
+
129
+ **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.
130
+
131
+ ## Mobile Optimization
132
+
133
+ **Safe Areas:** In fullscreen mode, the modal header and footer automatically respect device safe areas (notches) in hybrid apps.
134
+
135
+ **Hardware Back Button:** On Android devices in hybrid environments, the hardware back button will automatically close the modal if it is open.
136
+
137
+ **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.
138
+
139
+ ## Bootstrap CSS Classes
140
+
141
+ - `.modal`
142
+ - `.modal-dialog`
143
+ - `.modal-content`
144
+ - `.modal-header`
145
+ - `.modal-title`
146
+ - `.modal-body`
147
+ - `.modal-footer`
148
+ - `.modal-{size}`
149
+ - `.modal-dialog-centered`
150
+ - `.modal-dialog-scrollable`
151
+ - `.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.