@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,118 @@
1
+ # VibeFormGroup
2
+
3
+ Wrapper that owns a form control's label, help text, validation feedback, and id. It is the recommended way to make any VibeUI form control accessible.
4
+
5
+ ## How it works
6
+
7
+ `VibeFormGroup` generates a single id and provides it (plus its label/help/validation flags) to descendant controls. The **first** child control consumes the group id and renders against it; the group renders the `<label>` (linked via `for`), `help-text`, and validation feedback so the child does not duplicate them. This auto-wires `for`/`id` and `aria-describedby` with no manual ids.
8
+
9
+ ## Props
10
+
11
+ | Prop | Type | Default | Description |
12
+ |------|------|---------|-------------|
13
+ | `label` | `string` | `undefined` | Label text rendered for the first child control. |
14
+ | `labelFor` | `string` | `undefined` | Explicit id to use instead of the auto-generated one. |
15
+ | `required` | `boolean` | `false` | `true` appends a red `*` (aria-hidden) and a visually-hidden "required" span to the label. `false` (default) appends a gray "(optional)" label (aria-hidden). Omit on the child control — the group renders the indicator. |
16
+ | `validationState` | `'valid' \| 'invalid' \| null` | `null` | Render valid/invalid feedback. |
17
+ | `validationMessage` | `string` | `undefined` | Feedback message text. |
18
+ | `helpText` | `string` | `undefined` | Help text rendered below the control. |
19
+ | `floating` | `boolean` | `false` | Use Bootstrap floating-label layout (`.form-floating`). |
20
+ | `row` | `boolean` | `false` | Use a horizontal (grid row) layout. |
21
+ | `labelCols` | `number \| string` | `undefined` | Label column width (`col-sm-{n}`) in row layout. |
22
+ | `labelAlign` | `'start' \| 'center' \| 'end'` | `undefined` | Label text alignment in row layout. |
23
+
24
+ ## Events
25
+
26
+ None.
27
+
28
+ ## Slots
29
+
30
+ | Slot | Description |
31
+ |------|-------------|
32
+ | default | The form control(s) to wrap. |
33
+
34
+ ## Usage
35
+
36
+ ### Basic
37
+
38
+ ```vue
39
+ <script setup lang="ts">
40
+ import { ref } from 'vue'
41
+ const email = ref('')
42
+ </script>
43
+
44
+ <template>
45
+ <VibeFormGroup label="Email" help-text="We'll never share it.">
46
+ <VibeFormInput v-model="email" type="email" />
47
+ </VibeFormGroup>
48
+ </template>
49
+ ```
50
+
51
+ ### With validation
52
+
53
+ ```vue
54
+ <script setup lang="ts">
55
+ import { useFormValidation, validators } from '@velkymx/vibeui'
56
+
57
+ const name = useFormValidation('')
58
+ const validateName = () => name.validate([validators.required()])
59
+ </script>
60
+
61
+ <template>
62
+ <VibeFormGroup
63
+ label="Name"
64
+ required
65
+ :validation-state="name.validationState"
66
+ :validation-message="name.validationMessage"
67
+ >
68
+ <VibeFormInput v-model="name.value" @validate="validateName" />
69
+ </VibeFormGroup>
70
+ </template>
71
+ ```
72
+
73
+ ### Horizontal (row) layout
74
+
75
+ ```vue
76
+ <script setup lang="ts">
77
+ import { ref } from 'vue'
78
+ const username = ref('')
79
+ </script>
80
+
81
+ <template>
82
+ <VibeFormGroup label="Username" row :label-cols="3" label-align="end">
83
+ <VibeFormInput v-model="username" />
84
+ </VibeFormGroup>
85
+ </template>
86
+ ```
87
+
88
+ ### Floating label
89
+
90
+ ```vue
91
+ <script setup lang="ts">
92
+ import { ref } from 'vue'
93
+ const city = ref('')
94
+ </script>
95
+
96
+ <template>
97
+ <VibeFormGroup label="City" floating>
98
+ <VibeFormInput v-model="city" placeholder="City" />
99
+ </VibeFormGroup>
100
+ </template>
101
+ ```
102
+
103
+ ## Important Notes
104
+
105
+ - **Single-consumer rule:** only the first child control consumes the group id. With multiple controls (e.g. a checkbox or radio group), subsequent controls generate their own ids — the group's label still describes the set.
106
+ - **Don't double up:** when the group provides `label`, `helpText`, or validation, omit those same props on the child control; the child suppresses its own copies to avoid duplicates.
107
+ - **Floating labels** require the label to render after the control, which the group handles automatically; pair it with a `placeholder` on the input.
108
+ - **Required/optional indicator (WCAG 3.3.2):** the `required` prop renders both a visual indicator (`*` / "(optional)") and a visually-hidden text node for screen readers. The visual spans carry `aria-hidden="true"` so the screen-reader announcement comes from the hidden span, not the symbol.
109
+ - **`aria-describedby` (WCAG 1.3.1):** `helpText` and `validationMessage` elements are assigned stable ids; the child control's `aria-describedby` is wired automatically — no manual id plumbing needed.
110
+ - **Live error region (WCAG 4.1.3):** the invalid-feedback div carries `role="alert"` so new errors are announced by screen readers without requiring the user to re-focus the field.
111
+
112
+ ## Bootstrap CSS Classes
113
+
114
+ - `.mb-3`, `.row`
115
+ - `.form-floating`
116
+ - `.form-label`, `.col-form-label`, `.col-sm-{n}`, `.text-{start|center|end}`
117
+ - `.form-text`
118
+ - `.valid-feedback`, `.invalid-feedback`
@@ -0,0 +1,140 @@
1
+ # VibeFormInput
2
+
3
+ Single-line text input supporting all standard HTML input types, with built-in validation and accessibility.
4
+
5
+ ## Props
6
+
7
+ | Prop | Type | Default | Description |
8
+ |------|------|---------|-------------|
9
+ | `modelValue` | `string \| number` | `''` | The input value (v-model). Coerced to a number when `type="number"`. |
10
+ | `type` | `InputType` | `'text'` | HTML input type (`text`, `email`, `password`, `number`, `tel`, `url`, `search`, `date`, `time`, `datetime-local`, `month`, `week`, `color`). |
11
+ | `id` | `string` | auto-generated | Element id. Auto-generated, or inherited from a parent `VibeFormGroup`. |
12
+ | `label` | `string` | `undefined` | Standalone label text (omit when inside a `VibeFormGroup`). |
13
+ | `placeholder` | `string` | `undefined` | Placeholder text. |
14
+ | `disabled` | `boolean` | `false` | Disable the input. |
15
+ | `readonly` | `boolean` | `false` | Make the input read-only. |
16
+ | `required` | `boolean` | `false` | Mark as required (renders a `*` next to a standalone label). |
17
+ | `size` | `'sm' \| 'lg'` | `undefined` | Control size. |
18
+ | `validationState` | `'valid' \| 'invalid' \| null` | `null` | Visual validation state. |
19
+ | `validationMessage` | `string` | `undefined` | Feedback message shown for the current `validationState`. |
20
+ | `validationRules` | `ValidationRule[] \| ValidatorFunction` | `undefined` | Rules carried for use with a validation composable. |
21
+ | `validateOn` | `'input' \| 'blur' \| 'change'` | `'blur'` | When the `validate` event fires. |
22
+ | `helpText` | `string` | `undefined` | Help text below the input. |
23
+ | `plaintext` | `boolean` | `false` | Render as read-only plain text (`.form-control-plaintext`). |
24
+ | `noWrapper` | `boolean` | `false` | Render only the `<input>` (no wrapper/label/feedback). Use inside `VibeInputGroup`. |
25
+ | `focusRing` | `boolean` | `false` | Add the Bootstrap 5.3 `.focus-ring` helper. |
26
+ | `showToggle` | `boolean` | `false` | Show a show/hide password toggle button. Only applies when `type="password"`. |
27
+ | `showPasswordStrength` | `boolean` | `false` | Show a 4-segment strength meter and `aria-live` strength label below the input. Only applies when `type="password"`. |
28
+ | `autocomplete` | `AutocompleteType` | auto-detected | HTML `autocomplete` attribute. Auto-detected: `type="email"` → `"email"`. Set `"off"` to disable. |
29
+ | `inputmode` | `InputMode` | auto-detected | Mobile keyboard hint. Auto-detected: `number` → `decimal`, `email` → `email`, `tel` → `tel`, `url` → `url`, `search` → `search`. Override explicitly when needed. |
30
+
31
+ ## Events
32
+
33
+ | Event | Payload | Description |
34
+ |-------|---------|-------------|
35
+ | `update:modelValue` | `string \| number` | Emitted on input (number-coerced for `type="number"`). |
36
+ | `input` | `Event` | Native input event. |
37
+ | `change` | `Event` | Native change event. |
38
+ | `blur` | `FocusEvent` | Emitted on blur. |
39
+ | `focus` | `FocusEvent` | Emitted on focus. |
40
+ | `validate` | — | Emitted when the `validateOn` trigger occurs. |
41
+
42
+ ## Slots
43
+
44
+ None.
45
+
46
+ ## Usage
47
+
48
+ ### Recommended: inside a VibeFormGroup
49
+
50
+ `VibeFormGroup` generates the id, links the `<label>`, and wires `aria-describedby`, help text, and validation feedback for the first child control.
51
+
52
+ ```vue
53
+ <script setup lang="ts">
54
+ import { ref } from 'vue'
55
+ const name = ref('')
56
+ </script>
57
+
58
+ <template>
59
+ <VibeFormGroup label="Full Name" help-text="As it appears on your ID.">
60
+ <VibeFormInput v-model="name" placeholder="Jane Doe" />
61
+ </VibeFormGroup>
62
+ </template>
63
+ ```
64
+
65
+ ### With validation
66
+
67
+ ```vue
68
+ <script setup lang="ts">
69
+ import { useFormValidation, validators } from '@velkymx/vibeui'
70
+
71
+ const email = useFormValidation('')
72
+ const validateEmail = () =>
73
+ email.validate([validators.required(), validators.email()])
74
+ </script>
75
+
76
+ <template>
77
+ <VibeFormGroup
78
+ label="Email"
79
+ :validation-state="email.validationState"
80
+ :validation-message="email.validationMessage"
81
+ >
82
+ <VibeFormInput
83
+ v-model="email.value"
84
+ type="email"
85
+ @validate="validateEmail"
86
+ />
87
+ </VibeFormGroup>
88
+ </template>
89
+ ```
90
+
91
+ ### Standalone
92
+
93
+ ```vue
94
+ <script setup lang="ts">
95
+ import { ref } from 'vue'
96
+ const search = ref('')
97
+ </script>
98
+
99
+ <template>
100
+ <VibeFormInput v-model="search" label="Search" type="search" />
101
+ </template>
102
+ ```
103
+
104
+ ### Password field with toggle and strength meter
105
+
106
+ ```vue
107
+ <script setup lang="ts">
108
+ import { ref } from 'vue'
109
+ const password = ref('')
110
+ </script>
111
+
112
+ <template>
113
+ <VibeFormGroup label="Password" required>
114
+ <VibeFormInput
115
+ v-model="password"
116
+ type="password"
117
+ autocomplete="new-password"
118
+ show-toggle
119
+ show-password-strength
120
+ />
121
+ </VibeFormGroup>
122
+ </template>
123
+ ```
124
+
125
+ ## Important Notes
126
+
127
+ - **Automatic ID & label linking:** when wrapped in a `VibeFormGroup`, the first child control consumes the group id, so the group's `<label>`, help text, and feedback are linked automatically. Do not also set `label`/`helpText` on the input in that case — the group renders them.
128
+ - **Number coercion:** with `type="number"`, an empty field emits `''`; otherwise the emitted value is a `number`.
129
+ - **Plain text:** `plaintext` forces the control read-only.
130
+ - **Placeholder contrast (WCAG 1.4.3):** placeholder text is rendered at full opacity using `--bs-secondary-color`, overriding the browser-default ~0.6 alpha that drops contrast below 3:1.
131
+ - **`autocomplete` auto-detection:** the component sets `autocomplete="email"` automatically for `type="email"` inputs. For password fields, set `autocomplete="current-password"` (login) or `autocomplete="new-password"` (registration) explicitly — the component cannot infer intent from type alone.
132
+ - **`inputmode` auto-detection:** overrides only apply when the prop is not set. Pass an explicit `inputmode` to override (e.g. `inputmode="numeric"` for a 4-digit PIN field that uses `type="text"`).
133
+
134
+ ## Bootstrap CSS Classes
135
+
136
+ - `.form-control`
137
+ - `.form-control-{sm|lg}`
138
+ - `.form-control-plaintext`
139
+ - `.is-valid`, `.is-invalid`
140
+ - `.focus-ring`
@@ -0,0 +1,82 @@
1
+ # VibeFormRadio
2
+
3
+ Radio button for exclusive selection within a named group.
4
+
5
+ ## Props
6
+
7
+ | Prop | Type | Default | Description |
8
+ |------|------|---------|-------------|
9
+ | `modelValue` | `string \| number \| boolean` | `''` | Selected value shared across the group (v-model). |
10
+ | `value` | `string \| number \| boolean` | — (required) | This radio's value. |
11
+ | `name` | `string` | — (required) | Group name; all radios in a group share the same `name`. |
12
+ | `id` | `string` | auto-generated | Element id. Auto-generated, or inherited from a parent `VibeFormGroup`. |
13
+ | `label` | `string` | `undefined` | Radio label text. |
14
+ | `disabled` | `boolean` | `false` | Disable the radio. |
15
+ | `required` | `boolean` | `false` | Mark as required. |
16
+ | `inline` | `boolean` | `false` | Render inline (`.form-check-inline`). |
17
+ | `reverse` | `boolean` | `false` | Place the label before the radio (`.form-check-reverse`). |
18
+ | `validationState` | `'valid' \| 'invalid' \| null` | `null` | Visual validation state. |
19
+ | `validationMessage` | `string` | `undefined` | Feedback message for the current state. |
20
+ | `validationRules` | `ValidationRule[] \| ValidatorFunction` | `undefined` | Rules carried for use with a validation composable. |
21
+ | `validateOn` | `'change' \| 'blur'` | `'change'` | When the `validate` event fires. |
22
+ | `helpText` | `string` | `undefined` | Help text below the radio. |
23
+
24
+ ## Events
25
+
26
+ | Event | Payload | Description |
27
+ |-------|---------|-------------|
28
+ | `update:modelValue` | `string \| number \| boolean` | Emitted with this radio's `value` when selected. |
29
+ | `change` | `Event` | Native change event. |
30
+ | `blur` | `FocusEvent` | Emitted on blur. |
31
+ | `focus` | `FocusEvent` | Emitted on focus. |
32
+ | `validate` | — | Emitted when the `validateOn` trigger occurs. |
33
+
34
+ ## Slots
35
+
36
+ None.
37
+
38
+ ## Usage
39
+
40
+ ### Recommended: a group inside VibeFormGroup
41
+
42
+ ```vue
43
+ <script setup lang="ts">
44
+ import { ref } from 'vue'
45
+ const plan = ref('free')
46
+ </script>
47
+
48
+ <template>
49
+ <VibeFormGroup label="Plan">
50
+ <VibeFormRadio v-model="plan" name="plan" value="free" label="Free" />
51
+ <VibeFormRadio v-model="plan" name="plan" value="pro" label="Pro" />
52
+ <VibeFormRadio v-model="plan" name="plan" value="team" label="Team" />
53
+ </VibeFormGroup>
54
+ </template>
55
+ ```
56
+
57
+ ### Inline
58
+
59
+ ```vue
60
+ <script setup lang="ts">
61
+ import { ref } from 'vue'
62
+ const size = ref('m')
63
+ </script>
64
+
65
+ <template>
66
+ <VibeFormRadio v-model="size" name="size" value="s" label="Small" inline />
67
+ <VibeFormRadio v-model="size" name="size" value="m" label="Medium" inline />
68
+ <VibeFormRadio v-model="size" name="size" value="l" label="Large" inline />
69
+ </template>
70
+ ```
71
+
72
+ ## Important Notes
73
+
74
+ - **Shared `name`:** every radio in the same logical group must share a `name` so the browser enforces exclusivity.
75
+ - **Group linking:** the first radio in a `VibeFormGroup` consumes the group id; subsequent radios generate their own ids.
76
+
77
+ ## Bootstrap CSS Classes
78
+
79
+ - `.form-check`
80
+ - `.form-check-input`, `.form-check-label`
81
+ - `.form-check-inline`, `.form-check-reverse`
82
+ - `.is-valid`, `.is-invalid`
@@ -0,0 +1,98 @@
1
+ # VibeFormSelect
2
+
3
+ Single or multiple selection dropdown driven by an `options` array, with built-in validation and accessibility.
4
+
5
+ ## Props
6
+
7
+ | Prop | Type | Default | Description |
8
+ |------|------|---------|-------------|
9
+ | `modelValue` | `FormSelectOptionValue \| FormSelectOptionValue[]` | `''` | Selected value(s). An array when `multiple` is set. `FormSelectOptionValue` is `string \| number \| boolean \| null \| undefined`. |
10
+ | `options` | `FormSelectOption[]` | `[]` | Options to render: `{ value, text, disabled? }`. |
11
+ | `id` | `string` | auto-generated | Element id. Auto-generated, or inherited from a parent `VibeFormGroup`. |
12
+ | `label` | `string` | `undefined` | Standalone label text. |
13
+ | `multiple` | `boolean` | `false` | Allow multiple selection (model becomes an array). |
14
+ | `selectSize` | `number` | `undefined` | Number of visible rows (native `size`). |
15
+ | `htmlSize` | `number` | `undefined` | Number of visible rows (native `size`); takes precedence over `selectSize`. |
16
+ | `placeholder` | `string` | `undefined` | Disabled placeholder option (single-select only). |
17
+ | `disabled` | `boolean` | `false` | Disable the select. |
18
+ | `required` | `boolean` | `false` | Mark as required. |
19
+ | `size` | `'sm' \| 'lg'` | `undefined` | Control size (`.form-select-sm/lg`). |
20
+ | `validationState` | `'valid' \| 'invalid' \| null` | `null` | Visual validation state. |
21
+ | `validationMessage` | `string` | `undefined` | Feedback message for the current state. |
22
+ | `validationRules` | `ValidationRule[] \| ValidatorFunction` | `undefined` | Rules carried for use with a validation composable. |
23
+ | `validateOn` | `'change' \| 'blur'` | `'change'` | When the `validate` event fires. |
24
+ | `helpText` | `string` | `undefined` | Help text below the select. |
25
+
26
+ ## Events
27
+
28
+ | Event | Payload | Description |
29
+ |-------|---------|-------------|
30
+ | `update:modelValue` | `FormSelectOptionValue \| FormSelectOptionValue[]` | Emitted on selection. Array when `multiple`. |
31
+ | `change` | `Event` | Native change event. |
32
+ | `blur` | `FocusEvent` | Emitted on blur. |
33
+ | `focus` | `FocusEvent` | Emitted on focus. |
34
+ | `validate` | — | Emitted when the `validateOn` trigger occurs. |
35
+
36
+ ## Slots
37
+
38
+ | Slot | Description |
39
+ |------|-------------|
40
+ | default | Override the auto-rendered `<option>` list (provide your own `<option>` / `<optgroup>` elements). |
41
+
42
+ ## Usage
43
+
44
+ ### Recommended: inside a VibeFormGroup
45
+
46
+ ```vue
47
+ <script setup lang="ts">
48
+ import { ref } from 'vue'
49
+ import type { FormSelectOption } from '@velkymx/vibeui'
50
+
51
+ const country = ref('')
52
+ const options: FormSelectOption[] = [
53
+ { value: 'us', text: 'United States' },
54
+ { value: 'ca', text: 'Canada' },
55
+ { value: 'mx', text: 'Mexico' }
56
+ ]
57
+ </script>
58
+
59
+ <template>
60
+ <VibeFormGroup label="Country">
61
+ <VibeFormSelect v-model="country" :options="options" placeholder="Choose…" />
62
+ </VibeFormGroup>
63
+ </template>
64
+ ```
65
+
66
+ ### Multiple selection
67
+
68
+ ```vue
69
+ <script setup lang="ts">
70
+ import { ref } from 'vue'
71
+ import type { FormSelectOption } from '@velkymx/vibeui'
72
+
73
+ const tags = ref<string[]>([])
74
+ const options: FormSelectOption[] = [
75
+ { value: 'vue', text: 'Vue' },
76
+ { value: 'ts', text: 'TypeScript' },
77
+ { value: 'bs', text: 'Bootstrap' }
78
+ ]
79
+ </script>
80
+
81
+ <template>
82
+ <VibeFormGroup label="Tags">
83
+ <VibeFormSelect v-model="tags" :options="options" multiple :select-size="5" />
84
+ </VibeFormGroup>
85
+ </template>
86
+ ```
87
+
88
+ ## Important Notes
89
+
90
+ - **Non-string values preserved:** option values keep their original type (`number`, `boolean`, etc.). The component encodes options by index internally, so `v-model` round-trips the exact value — you do not have to stringify.
91
+ - **Placeholder:** only applies to single-select; it renders a disabled empty-value option.
92
+ - **Group linking:** wrapped in a `VibeFormGroup`, the select consumes the group id so the label and feedback link automatically.
93
+
94
+ ## Bootstrap CSS Classes
95
+
96
+ - `.form-select`
97
+ - `.form-select-{sm|lg}`
98
+ - `.is-valid`, `.is-invalid`
@@ -0,0 +1,94 @@
1
+ # VibeFormSpinbutton
2
+
3
+ Numeric input flanked by increment and decrement buttons, with clamping, stepping, and built-in validation.
4
+
5
+ ## Props
6
+
7
+ | Prop | Type | Default | Description |
8
+ |------|------|---------|-------------|
9
+ | `modelValue` | `number` | `0` | The numeric value (v-model). |
10
+ | `id` | `string` | auto-generated | Element id. Auto-generated, or inherited from a parent `VibeFormGroup`. |
11
+ | `label` | `string` | `undefined` | Standalone label text. |
12
+ | `disabled` | `boolean` | `false` | Disable the control. |
13
+ | `readonly` | `boolean` | `false` | Make the input read-only (buttons are also disabled). |
14
+ | `required` | `boolean` | `false` | Mark as required. |
15
+ | `min` | `number` | `undefined` | Minimum value (clamped on change/blur). |
16
+ | `max` | `number` | `undefined` | Maximum value (clamped on change/blur). |
17
+ | `step` | `number` | `1` | Increment/decrement step. Must be greater than 0. |
18
+ | `wrap` | `boolean` | `false` | Wrap from max back to min (and vice versa) at the bounds. |
19
+ | `vertical` | `boolean` | `false` | Stack the buttons vertically. |
20
+ | `size` | `'sm' \| 'lg'` | `undefined` | Control size. |
21
+ | `validationState` | `'valid' \| 'invalid' \| null` | `null` | Visual validation state. |
22
+ | `validationMessage` | `string` | `undefined` | Feedback message for the current state. |
23
+ | `validationRules` | `ValidationRule[] \| ValidatorFunction` | `undefined` | Rules carried for use with a validation composable. |
24
+ | `validateOn` | `'input' \| 'blur' \| 'change'` | `'blur'` | When the `validate` event fires from typing. |
25
+ | `helpText` | `string` | `undefined` | Help text below the control. |
26
+
27
+ ## Events
28
+
29
+ | Event | Payload | Description |
30
+ |-------|---------|-------------|
31
+ | `update:modelValue` | `number` | Emitted whenever the value changes. |
32
+ | `increment` | `number` | Emitted with the new value after the increment button is pressed. |
33
+ | `decrement` | `number` | Emitted with the new value after the decrement button is pressed. |
34
+ | `input` | `Event` | Native input event (typing). |
35
+ | `change` | `Event` | Native change event. |
36
+ | `blur` | `FocusEvent` | Emitted on blur. |
37
+ | `focus` | `FocusEvent` | Emitted on focus. |
38
+ | `validate` | — | Emitted on each button press and on the `validateOn` typing trigger. |
39
+
40
+ ## Slots
41
+
42
+ None.
43
+
44
+ ## Usage
45
+
46
+ ### Recommended: inside a VibeFormGroup
47
+
48
+ ```vue
49
+ <script setup lang="ts">
50
+ import { ref } from 'vue'
51
+ const quantity = ref(1)
52
+ </script>
53
+
54
+ <template>
55
+ <VibeFormGroup label="Quantity">
56
+ <VibeFormSpinbutton v-model="quantity" :min="1" :max="10" />
57
+ </VibeFormGroup>
58
+ </template>
59
+ ```
60
+
61
+ ### Stepping and wrapping
62
+
63
+ ```vue
64
+ <script setup lang="ts">
65
+ import { ref } from 'vue'
66
+ const rating = ref(0)
67
+ const onIncrement = (value: number) => console.log('new value', value)
68
+ </script>
69
+
70
+ <template>
71
+ <VibeFormSpinbutton
72
+ v-model="rating"
73
+ :min="0"
74
+ :max="5"
75
+ :step="0.5"
76
+ wrap
77
+ @increment="onIncrement"
78
+ />
79
+ </template>
80
+ ```
81
+
82
+ ## Important Notes
83
+
84
+ - **`step` must be greater than 0.** Decimal steps are snapped to the step's precision (e.g. `step="0.5"` keeps one decimal place).
85
+ - **Clamping:** typed values are clamped to `min`/`max` on `change` and `blur`; an empty field is treated as `0`.
86
+ - **`increment` / `decrement` payload:** both events carry the resulting numeric value, so you do not need to read `modelValue` separately.
87
+ - **Number model only:** when using a validation composable, bind to `.value` (a dev-mode warning fires if an object is passed).
88
+
89
+ ## Bootstrap CSS Classes
90
+
91
+ - `.input-group`, `.input-group-{sm|lg}`
92
+ - `.form-control`, `.form-control-{sm|lg}`
93
+ - `.btn`, `.btn-outline-secondary`
94
+ - `.is-valid`, `.is-invalid`
@@ -0,0 +1,75 @@
1
+ # VibeFormSwitch
2
+
3
+ Toggle switch for boolean values, rendered as an accessible `role="switch"` control.
4
+
5
+ ## Props
6
+
7
+ | Prop | Type | Default | Description |
8
+ |------|------|---------|-------------|
9
+ | `modelValue` | `boolean` | `false` | The toggle state (v-model). |
10
+ | `id` | `string` | auto-generated | Element id. Auto-generated, or inherited from a parent `VibeFormGroup`. |
11
+ | `label` | `string` | `undefined` | Switch label text. |
12
+ | `disabled` | `boolean` | `false` | Disable the switch. |
13
+ | `required` | `boolean` | `false` | Mark as required. |
14
+ | `inline` | `boolean` | `false` | Render inline (`.form-check-inline`). |
15
+ | `validationState` | `'valid' \| 'invalid' \| null` | `null` | Visual validation state. |
16
+ | `validationMessage` | `string` | `undefined` | Feedback message for the current state. |
17
+ | `validationRules` | `ValidationRule[] \| ValidatorFunction` | `undefined` | Rules carried for use with a validation composable. |
18
+ | `validateOn` | `'change' \| 'blur'` | `'change'` | When the `validate` event fires. |
19
+ | `helpText` | `string` | `undefined` | Help text below the switch. |
20
+
21
+ ## Events
22
+
23
+ | Event | Payload | Description |
24
+ |-------|---------|-------------|
25
+ | `update:modelValue` | `boolean` | Emitted on toggle. |
26
+ | `change` | `Event` | Native change event. |
27
+ | `blur` | `FocusEvent` | Emitted on blur. |
28
+ | `focus` | `FocusEvent` | Emitted on focus. |
29
+ | `validate` | — | Emitted when the `validateOn` trigger occurs. |
30
+
31
+ ## Slots
32
+
33
+ None.
34
+
35
+ ## Usage
36
+
37
+ ### Standalone
38
+
39
+ ```vue
40
+ <script setup lang="ts">
41
+ import { ref } from 'vue'
42
+ const notifications = ref(true)
43
+ </script>
44
+
45
+ <template>
46
+ <VibeFormSwitch v-model="notifications" label="Email notifications" />
47
+ </template>
48
+ ```
49
+
50
+ ### Inside a VibeFormGroup
51
+
52
+ ```vue
53
+ <script setup lang="ts">
54
+ import { ref } from 'vue'
55
+ const darkMode = ref(false)
56
+ </script>
57
+
58
+ <template>
59
+ <VibeFormGroup label="Appearance">
60
+ <VibeFormSwitch v-model="darkMode" label="Dark mode" />
61
+ </VibeFormGroup>
62
+ </template>
63
+ ```
64
+
65
+ ## Important Notes
66
+
67
+ - **Accessibility:** the underlying input is a checkbox with `role="switch"` and Bootstrap's `.form-switch` styling.
68
+ - **Group linking:** wrapped in a `VibeFormGroup`, the switch consumes the group id so the label and feedback link automatically.
69
+
70
+ ## Bootstrap CSS Classes
71
+
72
+ - `.form-check`, `.form-switch`
73
+ - `.form-check-input`, `.form-check-label`
74
+ - `.form-check-inline`
75
+ - `.is-valid`, `.is-invalid`