@velkymx/vibeui 0.9.0 → 1.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +44 -0
- package/CLAUDE.md +48 -0
- package/README.md +222 -197
- package/dist/purify.es-1D-VntFD.mjs +679 -0
- package/dist/src/App.vue.d.ts +3 -0
- package/dist/src/components/HelloWorld.vue.d.ts +6 -0
- package/dist/src/components/VibeAccordion.vue.d.ts +89 -0
- package/dist/{components → src/components}/VibeAlert.vue.d.ts +18 -34
- package/dist/src/components/VibeAutocomplete.vue.d.ts +74 -0
- package/dist/{components → src/components}/VibeBadge.vue.d.ts +10 -18
- package/dist/src/components/VibeBreadcrumb.vue.d.ts +51 -0
- package/dist/{components → src/components}/VibeButton.vue.d.ts +13 -17
- package/dist/{components → src/components}/VibeButtonGroup.vue.d.ts +10 -18
- package/dist/{components → src/components}/VibeCard.vue.d.ts +51 -24
- package/dist/{components → src/components}/VibeCarousel.vue.d.ts +27 -49
- package/dist/src/components/VibeChartBar.vue.d.ts +61 -0
- package/dist/src/components/VibeChartLine.vue.d.ts +70 -0
- package/dist/src/components/VibeChartPie.vue.d.ts +34 -0
- package/dist/{components → src/components}/VibeCloseButton.vue.d.ts +9 -7
- package/dist/{components → src/components}/VibeCol.vue.d.ts +9 -17
- package/dist/src/components/VibeCollapse.vue.d.ts +76 -0
- package/dist/src/components/VibeContainer.vue.d.ts +36 -0
- package/dist/src/components/VibeDataTable.vue.d.ts +131 -0
- package/dist/{components → src/components}/VibeDatePicker.vue.d.ts +4 -6
- package/dist/{components → src/components}/VibeDraggable.vue.d.ts +9 -13
- package/dist/{components → src/components}/VibeDropdown.vue.d.ts +46 -43
- package/dist/{components → src/components}/VibeDroppable.vue.d.ts +9 -13
- package/dist/{components → src/components}/VibeFileInput.vue.d.ts +14 -20
- package/dist/{components → src/components}/VibeFormCheckbox.vue.d.ts +29 -21
- package/dist/{components → src/components}/VibeFormDatepicker.vue.d.ts +26 -29
- package/dist/{components → src/components}/VibeFormGroup.vue.d.ts +10 -13
- package/dist/{components → src/components}/VibeFormInput.vue.d.ts +22 -23
- package/dist/{components → src/components}/VibeFormRadio.vue.d.ts +22 -23
- package/dist/{components → src/components}/VibeFormSelect.vue.d.ts +27 -33
- package/dist/{components → src/components}/VibeFormSpinbutton.vue.d.ts +30 -33
- package/dist/{components → src/components}/VibeFormSwitch.vue.d.ts +21 -22
- package/dist/{components → src/components}/VibeFormTextarea.vue.d.ts +23 -24
- package/dist/{components → src/components}/VibeFormWysiwyg.vue.d.ts +22 -21
- package/dist/src/components/VibeHero.vue.d.ts +108 -0
- package/dist/{components → src/components}/VibeIcon.vue.d.ts +27 -7
- package/dist/{components → src/components}/VibeInputGroup.vue.d.ts +11 -13
- package/dist/{components → src/components}/VibeLink.vue.d.ts +14 -18
- package/dist/{components → src/components}/VibeListGroup.vue.d.ts +26 -22
- package/dist/{components → src/components}/VibeModal.vue.d.ts +29 -45
- package/dist/{components → src/components}/VibeNav.vue.d.ts +40 -20
- package/dist/{components → src/components}/VibeNavbar.vue.d.ts +12 -19
- package/dist/src/components/VibeNavbarBrand.vue.d.ts +34 -0
- package/dist/src/components/VibeNavbarNav.vue.d.ts +80 -0
- package/dist/{components → src/components}/VibeNavbarToggle.vue.d.ts +7 -5
- package/dist/{components → src/components}/VibeOffcanvas.vue.d.ts +28 -43
- package/dist/{components → src/components}/VibePagination.vue.d.ts +38 -29
- package/dist/{components → src/components}/VibePlaceholder.vue.d.ts +9 -17
- package/dist/src/components/VibePopover.vue.d.ts +72 -0
- package/dist/src/components/VibeProgress.vue.d.ts +37 -0
- package/dist/{components → src/components}/VibeResizable.vue.d.ts +10 -14
- package/dist/{components → src/components}/VibeRow.vue.d.ts +9 -17
- package/dist/src/components/VibeScrollspy.vue.d.ts +89 -0
- package/dist/{components → src/components}/VibeSkeleton.vue.d.ts +2 -1
- package/dist/{components → src/components}/VibeSlider.vue.d.ts +4 -5
- package/dist/src/components/VibeSortable.vue.d.ts +59 -0
- package/dist/{components → src/components}/VibeSpinner.vue.d.ts +4 -7
- package/dist/{components → src/components}/VibeStepper.vue.d.ts +32 -31
- package/dist/{components → src/components}/VibeTab.vue.d.ts +7 -11
- package/dist/src/components/VibeTabContent.vue.d.ts +56 -0
- package/dist/{components → src/components}/VibeTabs.vue.d.ts +9 -13
- package/dist/{components → src/components}/VibeToast.vue.d.ts +31 -44
- package/dist/{components → src/components}/VibeToastHost.vue.d.ts +2 -1
- package/dist/src/components/VibeTooltip.vue.d.ts +63 -0
- package/dist/src/components/chart/chartColors.d.ts +3 -0
- package/dist/src/components/chart/chartResize.d.ts +2 -0
- package/dist/src/components/chart/chartTooltip.d.ts +2 -0
- package/dist/src/components/chart/chartTypes.d.ts +6 -0
- package/dist/src/components/chart/drawBar.d.ts +5 -0
- package/dist/src/components/chart/drawLine.d.ts +18 -0
- package/dist/src/components/chart/drawPie.d.ts +4 -0
- package/dist/{components → src/components}/dndStore.d.ts +1 -0
- package/dist/{components → src/components}/index.d.ts +5 -1
- package/dist/{composables → src/composables}/useBreakpoints.d.ts +1 -0
- package/dist/{composables → src/composables}/useColorMode.d.ts +1 -1
- package/dist/src/composables/useId.d.ts +2 -0
- package/dist/{directives → src/directives}/vTooltip.d.ts +2 -3
- package/dist/src/injectionKeys.d.ts +28 -0
- package/dist/{types.d.ts → src/types.d.ts} +21 -2
- package/dist/src/utils/safeCss.d.ts +16 -0
- package/dist/src/utils/safeHref.d.ts +7 -0
- package/dist/src/utils/sanitizeHtml.d.ts +13 -0
- package/dist/vibeui.css +2 -1
- package/dist/vibeui.es.js +8269 -5855
- package/dist/vibeui.umd.js +3 -1
- package/docs/README.md +225 -0
- package/docs/components/advanced/popover.md +125 -0
- package/docs/components/advanced/scrollspy.md +106 -0
- package/docs/components/advanced/tooltip.md +90 -0
- package/docs/components/card/card.md +223 -0
- package/docs/components/charts/chart-bar.md +129 -0
- package/docs/components/charts/chart-line.md +136 -0
- package/docs/components/charts/chart-pie.md +102 -0
- package/docs/components/core/alert.md +94 -0
- package/docs/components/core/badge.md +75 -0
- package/docs/components/core/button-group.md +99 -0
- package/docs/components/core/button.md +127 -0
- package/docs/components/core/close-button.md +82 -0
- package/docs/components/core/link.md +79 -0
- package/docs/components/core/placeholder.md +129 -0
- package/docs/components/core/skeleton.md +40 -0
- package/docs/components/core/spinner.md +103 -0
- package/docs/components/data/datatable.md +435 -0
- package/docs/components/hero/hero.md +64 -0
- package/docs/components/interactive/accordion.md +121 -0
- package/docs/components/interactive/carousel.md +112 -0
- package/docs/components/interactive/collapse.md +106 -0
- package/docs/components/interactive/date-picker.md +78 -0
- package/docs/components/interactive/draggable.md +91 -0
- package/docs/components/interactive/dropdown.md +129 -0
- package/docs/components/interactive/modal.md +143 -0
- package/docs/components/interactive/offcanvas.md +92 -0
- package/docs/components/interactive/resizable.md +73 -0
- package/docs/components/interactive/slider.md +57 -0
- package/docs/components/interactive/sortable.md +52 -0
- package/docs/components/interactive/stepper.md +83 -0
- package/docs/components/interactive/tabs.md +66 -0
- package/docs/components/interactive/toast.md +177 -0
- package/docs/components/layout/col.md +117 -0
- package/docs/components/layout/container.md +53 -0
- package/docs/components/layout/row.md +107 -0
- package/docs/components/list/list-group.md +225 -0
- package/docs/components/navigation/breadcrumb.md +120 -0
- package/docs/components/navigation/nav.md +151 -0
- package/docs/components/navigation/navbar.md +108 -0
- package/docs/components/navigation/pagination.md +162 -0
- package/docs/components/progress/progress.md +188 -0
- package/docs/composables/back-button.md +28 -0
- package/docs/composables/breakpoints.md +54 -0
- package/docs/composables/color-mode.md +179 -0
- package/docs/composables/use-form.md +78 -0
- package/docs/composables/use-position.md +68 -0
- package/docs/composables/use-toast.md +91 -0
- package/docs/directives/v-tooltip.md +58 -0
- package/docs/forms/README.md +87 -0
- package/docs/forms/autocomplete.md +96 -0
- package/docs/forms/file-input.md +97 -0
- package/docs/forms/form-checkbox.md +100 -0
- package/docs/forms/form-datepicker.md +80 -0
- package/docs/forms/form-group.md +115 -0
- package/docs/forms/form-input.md +112 -0
- package/docs/forms/form-radio.md +82 -0
- package/docs/forms/form-select.md +98 -0
- package/docs/forms/form-spinbutton.md +94 -0
- package/docs/forms/form-switch.md +75 -0
- package/docs/forms/form-textarea.md +82 -0
- package/docs/forms/form-wysiwyg.md +99 -0
- package/docs/forms/input-group.md +70 -0
- package/docs/forms/validation.md +213 -0
- package/docs/getting-started/starter-template.md +136 -0
- package/docs/superpowers/plans/2026-05-12-vibe-charts.md +1999 -0
- package/docs/superpowers/plans/2026-05-29-e2e-browser-testing.md +615 -0
- package/docs/superpowers/specs/2026-05-12-charting-design.md +185 -0
- package/docs/superpowers/specs/2026-05-29-e2e-browser-testing-design.md +168 -0
- package/docs/utilities/position.md +82 -0
- package/docs/versioning.md +57 -0
- package/examples/README.md +201 -0
- package/examples/album.html +262 -0
- package/examples/blog.html +166 -0
- package/examples/carousel.html +114 -0
- package/examples/checkout.html +275 -0
- package/examples/cover.html +89 -0
- package/examples/dashboard.html +156 -0
- package/examples/index.html +129 -0
- package/examples/jumbotron.html +56 -0
- package/examples/mobile-dashboard.html +138 -0
- package/examples/pricing.html +172 -0
- package/examples/product.html +145 -0
- package/examples/sidebars.html +166 -0
- package/examples/sign-in.html +119 -0
- package/examples/starter.html +314 -0
- package/examples/sticky-footer-navbar.html +70 -0
- package/examples/sticky-footer.html +60 -0
- package/examples/test-simple.html +91 -0
- package/llms.txt +782 -0
- package/package.json +44 -14
- package/dist/App.vue.d.ts +0 -2
- package/dist/components/HelloWorld.vue.d.ts +0 -5
- package/dist/components/VibeAccordion.vue.d.ts +0 -90
- package/dist/components/VibeAutocomplete.vue.d.ts +0 -46
- package/dist/components/VibeBreadcrumb.vue.d.ts +0 -47
- package/dist/components/VibeCollapse.vue.d.ts +0 -84
- package/dist/components/VibeContainer.vue.d.ts +0 -44
- package/dist/components/VibeDataTable.vue.d.ts +0 -76
- package/dist/components/VibeNavbarBrand.vue.d.ts +0 -42
- package/dist/components/VibeNavbarNav.vue.d.ts +0 -61
- package/dist/components/VibePopover.vue.d.ts +0 -95
- package/dist/components/VibeProgress.vue.d.ts +0 -45
- package/dist/components/VibeScrollspy.vue.d.ts +0 -77
- package/dist/components/VibeSortable.vue.d.ts +0 -40
- package/dist/components/VibeTabContent.vue.d.ts +0 -74
- package/dist/components/VibeTooltip.vue.d.ts +0 -86
- package/dist/composables/useId.d.ts +0 -5
- package/dist/types/index.d.ts +0 -6
- /package/dist/{composables → src/composables}/useBackButton.d.ts +0 -0
- /package/dist/{composables → src/composables}/useForm.d.ts +0 -0
- /package/dist/{composables → src/composables}/useFormValidation.d.ts +0 -0
- /package/dist/{composables → src/composables}/usePosition.d.ts +0 -0
- /package/dist/{composables → src/composables}/useToast.d.ts +0 -0
- /package/dist/{index.d.ts → src/index.d.ts} +0 -0
- /package/dist/{main.d.ts → src/main.d.ts} +0 -0
|
@@ -0,0 +1,112 @@
|
|
|
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
|
+
|
|
27
|
+
## Events
|
|
28
|
+
|
|
29
|
+
| Event | Payload | Description |
|
|
30
|
+
|-------|---------|-------------|
|
|
31
|
+
| `update:modelValue` | `string \| number` | Emitted on input (number-coerced for `type="number"`). |
|
|
32
|
+
| `input` | `Event` | Native input event. |
|
|
33
|
+
| `change` | `Event` | Native change event. |
|
|
34
|
+
| `blur` | `FocusEvent` | Emitted on blur. |
|
|
35
|
+
| `focus` | `FocusEvent` | Emitted on focus. |
|
|
36
|
+
| `validate` | — | Emitted when the `validateOn` trigger occurs. |
|
|
37
|
+
|
|
38
|
+
## Slots
|
|
39
|
+
|
|
40
|
+
None.
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
### Recommended: inside a VibeFormGroup
|
|
45
|
+
|
|
46
|
+
`VibeFormGroup` generates the id, links the `<label>`, and wires `aria-describedby`, help text, and validation feedback for the first child control.
|
|
47
|
+
|
|
48
|
+
```vue
|
|
49
|
+
<script setup lang="ts">
|
|
50
|
+
import { ref } from 'vue'
|
|
51
|
+
const name = ref('')
|
|
52
|
+
</script>
|
|
53
|
+
|
|
54
|
+
<template>
|
|
55
|
+
<VibeFormGroup label="Full Name" help-text="As it appears on your ID.">
|
|
56
|
+
<VibeFormInput v-model="name" placeholder="Jane Doe" />
|
|
57
|
+
</VibeFormGroup>
|
|
58
|
+
</template>
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### With validation
|
|
62
|
+
|
|
63
|
+
```vue
|
|
64
|
+
<script setup lang="ts">
|
|
65
|
+
import { useFormValidation, validators } from '@velkymx/vibeui'
|
|
66
|
+
|
|
67
|
+
const email = useFormValidation('')
|
|
68
|
+
const validateEmail = () =>
|
|
69
|
+
email.validate([validators.required(), validators.email()])
|
|
70
|
+
</script>
|
|
71
|
+
|
|
72
|
+
<template>
|
|
73
|
+
<VibeFormGroup
|
|
74
|
+
label="Email"
|
|
75
|
+
:validation-state="email.validationState"
|
|
76
|
+
:validation-message="email.validationMessage"
|
|
77
|
+
>
|
|
78
|
+
<VibeFormInput
|
|
79
|
+
v-model="email.value"
|
|
80
|
+
type="email"
|
|
81
|
+
@validate="validateEmail"
|
|
82
|
+
/>
|
|
83
|
+
</VibeFormGroup>
|
|
84
|
+
</template>
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Standalone
|
|
88
|
+
|
|
89
|
+
```vue
|
|
90
|
+
<script setup lang="ts">
|
|
91
|
+
import { ref } from 'vue'
|
|
92
|
+
const search = ref('')
|
|
93
|
+
</script>
|
|
94
|
+
|
|
95
|
+
<template>
|
|
96
|
+
<VibeFormInput v-model="search" label="Search" type="search" />
|
|
97
|
+
</template>
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
## Important Notes
|
|
101
|
+
|
|
102
|
+
- **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.
|
|
103
|
+
- **Number coercion:** with `type="number"`, an empty field emits `''`; otherwise the emitted value is a `number`.
|
|
104
|
+
- **Plain text:** `plaintext` forces the control read-only.
|
|
105
|
+
|
|
106
|
+
## Bootstrap CSS Classes
|
|
107
|
+
|
|
108
|
+
- `.form-control`
|
|
109
|
+
- `.form-control-{sm|lg}`
|
|
110
|
+
- `.form-control-plaintext`
|
|
111
|
+
- `.is-valid`, `.is-invalid`
|
|
112
|
+
- `.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`
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# VibeFormTextarea
|
|
2
|
+
|
|
3
|
+
Multi-line text input with optional character counting, built-in validation, and accessibility.
|
|
4
|
+
|
|
5
|
+
## Props
|
|
6
|
+
|
|
7
|
+
| Prop | Type | Default | Description |
|
|
8
|
+
|------|------|---------|-------------|
|
|
9
|
+
| `modelValue` | `string` | `''` | The textarea 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
|
+
| `placeholder` | `string` | `undefined` | Placeholder text. |
|
|
13
|
+
| `rows` | `number \| string` | `3` | Number of visible text rows. |
|
|
14
|
+
| `maxlength` | `number \| string` | `undefined` | Maximum character count (also shown in the counter when `showCharCount` is set). |
|
|
15
|
+
| `disabled` | `boolean` | `false` | Disable the textarea. |
|
|
16
|
+
| `readonly` | `boolean` | `false` | Make the textarea read-only. |
|
|
17
|
+
| `required` | `boolean` | `false` | Mark as required. |
|
|
18
|
+
| `size` | `'sm' \| 'lg'` | `undefined` | Control size. |
|
|
19
|
+
| `validationState` | `'valid' \| 'invalid' \| null` | `null` | Visual validation state. |
|
|
20
|
+
| `validationMessage` | `string` | `undefined` | Feedback message for the current state. |
|
|
21
|
+
| `validationRules` | `ValidationRule[] \| ValidatorFunction` | `undefined` | Rules carried for use with a validation composable. |
|
|
22
|
+
| `validateOn` | `'input' \| 'blur' \| 'change'` | `'blur'` | When the `validate` event fires. |
|
|
23
|
+
| `helpText` | `string` | `undefined` | Help text below the textarea. |
|
|
24
|
+
| `noResize` | `boolean` | `false` | Disable manual resizing (`resize: none`). |
|
|
25
|
+
| `showCharCount` | `boolean` | `false` | Show a character counter (`count` or `count / maxlength`). |
|
|
26
|
+
|
|
27
|
+
## Events
|
|
28
|
+
|
|
29
|
+
| Event | Payload | Description |
|
|
30
|
+
|-------|---------|-------------|
|
|
31
|
+
| `update:modelValue` | `string` | Emitted on input. |
|
|
32
|
+
| `input` | `Event` | Native input event. |
|
|
33
|
+
| `change` | `Event` | Native change event. |
|
|
34
|
+
| `blur` | `FocusEvent` | Emitted on blur. |
|
|
35
|
+
| `focus` | `FocusEvent` | Emitted on focus. |
|
|
36
|
+
| `validate` | — | Emitted when the `validateOn` trigger occurs. |
|
|
37
|
+
|
|
38
|
+
## Slots
|
|
39
|
+
|
|
40
|
+
None.
|
|
41
|
+
|
|
42
|
+
## Usage
|
|
43
|
+
|
|
44
|
+
### Recommended: inside a VibeFormGroup
|
|
45
|
+
|
|
46
|
+
```vue
|
|
47
|
+
<script setup lang="ts">
|
|
48
|
+
import { ref } from 'vue'
|
|
49
|
+
const bio = ref('')
|
|
50
|
+
</script>
|
|
51
|
+
|
|
52
|
+
<template>
|
|
53
|
+
<VibeFormGroup label="Bio">
|
|
54
|
+
<VibeFormTextarea v-model="bio" :rows="5" :maxlength="280" show-char-count />
|
|
55
|
+
</VibeFormGroup>
|
|
56
|
+
</template>
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
### Standalone
|
|
60
|
+
|
|
61
|
+
```vue
|
|
62
|
+
<script setup lang="ts">
|
|
63
|
+
import { ref } from 'vue'
|
|
64
|
+
const notes = ref('')
|
|
65
|
+
</script>
|
|
66
|
+
|
|
67
|
+
<template>
|
|
68
|
+
<VibeFormTextarea v-model="notes" label="Notes" no-resize />
|
|
69
|
+
</template>
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
## Important Notes
|
|
73
|
+
|
|
74
|
+
- **Character counter:** `showCharCount` renders inside the help-text row. When inside a `VibeFormGroup` that provides its own help text, the counter is suppressed (the group owns help rendering).
|
|
75
|
+
- **Group linking:** wrapped in a `VibeFormGroup`, the textarea consumes the group id so the label and feedback link automatically.
|
|
76
|
+
|
|
77
|
+
## Bootstrap CSS Classes
|
|
78
|
+
|
|
79
|
+
- `.form-control`
|
|
80
|
+
- `.form-control-{sm|lg}`
|
|
81
|
+
- `.is-valid`, `.is-invalid`
|
|
82
|
+
- `.form-text`
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
# VibeFormWysiwyg
|
|
2
|
+
|
|
3
|
+
Rich-text editor powered by Quill. HTML is sanitized with DOMPurify on the way in and on the way out (XSS defense-in-depth).
|
|
4
|
+
|
|
5
|
+
## Peer dependencies
|
|
6
|
+
|
|
7
|
+
This component requires two optional peers — install both:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
npm install quill dompurify
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Quill and DOMPurify are loaded lazily on mount. If `quill` is missing, the component shows a warning alert and emits a `component-error` event instead of crashing.
|
|
14
|
+
|
|
15
|
+
## Props
|
|
16
|
+
|
|
17
|
+
| Prop | Type | Default | Description |
|
|
18
|
+
|------|------|---------|-------------|
|
|
19
|
+
| `modelValue` | `string` | `''` | HTML content (v-model). Sanitized with DOMPurify before being rendered. |
|
|
20
|
+
| `id` | `string` | auto-generated | Element id. Auto-generated, or inherited from a parent `VibeFormGroup`. |
|
|
21
|
+
| `label` | `string` | `undefined` | Label text. |
|
|
22
|
+
| `placeholder` | `string` | `'Write something...'` | Placeholder shown when empty. |
|
|
23
|
+
| `disabled` | `boolean` | `false` | Disable editing. |
|
|
24
|
+
| `readonly` | `boolean` | `false` | Make the editor read-only. |
|
|
25
|
+
| `required` | `boolean` | `false` | Mark as required. |
|
|
26
|
+
| `theme` | `'snow' \| 'bubble'` | `'snow'` | Quill theme. |
|
|
27
|
+
| `toolbar` | `unknown[] \| string \| boolean` | `undefined` | Toolbar config: a Quill toolbar array, a preset name (`'minimal'`, `'standard'`, `'full'`), `false` to hide, or omit for the default toolbar. |
|
|
28
|
+
| `mobileToolbar` | `unknown[] \| string \| boolean` | `undefined` | Toolbar used at mobile breakpoints (same value forms as `toolbar`). |
|
|
29
|
+
| `height` | `string` | `'200px'` | Minimum editor height. Must be a valid CSS length; invalid values fall back to `200px`. |
|
|
30
|
+
| `validationState` | `'valid' \| 'invalid' \| null` | `null` | Visual validation state. |
|
|
31
|
+
| `validationMessage` | `string` | `undefined` | Feedback message for the current state. |
|
|
32
|
+
| `validationRules` | `ValidationRule[] \| ValidatorFunction` | `undefined` | Rules carried for use with a validation composable. |
|
|
33
|
+
| `validateOn` | `'change' \| 'blur'` | `'blur'` | When the `validate` event fires. |
|
|
34
|
+
| `helpText` | `string` | `undefined` | Help text below the editor. |
|
|
35
|
+
|
|
36
|
+
## Events
|
|
37
|
+
|
|
38
|
+
| Event | Payload | Description |
|
|
39
|
+
|-------|---------|-------------|
|
|
40
|
+
| `update:modelValue` | `string` | Emitted with sanitized HTML as content changes. |
|
|
41
|
+
| `change` | — | Emitted on content change. |
|
|
42
|
+
| `blur` | — | Emitted on blur. |
|
|
43
|
+
| `focus` | — | Emitted on focus. |
|
|
44
|
+
| `validate` | — | Emitted when the `validateOn` trigger occurs. |
|
|
45
|
+
| `ready` | `unknown` | Emitted with the Quill instance once initialized. |
|
|
46
|
+
| `component-error` | `ComponentError` | Emitted if Quill fails to load (e.g. peer not installed). |
|
|
47
|
+
|
|
48
|
+
## Slots
|
|
49
|
+
|
|
50
|
+
None.
|
|
51
|
+
|
|
52
|
+
## Usage
|
|
53
|
+
|
|
54
|
+
### Recommended: inside a VibeFormGroup
|
|
55
|
+
|
|
56
|
+
```vue
|
|
57
|
+
<script setup lang="ts">
|
|
58
|
+
import { ref } from 'vue'
|
|
59
|
+
const content = ref('<p>Hello <strong>world</strong></p>')
|
|
60
|
+
</script>
|
|
61
|
+
|
|
62
|
+
<template>
|
|
63
|
+
<VibeFormGroup label="Description">
|
|
64
|
+
<VibeFormWysiwyg v-model="content" toolbar="standard" height="300px" />
|
|
65
|
+
</VibeFormGroup>
|
|
66
|
+
</template>
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### Handling a missing peer
|
|
70
|
+
|
|
71
|
+
```vue
|
|
72
|
+
<script setup lang="ts">
|
|
73
|
+
import { ref } from 'vue'
|
|
74
|
+
import type { ComponentError } from '@velkymx/vibeui'
|
|
75
|
+
|
|
76
|
+
const content = ref('')
|
|
77
|
+
const onError = (err: ComponentError) => console.error(err.message)
|
|
78
|
+
</script>
|
|
79
|
+
|
|
80
|
+
<template>
|
|
81
|
+
<VibeFormWysiwyg v-model="content" @component-error="onError" />
|
|
82
|
+
</template>
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
## Important Notes
|
|
86
|
+
|
|
87
|
+
- **Sanitization:** incoming `modelValue` HTML is sanitized before it is rendered, and the emitted HTML is sanitized too. Unsafe tags and attributes (e.g. `<script>`, inline event handlers) are stripped. Do not rely on the editor to preserve dangerous markup.
|
|
88
|
+
- **Both peers required:** `dompurify` is needed for sanitization and `quill` for the editor; install them together.
|
|
89
|
+
- **`height` is validated:** only CSS length values are accepted; anything else falls back to `200px`.
|
|
90
|
+
- **Responsive toolbar:** at mobile breakpoints `mobileToolbar` (or a compact default) is used, and the editor re-initializes while preserving content.
|
|
91
|
+
- **Group linking:** wrapped in a `VibeFormGroup`, the editor consumes the group id so the label and feedback link automatically.
|
|
92
|
+
|
|
93
|
+
## Bootstrap CSS Classes
|
|
94
|
+
|
|
95
|
+
- `.form-label`, `.form-text`
|
|
96
|
+
- `.alert`, `.alert-warning` (load-failure message)
|
|
97
|
+
- `.valid-feedback`, `.invalid-feedback`
|
|
98
|
+
|
|
99
|
+
The editor shell uses VibeUI's own `.vibe-wysiwyg-container` class plus Quill's `.ql-*` classes.
|