@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.
Files changed (205) hide show
  1. package/AGENTS.md +44 -0
  2. package/CLAUDE.md +48 -0
  3. package/README.md +222 -197
  4. package/dist/purify.es-1D-VntFD.mjs +679 -0
  5. package/dist/src/App.vue.d.ts +3 -0
  6. package/dist/src/components/HelloWorld.vue.d.ts +6 -0
  7. package/dist/src/components/VibeAccordion.vue.d.ts +89 -0
  8. package/dist/{components → src/components}/VibeAlert.vue.d.ts +18 -34
  9. package/dist/src/components/VibeAutocomplete.vue.d.ts +74 -0
  10. package/dist/{components → src/components}/VibeBadge.vue.d.ts +10 -18
  11. package/dist/src/components/VibeBreadcrumb.vue.d.ts +51 -0
  12. package/dist/{components → src/components}/VibeButton.vue.d.ts +13 -17
  13. package/dist/{components → src/components}/VibeButtonGroup.vue.d.ts +10 -18
  14. package/dist/{components → src/components}/VibeCard.vue.d.ts +51 -24
  15. package/dist/{components → src/components}/VibeCarousel.vue.d.ts +27 -49
  16. package/dist/src/components/VibeChartBar.vue.d.ts +61 -0
  17. package/dist/src/components/VibeChartLine.vue.d.ts +70 -0
  18. package/dist/src/components/VibeChartPie.vue.d.ts +34 -0
  19. package/dist/{components → src/components}/VibeCloseButton.vue.d.ts +9 -7
  20. package/dist/{components → src/components}/VibeCol.vue.d.ts +9 -17
  21. package/dist/src/components/VibeCollapse.vue.d.ts +76 -0
  22. package/dist/src/components/VibeContainer.vue.d.ts +36 -0
  23. package/dist/src/components/VibeDataTable.vue.d.ts +131 -0
  24. package/dist/{components → src/components}/VibeDatePicker.vue.d.ts +4 -6
  25. package/dist/{components → src/components}/VibeDraggable.vue.d.ts +9 -13
  26. package/dist/{components → src/components}/VibeDropdown.vue.d.ts +46 -43
  27. package/dist/{components → src/components}/VibeDroppable.vue.d.ts +9 -13
  28. package/dist/{components → src/components}/VibeFileInput.vue.d.ts +14 -20
  29. package/dist/{components → src/components}/VibeFormCheckbox.vue.d.ts +29 -21
  30. package/dist/{components → src/components}/VibeFormDatepicker.vue.d.ts +26 -29
  31. package/dist/{components → src/components}/VibeFormGroup.vue.d.ts +10 -13
  32. package/dist/{components → src/components}/VibeFormInput.vue.d.ts +22 -23
  33. package/dist/{components → src/components}/VibeFormRadio.vue.d.ts +22 -23
  34. package/dist/{components → src/components}/VibeFormSelect.vue.d.ts +27 -33
  35. package/dist/{components → src/components}/VibeFormSpinbutton.vue.d.ts +30 -33
  36. package/dist/{components → src/components}/VibeFormSwitch.vue.d.ts +21 -22
  37. package/dist/{components → src/components}/VibeFormTextarea.vue.d.ts +23 -24
  38. package/dist/{components → src/components}/VibeFormWysiwyg.vue.d.ts +22 -21
  39. package/dist/src/components/VibeHero.vue.d.ts +108 -0
  40. package/dist/{components → src/components}/VibeIcon.vue.d.ts +27 -7
  41. package/dist/{components → src/components}/VibeInputGroup.vue.d.ts +11 -13
  42. package/dist/{components → src/components}/VibeLink.vue.d.ts +14 -18
  43. package/dist/{components → src/components}/VibeListGroup.vue.d.ts +26 -22
  44. package/dist/{components → src/components}/VibeModal.vue.d.ts +29 -45
  45. package/dist/{components → src/components}/VibeNav.vue.d.ts +40 -20
  46. package/dist/{components → src/components}/VibeNavbar.vue.d.ts +12 -19
  47. package/dist/src/components/VibeNavbarBrand.vue.d.ts +34 -0
  48. package/dist/src/components/VibeNavbarNav.vue.d.ts +80 -0
  49. package/dist/{components → src/components}/VibeNavbarToggle.vue.d.ts +7 -5
  50. package/dist/{components → src/components}/VibeOffcanvas.vue.d.ts +28 -43
  51. package/dist/{components → src/components}/VibePagination.vue.d.ts +38 -29
  52. package/dist/{components → src/components}/VibePlaceholder.vue.d.ts +9 -17
  53. package/dist/src/components/VibePopover.vue.d.ts +72 -0
  54. package/dist/src/components/VibeProgress.vue.d.ts +37 -0
  55. package/dist/{components → src/components}/VibeResizable.vue.d.ts +10 -14
  56. package/dist/{components → src/components}/VibeRow.vue.d.ts +9 -17
  57. package/dist/src/components/VibeScrollspy.vue.d.ts +89 -0
  58. package/dist/{components → src/components}/VibeSkeleton.vue.d.ts +2 -1
  59. package/dist/{components → src/components}/VibeSlider.vue.d.ts +4 -5
  60. package/dist/src/components/VibeSortable.vue.d.ts +59 -0
  61. package/dist/{components → src/components}/VibeSpinner.vue.d.ts +4 -7
  62. package/dist/{components → src/components}/VibeStepper.vue.d.ts +32 -31
  63. package/dist/{components → src/components}/VibeTab.vue.d.ts +7 -11
  64. package/dist/src/components/VibeTabContent.vue.d.ts +56 -0
  65. package/dist/{components → src/components}/VibeTabs.vue.d.ts +9 -13
  66. package/dist/{components → src/components}/VibeToast.vue.d.ts +31 -44
  67. package/dist/{components → src/components}/VibeToastHost.vue.d.ts +2 -1
  68. package/dist/src/components/VibeTooltip.vue.d.ts +63 -0
  69. package/dist/src/components/chart/chartColors.d.ts +3 -0
  70. package/dist/src/components/chart/chartResize.d.ts +2 -0
  71. package/dist/src/components/chart/chartTooltip.d.ts +2 -0
  72. package/dist/src/components/chart/chartTypes.d.ts +6 -0
  73. package/dist/src/components/chart/drawBar.d.ts +5 -0
  74. package/dist/src/components/chart/drawLine.d.ts +18 -0
  75. package/dist/src/components/chart/drawPie.d.ts +4 -0
  76. package/dist/{components → src/components}/dndStore.d.ts +1 -0
  77. package/dist/{components → src/components}/index.d.ts +5 -1
  78. package/dist/{composables → src/composables}/useBreakpoints.d.ts +1 -0
  79. package/dist/{composables → src/composables}/useColorMode.d.ts +1 -1
  80. package/dist/src/composables/useId.d.ts +2 -0
  81. package/dist/{directives → src/directives}/vTooltip.d.ts +2 -3
  82. package/dist/src/injectionKeys.d.ts +28 -0
  83. package/dist/{types.d.ts → src/types.d.ts} +21 -2
  84. package/dist/src/utils/safeCss.d.ts +16 -0
  85. package/dist/src/utils/safeHref.d.ts +7 -0
  86. package/dist/src/utils/sanitizeHtml.d.ts +13 -0
  87. package/dist/vibeui.css +2 -1
  88. package/dist/vibeui.es.js +8269 -5855
  89. package/dist/vibeui.umd.js +3 -1
  90. package/docs/README.md +225 -0
  91. package/docs/components/advanced/popover.md +125 -0
  92. package/docs/components/advanced/scrollspy.md +106 -0
  93. package/docs/components/advanced/tooltip.md +90 -0
  94. package/docs/components/card/card.md +223 -0
  95. package/docs/components/charts/chart-bar.md +129 -0
  96. package/docs/components/charts/chart-line.md +136 -0
  97. package/docs/components/charts/chart-pie.md +102 -0
  98. package/docs/components/core/alert.md +94 -0
  99. package/docs/components/core/badge.md +75 -0
  100. package/docs/components/core/button-group.md +99 -0
  101. package/docs/components/core/button.md +127 -0
  102. package/docs/components/core/close-button.md +82 -0
  103. package/docs/components/core/link.md +79 -0
  104. package/docs/components/core/placeholder.md +129 -0
  105. package/docs/components/core/skeleton.md +40 -0
  106. package/docs/components/core/spinner.md +103 -0
  107. package/docs/components/data/datatable.md +435 -0
  108. package/docs/components/hero/hero.md +64 -0
  109. package/docs/components/interactive/accordion.md +121 -0
  110. package/docs/components/interactive/carousel.md +112 -0
  111. package/docs/components/interactive/collapse.md +106 -0
  112. package/docs/components/interactive/date-picker.md +78 -0
  113. package/docs/components/interactive/draggable.md +91 -0
  114. package/docs/components/interactive/dropdown.md +129 -0
  115. package/docs/components/interactive/modal.md +143 -0
  116. package/docs/components/interactive/offcanvas.md +92 -0
  117. package/docs/components/interactive/resizable.md +73 -0
  118. package/docs/components/interactive/slider.md +57 -0
  119. package/docs/components/interactive/sortable.md +52 -0
  120. package/docs/components/interactive/stepper.md +83 -0
  121. package/docs/components/interactive/tabs.md +66 -0
  122. package/docs/components/interactive/toast.md +177 -0
  123. package/docs/components/layout/col.md +117 -0
  124. package/docs/components/layout/container.md +53 -0
  125. package/docs/components/layout/row.md +107 -0
  126. package/docs/components/list/list-group.md +225 -0
  127. package/docs/components/navigation/breadcrumb.md +120 -0
  128. package/docs/components/navigation/nav.md +151 -0
  129. package/docs/components/navigation/navbar.md +108 -0
  130. package/docs/components/navigation/pagination.md +162 -0
  131. package/docs/components/progress/progress.md +188 -0
  132. package/docs/composables/back-button.md +28 -0
  133. package/docs/composables/breakpoints.md +54 -0
  134. package/docs/composables/color-mode.md +179 -0
  135. package/docs/composables/use-form.md +78 -0
  136. package/docs/composables/use-position.md +68 -0
  137. package/docs/composables/use-toast.md +91 -0
  138. package/docs/directives/v-tooltip.md +58 -0
  139. package/docs/forms/README.md +87 -0
  140. package/docs/forms/autocomplete.md +96 -0
  141. package/docs/forms/file-input.md +97 -0
  142. package/docs/forms/form-checkbox.md +100 -0
  143. package/docs/forms/form-datepicker.md +80 -0
  144. package/docs/forms/form-group.md +115 -0
  145. package/docs/forms/form-input.md +112 -0
  146. package/docs/forms/form-radio.md +82 -0
  147. package/docs/forms/form-select.md +98 -0
  148. package/docs/forms/form-spinbutton.md +94 -0
  149. package/docs/forms/form-switch.md +75 -0
  150. package/docs/forms/form-textarea.md +82 -0
  151. package/docs/forms/form-wysiwyg.md +99 -0
  152. package/docs/forms/input-group.md +70 -0
  153. package/docs/forms/validation.md +213 -0
  154. package/docs/getting-started/starter-template.md +136 -0
  155. package/docs/superpowers/plans/2026-05-12-vibe-charts.md +1999 -0
  156. package/docs/superpowers/plans/2026-05-29-e2e-browser-testing.md +615 -0
  157. package/docs/superpowers/specs/2026-05-12-charting-design.md +185 -0
  158. package/docs/superpowers/specs/2026-05-29-e2e-browser-testing-design.md +168 -0
  159. package/docs/utilities/position.md +82 -0
  160. package/docs/versioning.md +57 -0
  161. package/examples/README.md +201 -0
  162. package/examples/album.html +262 -0
  163. package/examples/blog.html +166 -0
  164. package/examples/carousel.html +114 -0
  165. package/examples/checkout.html +275 -0
  166. package/examples/cover.html +89 -0
  167. package/examples/dashboard.html +156 -0
  168. package/examples/index.html +129 -0
  169. package/examples/jumbotron.html +56 -0
  170. package/examples/mobile-dashboard.html +138 -0
  171. package/examples/pricing.html +172 -0
  172. package/examples/product.html +145 -0
  173. package/examples/sidebars.html +166 -0
  174. package/examples/sign-in.html +119 -0
  175. package/examples/starter.html +314 -0
  176. package/examples/sticky-footer-navbar.html +70 -0
  177. package/examples/sticky-footer.html +60 -0
  178. package/examples/test-simple.html +91 -0
  179. package/llms.txt +782 -0
  180. package/package.json +44 -14
  181. package/dist/App.vue.d.ts +0 -2
  182. package/dist/components/HelloWorld.vue.d.ts +0 -5
  183. package/dist/components/VibeAccordion.vue.d.ts +0 -90
  184. package/dist/components/VibeAutocomplete.vue.d.ts +0 -46
  185. package/dist/components/VibeBreadcrumb.vue.d.ts +0 -47
  186. package/dist/components/VibeCollapse.vue.d.ts +0 -84
  187. package/dist/components/VibeContainer.vue.d.ts +0 -44
  188. package/dist/components/VibeDataTable.vue.d.ts +0 -76
  189. package/dist/components/VibeNavbarBrand.vue.d.ts +0 -42
  190. package/dist/components/VibeNavbarNav.vue.d.ts +0 -61
  191. package/dist/components/VibePopover.vue.d.ts +0 -95
  192. package/dist/components/VibeProgress.vue.d.ts +0 -45
  193. package/dist/components/VibeScrollspy.vue.d.ts +0 -77
  194. package/dist/components/VibeSortable.vue.d.ts +0 -40
  195. package/dist/components/VibeTabContent.vue.d.ts +0 -74
  196. package/dist/components/VibeTooltip.vue.d.ts +0 -86
  197. package/dist/composables/useId.d.ts +0 -5
  198. package/dist/types/index.d.ts +0 -6
  199. /package/dist/{composables → src/composables}/useBackButton.d.ts +0 -0
  200. /package/dist/{composables → src/composables}/useForm.d.ts +0 -0
  201. /package/dist/{composables → src/composables}/useFormValidation.d.ts +0 -0
  202. /package/dist/{composables → src/composables}/usePosition.d.ts +0 -0
  203. /package/dist/{composables → src/composables}/useToast.d.ts +0 -0
  204. /package/dist/{index.d.ts → src/index.d.ts} +0 -0
  205. /package/dist/{main.d.ts → src/main.d.ts} +0 -0
@@ -0,0 +1,103 @@
1
+ # VibeSpinner
2
+
3
+ Loading spinner with border or grow animation styles.
4
+
5
+ ## Props
6
+
7
+ | Prop | Type | Default | Description |
8
+ |------|------|---------|-------------|
9
+ | `variant` | `Variant` | `undefined` | Text color variant |
10
+ | `type` | `SpinnerType` | `'border'` | Spinner type: `'border'` or `'grow'` |
11
+ | `size` | `Size` | `undefined` | Spinner size: `'sm'` or `'lg'` |
12
+ | `label` | `String` | `'Loading...'` | Screen reader text |
13
+ | `tag` | `String` | `'div'` | HTML tag to render |
14
+
15
+ ## Usage
16
+
17
+ ### Basic Spinner
18
+
19
+ ```vue
20
+ <template>
21
+ <VibeSpinner />
22
+ </template>
23
+ ```
24
+
25
+ ### Grow Spinner
26
+
27
+ ```vue
28
+ <template>
29
+ <VibeSpinner type="grow" />
30
+ </template>
31
+ ```
32
+
33
+ ### Colored Spinners
34
+
35
+ ```vue
36
+ <template>
37
+ <div>
38
+ <VibeSpinner variant="primary" />
39
+ <VibeSpinner variant="success" />
40
+ <VibeSpinner variant="danger" />
41
+ <VibeSpinner variant="warning" />
42
+ <VibeSpinner variant="info" />
43
+ </div>
44
+ </template>
45
+ ```
46
+
47
+ ### Small Spinners
48
+
49
+ ```vue
50
+ <template>
51
+ <div>
52
+ <VibeSpinner size="sm" />
53
+ <VibeSpinner type="grow" size="sm" />
54
+ </div>
55
+ </template>
56
+ ```
57
+
58
+ ### In Button
59
+
60
+ ```vue
61
+ <template>
62
+ <VibeButton variant="primary" disabled>
63
+ <VibeSpinner size="sm" tag="span" />
64
+ Loading...
65
+ </VibeButton>
66
+ </template>
67
+ ```
68
+
69
+ ### Custom Label
70
+
71
+ ```vue
72
+ <template>
73
+ <VibeSpinner label="Please wait while we load your data..." />
74
+ </template>
75
+ ```
76
+
77
+ ### Loading State Example
78
+
79
+ ```vue
80
+ <script setup>
81
+ import { ref } from 'vue'
82
+
83
+ const loading = ref(true)
84
+
85
+ setTimeout(() => {
86
+ loading.value = false
87
+ }, 3000)
88
+ </script>
89
+
90
+ <template>
91
+ <div>
92
+ <VibeSpinner v-if="loading" variant="primary" />
93
+ <div v-else>Content loaded!</div>
94
+ </div>
95
+ </template>
96
+ ```
97
+
98
+ ## Bootstrap CSS Classes
99
+
100
+ - `.spinner-border` or `.spinner-grow`
101
+ - `.text-{variant}`
102
+ - `.spinner-{type}-{size}`
103
+ - `.visually-hidden` (for label)
@@ -0,0 +1,435 @@
1
+ # VibeDataTable
2
+
3
+ Powerful data table component with search, sorting, and pagination - similar to DataTables.net but built for Vue 3 and Bootstrap 5.3.
4
+
5
+ ## Features
6
+
7
+ - **Search/Filter** - Real-time search across all searchable columns
8
+ - **Column Sorting** - Click column headers to sort (asc/desc)
9
+ - **Pagination** - Built-in pagination with customizable page sizes
10
+ - **Responsive** - Mobile-friendly with responsive table wrapper
11
+ - **Bootstrap Styling** - All Bootstrap table variants (striped, bordered, hover, etc.)
12
+ - **Custom Cell Rendering** - Slots for custom cell content
13
+ - **Formatters** - Custom data formatters per column
14
+ - **TypeScript** - Fully typed with comprehensive interfaces
15
+
16
+ ## Props
17
+
18
+ ### Data Props
19
+
20
+ | Prop | Type | Default | Description |
21
+ |------|------|---------|-------------|
22
+ | `items` | `T[]` | `[]` | Array of data objects to display |
23
+ | `columns` | `DataTableColumn<T>[]` | Required | Column definitions |
24
+ | `rowKey` | `String` | `'id'` | Property name used as the unique key for each row. **Recommended** — set it to a unique field in your data (e.g. `'id'`, `'uuid'`) so Vue tracks rows correctly across sorting, filtering, and pagination. Falls back to a positional key (with a DEV warning) when missing. |
25
+
26
+ > **Typing tip**: `DataTableColumn` is generic over your row type. For full slot-prop / formatter typing, annotate the column array:
27
+ >
28
+ > ```ts
29
+ > import type { DataTableColumn } from '@velkymx/vibeui'
30
+ > interface User { id: number; name: string; active: boolean }
31
+ > const columns: DataTableColumn<User>[] = [
32
+ > { key: 'name', label: 'Name' }, // key narrowed to keyof User
33
+ > { key: 'active', label: 'Active', formatter: v => v ? 'Yes' : 'No' }
34
+ > ]
35
+ > ```
36
+ >
37
+ > Without the annotation, `T` defaults to `Record<string, unknown>` and slot props arrive as `unknown`.
38
+
39
+ ### Table Styling Props
40
+
41
+ | Prop | Type | Default | Description |
42
+ |------|------|---------|-------------|
43
+ | `striped` | `Boolean` | `false` | Striped table rows |
44
+ | `bordered` | `Boolean` | `false` | Bordered table |
45
+ | `borderless` | `Boolean` | `false` | Remove all borders |
46
+ | `hover` | `Boolean` | `false` | Hover effect on rows |
47
+ | `small` | `Boolean` | `false` | Compact table |
48
+ | `responsive` | `Boolean` | `true` | Responsive table wrapper |
49
+ | `stack` | `Boolean` | `false` | Transforms table into cards on mobile screens |
50
+ | `variant` | `String` | `undefined` | Table color variant |
51
+
52
+ ### Feature Props
53
+
54
+ | Prop | Type | Default | Description |
55
+ |------|------|---------|-------------|
56
+ | `searchable` | `Boolean` | `true` | Enable search functionality |
57
+ | `sortable` | `Boolean` | `true` | Enable column sorting |
58
+ | `paginated` | `Boolean` | `true` | Enable pagination |
59
+
60
+ ### Search Props
61
+
62
+ | Prop | Type | Default | Description |
63
+ |------|------|---------|-------------|
64
+ | `searchPlaceholder` | `String` | `'Search...'` | Search input placeholder |
65
+ | `searchDebounce` | `Number` | `300` | Search debounce delay (ms) |
66
+
67
+ ### Pagination Props
68
+
69
+ | Prop | Type | Default | Description |
70
+ |------|------|---------|-------------|
71
+ | `perPage` | `Number` | `10` | Items per page |
72
+ | `currentPage` | `Number` | `1` | Current page number |
73
+ | `perPageOptions` | `Number[]` | `[5, 10, 25, 50, 100]` | Page size options |
74
+
75
+ ### Sorting Props
76
+
77
+ | Prop | Type | Default | Description |
78
+ |------|------|---------|-------------|
79
+ | `sortBy` | `String` | `undefined` | Initial sort column key |
80
+ | `sortDesc` | `Boolean` | `false` | Initial sort direction (true = descending) |
81
+
82
+ ### Display Props
83
+
84
+ | Prop | Type | Default | Description |
85
+ |------|------|---------|-------------|
86
+ | `showEmpty` | `Boolean` | `true` | Show message when no data |
87
+ | `emptyText` | `String` | `'No data available'` | Empty state message |
88
+ | `showPerPage` | `Boolean` | `true` | Show per-page selector |
89
+ | `showInfo` | `Boolean` | `true` | Show info text (X to Y of Z entries) |
90
+ | `infoText` | `String` | `'Showing {start} to {end} of {total} entries'` | Info text template |
91
+ | `filteredInfoText` | `String` | `'Showing {start} to {end} of {total} entries (filtered from {totalRows} total entries)'` | Filtered info text template |
92
+
93
+ ## Column Definition
94
+
95
+ The `columns` prop accepts an array of `DataTableColumn` objects:
96
+
97
+ ```typescript
98
+ interface DataTableColumn {
99
+ key: string // Property key in data object
100
+ label: string // Column header label
101
+ sortable?: boolean // Enable/disable sorting (default: true)
102
+ searchable?: boolean // Include in search (default: true)
103
+ formatter?: (value: any, row: any) => string | number // Custom formatter
104
+ class?: string // CSS class for td
105
+ headerClass?: string // CSS class for th
106
+ thStyle?: Record<string, string> // Inline styles for th (sanitized — see note)
107
+ tdStyle?: Record<string, string> // Inline styles for td (sanitized — see note)
108
+ }
109
+ ```
110
+
111
+ > **`thStyle` / `tdStyle` are sanitized.** Both objects are filtered against a safe CSS-property allowlist before being applied, as a defense against CSS injection (data exfiltration / UI spoofing) when column config comes from an API or untrusted source. Properties outside the allowlist are dropped.
112
+
113
+ ## Events
114
+
115
+ | Event | Payload | Description |
116
+ |-------|---------|-------------|
117
+ | `update:currentPage` | `Number` | Emitted when page changes |
118
+ | `update:perPage` | `Number` | Emitted when per-page changes |
119
+ | `update:sortBy` | `String` | Emitted when sort column changes |
120
+ | `update:sortDesc` | `Boolean` | Emitted when sort direction changes |
121
+ | `row-clicked` | `(item, globalIndex)` | Emitted when a row is clicked. `globalIndex` is the index within the full filtered/sorted dataset, not the current page. Only emitted when a `@row-clicked` listener is attached (rows show a pointer cursor in that case). |
122
+
123
+ ## Slots
124
+
125
+ | Slot | Props | Description |
126
+ |------|-------|-------------|
127
+ | `cell({columnKey})` | `{ item, value, index }` | Custom cell rendering for specific column |
128
+
129
+ ## Usage
130
+
131
+ ### Basic DataTable
132
+
133
+ ```vue
134
+ <script setup>
135
+ import { ref } from 'vue'
136
+
137
+ const columns = [
138
+ { key: 'id', label: 'ID' },
139
+ { key: 'name', label: 'Name' },
140
+ { key: 'email', label: 'Email' },
141
+ { key: 'status', label: 'Status' }
142
+ ]
143
+
144
+ const items = [
145
+ { id: 1, name: 'John Doe', email: 'john@example.com', status: 'Active' },
146
+ { id: 2, name: 'Jane Smith', email: 'jane@example.com', status: 'Inactive' },
147
+ { id: 3, name: 'Bob Johnson', email: 'bob@example.com', status: 'Active' }
148
+ ]
149
+ </script>
150
+
151
+ <template>
152
+ <VibeDataTable :columns="columns" :items="items" row-key="id" />
153
+ </template>
154
+ ```
155
+
156
+ > Always pass `row-key` pointing at a unique field (here `id`) so Vue keys rows stably across sorting, filtering, and pagination.
157
+
158
+ ### With Bootstrap Styling
159
+
160
+ ```vue
161
+ <template>
162
+ <VibeDataTable
163
+ :columns="columns"
164
+ :items="items"
165
+ striped
166
+ hover
167
+ bordered
168
+ />
169
+ </template>
170
+ ```
171
+
172
+ ### Custom Column Configuration
173
+
174
+ ```vue
175
+ <script setup>
176
+ const columns = [
177
+ {
178
+ key: 'id',
179
+ label: 'ID',
180
+ sortable: true,
181
+ searchable: false,
182
+ headerClass: 'bg-primary text-white'
183
+ },
184
+ {
185
+ key: 'name',
186
+ label: 'Full Name',
187
+ sortable: true
188
+ },
189
+ {
190
+ key: 'salary',
191
+ label: 'Salary',
192
+ formatter: (value) => `$${value.toLocaleString()}`,
193
+ tdStyle: { textAlign: 'right' }
194
+ },
195
+ {
196
+ key: 'status',
197
+ label: 'Status',
198
+ class: 'text-center'
199
+ }
200
+ ]
201
+ </script>
202
+
203
+ <template>
204
+ <VibeDataTable :columns="columns" :items="items" />
205
+ </template>
206
+ ```
207
+
208
+ ### With Custom Cell Rendering
209
+
210
+ ```vue
211
+ <script setup>
212
+ const columns = [
213
+ { key: 'name', label: 'Name' },
214
+ { key: 'email', label: 'Email' },
215
+ { key: 'status', label: 'Status' },
216
+ { key: 'actions', label: 'Actions', sortable: false }
217
+ ]
218
+ </script>
219
+
220
+ <template>
221
+ <VibeDataTable :columns="columns" :items="items">
222
+ <!-- Custom status column -->
223
+ <template #cell(status)="{ value }">
224
+ <VibeBadge :variant="value === 'Active' ? 'success' : 'danger'">
225
+ {{ value }}
226
+ </VibeBadge>
227
+ </template>
228
+
229
+ <!-- Custom actions column -->
230
+ <template #cell(actions)="{ item }">
231
+ <VibeButton size="sm" variant="primary" @click="editItem(item)">
232
+ Edit
233
+ </VibeButton>
234
+ <VibeButton size="sm" variant="danger" @click="deleteItem(item)">
235
+ Delete
236
+ </VibeButton>
237
+ </template>
238
+ </VibeDataTable>
239
+ </template>
240
+ ```
241
+
242
+ ### Controlled State (v-model)
243
+
244
+ ```vue
245
+ <script setup>
246
+ import { ref } from 'vue'
247
+
248
+ const currentPage = ref(1)
249
+ const perPage = ref(25)
250
+ const sortBy = ref('name')
251
+ const sortDesc = ref(false)
252
+
253
+ const handleRowClick = (item, globalIndex) => {
254
+ console.log('Clicked row:', item, globalIndex)
255
+ }
256
+ </script>
257
+
258
+ <template>
259
+ <VibeDataTable
260
+ :columns="columns"
261
+ :items="items"
262
+ row-key="id"
263
+ v-model:current-page="currentPage"
264
+ v-model:per-page="perPage"
265
+ v-model:sort-by="sortBy"
266
+ v-model:sort-desc="sortDesc"
267
+ @row-clicked="handleRowClick"
268
+ />
269
+ </template>
270
+ ```
271
+
272
+ ### Disable Features
273
+
274
+ ```vue
275
+ <template>
276
+ <!-- No search, no pagination -->
277
+ <VibeDataTable
278
+ :columns="columns"
279
+ :items="items"
280
+ :searchable="false"
281
+ :paginated="false"
282
+ />
283
+
284
+ <!-- No sorting -->
285
+ <VibeDataTable
286
+ :columns="columns"
287
+ :items="items"
288
+ :sortable="false"
289
+ />
290
+ </template>
291
+ ```
292
+
293
+ ### Custom Page Sizes
294
+
295
+ ```vue
296
+ <template>
297
+ <VibeDataTable
298
+ :columns="columns"
299
+ :items="items"
300
+ :per-page="20"
301
+ :per-page-options="[10, 20, 50, 100, 500]"
302
+ />
303
+ </template>
304
+ ```
305
+
306
+ ### Large Dataset Example
307
+
308
+ ```vue
309
+ <script setup>
310
+ import { ref } from 'vue'
311
+
312
+ // Generate large dataset
313
+ const items = ref(
314
+ Array.from({ length: 1000 }, (_, i) => ({
315
+ id: i + 1,
316
+ name: `User ${i + 1}`,
317
+ email: `user${i + 1}@example.com`,
318
+ department: ['Sales', 'Marketing', 'Engineering', 'HR'][i % 4],
319
+ salary: Math.floor(Math.random() * 100000) + 50000,
320
+ joinDate: new Date(2020 + Math.floor(Math.random() * 5), Math.floor(Math.random() * 12), 1)
321
+ .toISOString()
322
+ .split('T')[0]
323
+ }))
324
+ )
325
+
326
+ const columns = [
327
+ { key: 'id', label: 'ID', sortable: true },
328
+ { key: 'name', label: 'Name', sortable: true },
329
+ { key: 'email', label: 'Email', sortable: true },
330
+ { key: 'department', label: 'Department', sortable: true },
331
+ {
332
+ key: 'salary',
333
+ label: 'Salary',
334
+ sortable: true,
335
+ formatter: (value) => `$${value.toLocaleString()}`
336
+ },
337
+ { key: 'joinDate', label: 'Join Date', sortable: true }
338
+ ]
339
+ </script>
340
+
341
+ <template>
342
+ <VibeDataTable
343
+ :columns="columns"
344
+ :items="items"
345
+ :per-page="25"
346
+ striped
347
+ hover
348
+ small
349
+ />
350
+ </template>
351
+ ```
352
+
353
+ ### With Custom Empty State
354
+
355
+ ```vue
356
+ <template>
357
+ <VibeDataTable
358
+ :columns="columns"
359
+ :items="[]"
360
+ empty-text="No users found. Try adjusting your search."
361
+ />
362
+ </template>
363
+ ```
364
+
365
+ ## Advanced Features
366
+
367
+ ### Formatters
368
+
369
+ Use formatters to transform data before display:
370
+
371
+ ```vue
372
+ <script setup>
373
+ const columns = [
374
+ {
375
+ key: 'price',
376
+ label: 'Price',
377
+ formatter: (value) => `$${value.toFixed(2)}`
378
+ },
379
+ {
380
+ key: 'date',
381
+ label: 'Date',
382
+ formatter: (value) => new Date(value).toLocaleDateString()
383
+ },
384
+ {
385
+ key: 'percentage',
386
+ label: 'Complete',
387
+ formatter: (value) => `${value}%`
388
+ }
389
+ ]
390
+ </script>
391
+ ```
392
+
393
+ ### Accessing Full Row in Formatter
394
+
395
+ ```vue
396
+ <script setup>
397
+ const columns = [
398
+ {
399
+ key: 'fullName',
400
+ label: 'Full Name',
401
+ formatter: (value, row) => `${row.firstName} ${row.lastName}`
402
+ },
403
+ {
404
+ key: 'discount',
405
+ label: 'Discount',
406
+ formatter: (value, row) => {
407
+ return row.isPremium ? `${value}% (Premium)` : `${value}%`
408
+ }
409
+ }
410
+ ]
411
+ </script>
412
+ ```
413
+
414
+ ## Bootstrap CSS Classes
415
+
416
+ - `.table` - Base table
417
+ - `.table-striped` - Striped rows
418
+ - `.table-bordered` - Bordered table
419
+ - `.table-borderless` - Borderless table
420
+ - `.table-hover` - Hover effect
421
+ - `.table-sm` - Compact table
422
+ - `.table-{variant}` - Color variants
423
+ - `.table-responsive` - Responsive wrapper
424
+ - `.vibe-table-stack` - Mobile card view transformation
425
+ - `.pagination` - Pagination controls
426
+ - `.form-control` - Search input
427
+ - `.form-select` - Per-page selector
428
+
429
+ ## Tips
430
+
431
+ 1. **Large Datasets**: For datasets with 1000+ rows, consider server-side pagination
432
+ 2. **Stable keys**: Set the `row-key` prop to a unique field in your data for correct behavior during sorting/filtering and best reactivity
433
+ 3. **Search Debounce**: Adjust `searchDebounce` prop for performance with large datasets
434
+ 4. **Custom Styling**: Use column `class`, `headerClass`, `thStyle`, `tdStyle` for styling (style objects are sanitized to a safe property allowlist)
435
+ 5. **Slots**: Use slots for complex cell rendering (badges, buttons, images, etc.)
@@ -0,0 +1,64 @@
1
+ # VibeHero
2
+
3
+ A hero / banner section. Renders a `<section>` with consistent padding, an inner container, and content alignment — covering the Bootstrap 5.3 hero patterns (centered, two-column, dark, bordered) plus full-bleed background image / gradient heroes.
4
+
5
+ ```vue
6
+ <VibeHero variant="dark" text-variant="light">
7
+ <h1 class="display-4 fw-bold">Build faster with VibeUI</h1>
8
+ <p class="lead">A modern Vue 3 component library for Bootstrap 5.3.</p>
9
+ <VibeButton variant="primary" size="lg">Get started</VibeButton>
10
+ </VibeHero>
11
+ ```
12
+
13
+ ## Props
14
+
15
+ | Prop | Type | Default | Description |
16
+ |------|------|---------|-------------|
17
+ | `variant` | `Variant` | `undefined` | Background color → `bg-{variant}` (same vocabulary as `VibeCard`) |
18
+ | `textVariant` | `Variant` | `undefined` | Text color → `text-{variant}` |
19
+ | `border` | `Variant` | `undefined` | Adds `border border-{variant} rounded-3` (the bordered-hero pattern) |
20
+ | `align` | `'start' \| 'center' \| 'end'` | `'center'` | Content alignment → `text-{align}` |
21
+ | `fluid` | `Boolean \| ContainerType` | `false` | Inner container width (same vocabulary as `VibeContainer`) |
22
+ | `minHeight` | `String` | `undefined` | Sanitized via `safeLength`; when set, content is vertically centered |
23
+ | `bgImage` | `String` | `undefined` | Full-bleed background image URL; sanitized via `safeHref` (blocks `javascript:`/`data:`), rendered `cover`/`center` |
24
+ | `overlay` | `Boolean \| String` | `false` | Darkening layer over `bgImage` for legibility — `true` for a default dark scrim, or a CSS color (sanitized via `safeColor`) |
25
+ | `gradient` | `String` | `undefined` | CSS gradient background (e.g. `linear-gradient(135deg, #667eea, #764ba2)`); validated to `*-gradient(...)` only — no `url()`/`expression()` |
26
+ | `tag` | `Tag` | `'section'` | Root element tag |
27
+
28
+ ## Slots
29
+
30
+ | Slot | Description |
31
+ |------|-------------|
32
+ | `default` | Hero content. You supply the inner layout (a centered column, or a `VibeRow`/`VibeCol` split). |
33
+
34
+ ## Examples
35
+
36
+ **Centered (Bootstrap "centered hero")**
37
+
38
+ ```vue
39
+ <VibeHero>
40
+ <VibeCol :lg="7" class="mx-auto">
41
+ <h1 class="display-3 fw-bold">Photo Gallery</h1>
42
+ <p class="lead">Curated photography from around the world.</p>
43
+ </VibeCol>
44
+ </VibeHero>
45
+ ```
46
+
47
+ **Two-column with gradient**
48
+
49
+ ```vue
50
+ <VibeHero gradient="linear-gradient(135deg, #667eea 0%, #764ba2 100%)" align="start" class="text-white">
51
+ <VibeRow class="align-items-center">
52
+ <VibeCol :lg="6"><h1 class="display-3 fw-bold">Headline</h1></VibeCol>
53
+ <VibeCol :lg="6"><img src="/demo.png" class="img-fluid rounded-4 shadow-lg"></VibeCol>
54
+ </VibeRow>
55
+ </VibeHero>
56
+ ```
57
+
58
+ **Full-bleed image with overlay**
59
+
60
+ ```vue
61
+ <VibeHero bg-image="/banner.jpg" overlay min-height="400px" class="text-white">
62
+ <h1 class="display-3 fw-bold">Welcome</h1>
63
+ </VibeHero>
64
+ ```