@velkymx/vibeui 0.1.1 → 0.3.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.
package/README.md CHANGED
@@ -4,11 +4,12 @@ A modern Vue 3 UI component library built with Bootstrap 5, designed to simplify
4
4
 
5
5
  ## Features
6
6
 
7
- * Vue 3 Composition API: Built from the ground up using modern, reactive Vue.js practices.
8
- * Bootstrap 5 Integration: Directly utilizes Bootstrap 5 CSS for consistency, without additional styling overhead.
9
- * Lightweight & Modular: Import only what you need, keeping your bundle small.
10
- * TypeScript Support: Fully typed components for a great developer experience.
11
- * Accessibility First: Components crafted with accessibility and usability in mind.
7
+ * **Vue 3 Composition API**: Built from the ground up using modern, reactive Vue.js practices.
8
+ * **Bootstrap 5 Integration**: Directly utilizes Bootstrap 5 CSS for consistency, without additional styling overhead.
9
+ * **Dual-Mode Components**: Use shorthand props for quick setup or composable slots for full control.
10
+ * **Lightweight & Modular**: Import only what you need, keeping your bundle small.
11
+ * **TypeScript Support**: Fully typed components for a great developer experience.
12
+ * **Accessibility First**: Components crafted with accessibility and usability in mind.
12
13
 
13
14
  ## Installation
14
15
 
@@ -55,10 +56,363 @@ const showAlert = ref(true);
55
56
  </template>
56
57
  ```
57
58
 
59
+ ## Dual-Mode Components
60
+
61
+ Many VibeUI components support two usage modes:
62
+
63
+ ### Shorthand Mode (Array-Based Props)
64
+
65
+ Perfect for quickly building UIs with data arrays:
66
+
67
+ ```vue
68
+ <template>
69
+ <VibeBreadcrumb :items="breadcrumbItems" />
70
+ <VibeNav tabs :items="navItems" />
71
+ <VibeDropdown id="menu" text="Menu" :items="dropdownItems" />
72
+ </template>
73
+
74
+ <script setup>
75
+ const breadcrumbItems = [
76
+ { text: 'Home', href: '/' },
77
+ { text: 'Products', href: '/products' },
78
+ { text: 'Details', active: true }
79
+ ]
80
+
81
+ const navItems = [
82
+ { text: 'Home', href: '#', active: true },
83
+ { text: 'Features', href: '#' },
84
+ { text: 'Pricing', href: '#' }
85
+ ]
86
+
87
+ const dropdownItems = [
88
+ { text: 'Action', href: '#' },
89
+ { text: 'Another action', href: '#' },
90
+ { divider: true },
91
+ { text: 'Separated link', href: '#' }
92
+ ]
93
+ </script>
94
+ ```
95
+
96
+ ### Composable Mode (Slot-Based)
97
+
98
+ For maximum flexibility and custom content:
99
+
100
+ ```vue
101
+ <template>
102
+ <VibeBreadcrumb>
103
+ <VibeBreadcrumbItem href="/">Home</VibeBreadcrumbItem>
104
+ <VibeBreadcrumbItem href="/products">Products</VibeBreadcrumbItem>
105
+ <VibeBreadcrumbItem active>Details</VibeBreadcrumbItem>
106
+ </VibeBreadcrumb>
107
+
108
+ <VibeNav tabs>
109
+ <VibeNavItem active href="#">Home</VibeNavItem>
110
+ <VibeNavItem href="#">Features</VibeNavItem>
111
+ <VibeNavItem href="#">Pricing</VibeNavItem>
112
+ </VibeNav>
113
+
114
+ <VibeDropdown id="menu" text="Menu">
115
+ <VibeDropdownItem href="#">Action</VibeDropdownItem>
116
+ <VibeDropdownItem href="#">Another action</VibeDropdownItem>
117
+ <VibeDropdownItem divider />
118
+ <VibeDropdownItem href="#">Separated link</VibeDropdownItem>
119
+ </VibeDropdown>
120
+ </template>
121
+ ```
122
+
123
+ Components with dual-mode support include: `VibeBreadcrumb`, `VibeNav`, `VibeNavbarNav`, `VibePagination`, `VibeListGroup`, `VibeAccordion`, `VibeDropdown`, and `VibeCarousel`.
124
+
125
+ ## Form Components with Validation
126
+
127
+ VibeUI provides comprehensive form components with built-in validation support for both front-end and API-based validation:
128
+
129
+ ### Basic Form Example
130
+
131
+ ```vue
132
+ <script setup lang="ts">
133
+ import { ref } from 'vue'
134
+ import { validators } from '@velkymx/vibeui'
135
+
136
+ const email = ref('')
137
+ const emailValidationState = ref(null)
138
+ const emailValidationMessage = ref('')
139
+
140
+ const validateEmail = async () => {
141
+ const emailRules = [validators.required(), validators.email()]
142
+
143
+ for (const rule of emailRules) {
144
+ const result = await rule.validator(email.value)
145
+ if (result !== true) {
146
+ emailValidationState.value = 'invalid'
147
+ emailValidationMessage.value = typeof result === 'string' ? result : rule.message
148
+ return
149
+ }
150
+ }
151
+
152
+ emailValidationState.value = 'valid'
153
+ emailValidationMessage.value = ''
154
+ }
155
+ </script>
156
+
157
+ <template>
158
+ <VibeFormInput
159
+ v-model="email"
160
+ id="email"
161
+ type="email"
162
+ label="Email Address"
163
+ placeholder="Enter your email"
164
+ :validation-state="emailValidationState"
165
+ :validation-message="emailValidationMessage"
166
+ @validate="validateEmail"
167
+ required
168
+ />
169
+ </template>
170
+ ```
171
+
172
+ ### Advanced Form with Composable
173
+
174
+ ```vue
175
+ <script setup lang="ts">
176
+ import { ref } from 'vue'
177
+ import { useFormValidation, validators } from '@velkymx/vibeui'
178
+
179
+ const form = {
180
+ username: useFormValidation(''),
181
+ password: useFormValidation(''),
182
+ age: useFormValidation(0),
183
+ country: useFormValidation(''),
184
+ agreeToTerms: useFormValidation(false)
185
+ }
186
+
187
+ const handleSubmit = async () => {
188
+ const usernameValid = await form.username.validate([
189
+ validators.required(),
190
+ validators.minLength(3)
191
+ ])
192
+
193
+ const passwordValid = await form.password.validate([
194
+ validators.required(),
195
+ validators.minLength(8)
196
+ ])
197
+
198
+ const ageValid = await form.age.validate([
199
+ validators.required(),
200
+ validators.min(18)
201
+ ])
202
+
203
+ if (usernameValid.valid && passwordValid.valid && ageValid.valid) {
204
+ console.log('Form is valid!')
205
+ }
206
+ }
207
+ </script>
208
+
209
+ <template>
210
+ <form @submit.prevent="handleSubmit">
211
+ <VibeFormInput
212
+ v-model="form.username.value"
213
+ id="username"
214
+ label="Username"
215
+ :validation-state="form.username.validationState"
216
+ :validation-message="form.username.validationMessage"
217
+ @validate="() => form.username.validate([validators.required(), validators.minLength(3)])"
218
+ required
219
+ />
220
+
221
+ <VibeFormInput
222
+ v-model="form.password.value"
223
+ id="password"
224
+ type="password"
225
+ label="Password"
226
+ :validation-state="form.password.validationState"
227
+ :validation-message="form.password.validationMessage"
228
+ @validate="() => form.password.validate([validators.required(), validators.minLength(8)])"
229
+ required
230
+ />
231
+
232
+ <VibeFormSpinbutton
233
+ v-model="form.age.value"
234
+ id="age"
235
+ label="Age"
236
+ :min="0"
237
+ :max="120"
238
+ :validation-state="form.age.validationState"
239
+ :validation-message="form.age.validationMessage"
240
+ @validate="() => form.age.validate([validators.required(), validators.min(18)])"
241
+ required
242
+ />
243
+
244
+ <VibeFormCheckbox
245
+ v-model="form.agreeToTerms.value"
246
+ id="terms"
247
+ label="I agree to the terms and conditions"
248
+ required
249
+ />
250
+
251
+ <VibeButton type="submit" variant="primary">Submit</VibeButton>
252
+ </form>
253
+ </template>
254
+ ```
255
+
256
+ ### API Validation Example
257
+
258
+ ```vue
259
+ <script setup lang="ts">
260
+ import { ref } from 'vue'
261
+ import { validators } from '@velkymx/vibeui'
262
+
263
+ const username = ref('')
264
+ const usernameValidationState = ref(null)
265
+ const usernameValidationMessage = ref('')
266
+
267
+ // Custom async validator for checking username availability
268
+ const checkUsernameAvailability = validators.async(async (value) => {
269
+ if (!value) return true
270
+
271
+ try {
272
+ const response = await fetch(`/api/check-username?username=${value}`)
273
+ const data = await response.json()
274
+
275
+ if (data.available) {
276
+ return true
277
+ } else {
278
+ return 'Username is already taken'
279
+ }
280
+ } catch (error) {
281
+ return 'Error checking username availability'
282
+ }
283
+ })
284
+
285
+ const validateUsername = async () => {
286
+ const rules = [
287
+ validators.required(),
288
+ validators.minLength(3),
289
+ checkUsernameAvailability
290
+ ]
291
+
292
+ usernameValidationState.value = null
293
+
294
+ for (const rule of rules) {
295
+ const result = await rule.validator(username.value)
296
+ if (result !== true) {
297
+ usernameValidationState.value = 'invalid'
298
+ usernameValidationMessage.value = typeof result === 'string' ? result : rule.message
299
+ return
300
+ }
301
+ }
302
+
303
+ usernameValidationState.value = 'valid'
304
+ usernameValidationMessage.value = 'Username is available!'
305
+ }
306
+ </script>
307
+
308
+ <template>
309
+ <VibeFormInput
310
+ v-model="username"
311
+ id="username"
312
+ label="Username"
313
+ :validation-state="usernameValidationState"
314
+ :validation-message="usernameValidationMessage"
315
+ @validate="validateUsername"
316
+ validate-on="blur"
317
+ required
318
+ />
319
+ </template>
320
+ ```
321
+
322
+ ### Available Validators
323
+
324
+ VibeUI provides built-in validators:
325
+
326
+ - `validators.required(message?)` - Field is required
327
+ - `validators.email(message?)` - Valid email format
328
+ - `validators.minLength(min, message?)` - Minimum string length
329
+ - `validators.maxLength(max, message?)` - Maximum string length
330
+ - `validators.min(min, message?)` - Minimum numeric value
331
+ - `validators.max(max, message?)` - Maximum numeric value
332
+ - `validators.pattern(regex, message?)` - Custom regex pattern
333
+ - `validators.url(message?)` - Valid URL format
334
+ - `validators.async(asyncFn)` - Custom async validator
335
+
58
336
  ## Components
59
337
 
60
- * VibeAlert
61
- * More components coming soon.
338
+ VibeUI includes all major Bootstrap 5.3 components:
339
+
340
+ ### Core Components
341
+ * **VibeAlert** - Alert messages with variants and dismissible option
342
+ * **VibeBadge** - Badges and labels with pill option
343
+ * **VibeButton** - Buttons with variants, sizes, and outline style
344
+ * **VibeButtonGroup** - Button groups with sizing and vertical layout
345
+ * **VibeCloseButton** - Close button with white variant
346
+ * **VibeSpinner** - Loading spinners (border and grow types)
347
+ * **VibePlaceholder** - Placeholder loading states with animations
348
+
349
+ ### Card Components
350
+ * **VibeCard** - Card container with variant styling
351
+ * **VibeCardHeader** - Card header section
352
+ * **VibeCardBody** - Card body section
353
+ * **VibeCardFooter** - Card footer section
354
+ * **VibeCardImg** - Card images (top, bottom, or overlay)
355
+ * **VibeCardTitle** - Card title heading
356
+ * **VibeCardText** - Card text paragraph
357
+
358
+ ### Navigation Components
359
+ * **VibeBreadcrumb** - Breadcrumb navigation container
360
+ * **VibeBreadcrumbItem** - Individual breadcrumb items
361
+ * **VibeNav** - Navigation tabs and pills
362
+ * **VibeNavItem** - Navigation items with active state
363
+ * **VibeNavbar** - Responsive navbar with variants
364
+ * **VibeNavbarBrand** - Navbar branding section
365
+ * **VibeNavbarToggle** - Navbar mobile toggle button
366
+ * **VibeNavbarNav** - Navbar navigation links container
367
+ * **VibePagination** - Pagination container
368
+ * **VibePaginationItem** - Individual pagination items
369
+
370
+ ### List Components
371
+ * **VibeListGroup** - List group container with flush and horizontal options
372
+ * **VibeListGroupItem** - List items with variants and active state
373
+
374
+ ### Progress Components
375
+ * **VibeProgress** - Progress bar container
376
+ * **VibeProgressBar** - Progress bar with variants, striped, and animated styles
377
+
378
+ ### Interactive Components
379
+ * **VibeAccordion** - Accordion container with flush option
380
+ * **VibeAccordionItem** - Collapsible accordion items
381
+ * **VibeCollapse** - Collapse component for showing/hiding content
382
+ * **VibeDropdown** - Dropdown menus with variants and directions
383
+ * **VibeDropdownItem** - Dropdown menu items, dividers, and headers
384
+ * **VibeModal** - Modal dialogs with sizes and positions
385
+ * **VibeOffcanvas** - Offcanvas sidebars with placement options
386
+ * **VibeToast** - Toast notifications with autohide
387
+ * **VibeCarousel** - Image carousels with controls and indicators
388
+ * **VibeCarouselSlide** - Individual carousel slides
389
+
390
+ ### Advanced Components
391
+ * **VibeTooltip** - Tooltips with placement options (requires Bootstrap JS)
392
+ * **VibePopover** - Popovers with title and content (requires Bootstrap JS)
393
+ * **VibeScrollspy** - Scrollspy for navigation highlighting
394
+
395
+ ### Data Components
396
+ * **VibeDataTable** - Powerful data table with search, sorting, and pagination
397
+
398
+ ### Form Components
399
+ * **VibeFormInput** - Text, email, password, number inputs with validation
400
+ * **VibeFormSelect** - Select dropdowns with single/multiple selection
401
+ * **VibeFormTextarea** - Multi-line text input with character count
402
+ * **VibeFormSpinbutton** - Number input with increment/decrement buttons
403
+ * **VibeFormDatepicker** - Date, time, and datetime input controls
404
+ * **VibeFormCheckbox** - Checkboxes with support for arrays
405
+ * **VibeFormRadio** - Radio button groups
406
+ * **VibeFormSwitch** - Toggle switches
407
+ * **VibeFormGroup** - Form group container with floating labels
408
+ * **VibeFormWysiwyg** - WYSIWYG editor with QuillJS (requires quill package)
409
+
410
+ All form components support:
411
+ - Front-end validation with built-in validators
412
+ - Async validation for API calls
413
+ - Bootstrap 5 styling and validation states
414
+ - Accessibility features
415
+ - Custom validation messages
62
416
 
63
417
  ## Contributing
64
418
 
@@ -0,0 +1 @@
1
+ .vibe-datatable[data-v-48221c7b]{width:100%}.datatable-info[data-v-48221c7b]{padding:.5rem 0;color:#6c757d}.input-group-vertical[data-v-e706d3dc]{flex-direction:column}.input-group-vertical[data-v-e706d3dc]>*{width:100%}.vibe-wysiwyg-container[data-v-2eb8f4ff]{border:1px solid #ced4da;border-radius:.375rem}.vibe-wysiwyg-container.is-valid[data-v-2eb8f4ff]{border-color:#198754}.vibe-wysiwyg-container.is-invalid[data-v-2eb8f4ff]{border-color:#dc3545}.vibe-wysiwyg-container.disabled[data-v-2eb8f4ff]{background-color:#e9ecef;opacity:.6;cursor:not-allowed}.vibe-wysiwyg-container[data-v-2eb8f4ff] .ql-container{border:none;font-size:1rem}.vibe-wysiwyg-container[data-v-2eb8f4ff] .ql-toolbar{border:none;border-bottom:1px solid #ced4da;border-top-left-radius:.375rem;border-top-right-radius:.375rem}.vibe-wysiwyg-container[data-v-2eb8f4ff] .ql-editor{min-height:150px}