@fastkit/vui 0.20.0 → 0.20.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +932 -1
  2. package/package.json +13 -13
package/README.md CHANGED
@@ -1,4 +1,935 @@
1
+
1
2
  # @fastkit/vui
2
3
 
4
+ 🌐 English | [日本語](https://github.com/dadajam4/fastkit/blob/main/packages/vui/README-ja.md)
5
+
6
+ A simple and extensible UI component library for Vue.js 3 applications. Focused on full TypeScript support, color theme system, accessibility, and tight integration with @fastkit/vue-form-control.
7
+
8
+ ## Features
9
+
10
+ - **45+ UI Components**: Comprehensive component set including buttons, forms, navigation, data display
11
+ - **Integrated Ecosystem**: 20+ @fastkit packages with unified API
12
+ - **Full TypeScript Support**: Type-safe props, events, and slot definitions
13
+ - **Composition API Design**: Full adoption of Vue 3 modern patterns
14
+ - **Color Theme System**: Flexible theming with CSS Variables foundation
15
+ - **Form Integration**: Seamless integration with @fastkit/vue-form-control
16
+ - **Accessibility**: WAI-ARIA compliant, keyboard navigation support
17
+ - **Responsive Design**: Mobile-first grid system
18
+ - **Internationalization**: Multi-language font settings, RTL language support
19
+ - **Programmatic UI**: Imperative operations for dialogs, notifications, etc.
20
+
21
+ ## Installation
22
+
23
+ ```bash
24
+ npm install @fastkit/vui
25
+ # or
26
+ pnpm add @fastkit/vui
27
+ ```
28
+
29
+ ## Basic Usage
30
+
31
+ ### Plugin Setup
32
+
33
+ ```typescript
34
+ import { createApp } from 'vue';
35
+ import { VuiPlugin } from '@fastkit/vui';
36
+ import { createRouter } from 'vue-router';
37
+
38
+ const app = createApp(App);
39
+ const router = createRouter(/* routes */);
40
+
41
+ // Install VUI plugin
42
+ app.use(VuiPlugin, {
43
+ router,
44
+ colorScheme: {
45
+ // Color theme settings
46
+ primary: '#1976d2',
47
+ secondary: '#424242'
48
+ },
49
+ uiSettings: {
50
+ primaryScope: 'primary',
51
+ buttonDefault: {
52
+ color: 'primary',
53
+ variant: 'contained'
54
+ }
55
+ }
56
+ });
57
+ ```
58
+
59
+ ### Application Setup
60
+
61
+ ```vue
62
+ <template>
63
+ <VApp>
64
+ <!-- Application content -->
65
+ <router-view />
66
+ </VApp>
67
+ </template>
68
+
69
+ <script setup lang="ts">
70
+ import { VApp } from '@fastkit/vui';
71
+ </script>
72
+ ```
73
+
74
+ ## Component List
75
+
76
+ ### Layout & Structure
77
+
78
+ - **VApp** - Application root container
79
+ - **VGrid** (`VGridContainer`, `VGridItem`) - Responsive grid system
80
+ - **VPaper** - Material Design-style paper container
81
+ - **VCard** (`VCardContent`, `VCardActions`) - Card layout
82
+ - **VToolbar** (`VToolbarTitle`, `VToolbarMenu`, `VToolbarEdge`) - Toolbar
83
+
84
+ ### Navigation
85
+
86
+ - **VNavigation**, **VNavigationItem** - Side navigation
87
+ - **VBreadcrumbs** - Breadcrumb navigation
88
+ - **VTabs**, **VTab** - Tab interface
89
+ - **VPagination** - Pagination
90
+
91
+ ### Form Controls
92
+
93
+ - **VButton**, **VButtonGroup** - Button and button group
94
+ - **VTextField** - Text input field
95
+ - **VTextarea** - Multi-line text input
96
+ - **VNumberField** - Number input field
97
+ - **VSelect** - Select dropdown
98
+ - **VCheckbox**, **VCheckboxGroup** - Checkbox
99
+ - **VRadio**, **VRadioGroup** - Radio button
100
+ - **VSwitch**, **VSwitchGroup** - Switch toggle
101
+ - **VOption**, **VOptionGroup** - Option element
102
+
103
+ ### Data Display
104
+
105
+ - **VDataTable** - Data table
106
+ - **VListTile** - List item
107
+ - **VAvatar** - User avatar
108
+ - **VChip** - Chip/tag element
109
+ - **VIcon** - Icon display
110
+
111
+ ### Feedback & Interaction
112
+
113
+ - **VDialog** - Modal dialog
114
+ - **VSnackbar** - Notification snackbar
115
+ - **VTooltip** - Tooltip
116
+ - **VMenu** - Context menu
117
+ - **VSheetModal** - Sheet modal
118
+
119
+ ### Others
120
+
121
+ - **VSkeltonLoader** - Skeleton loading
122
+ - **VBusyImage** - Lazy loading image
123
+ - **VHero** - Hero section
124
+ - **VContentSwitcher** - Content switcher
125
+
126
+ ## Usage Examples
127
+
128
+ ### Button Components
129
+
130
+ ```vue
131
+ <template>
132
+ <div>
133
+ <!-- Basic button -->
134
+ <VButton @click="handleClick">Click</VButton>
135
+
136
+ <!-- Primary button -->
137
+ <VButton color="primary" variant="contained">
138
+ Save
139
+ </VButton>
140
+
141
+ <!-- Button with icon -->
142
+ <VButton
143
+ startIcon="mdi-search"
144
+ color="primary"
145
+ variant="outlined"
146
+ :loading="searching"
147
+ @click="handleSearch"
148
+ >
149
+ Search
150
+ </VButton>
151
+
152
+ <!-- Button group -->
153
+ <VButtonGroup>
154
+ <VButton>Left</VButton>
155
+ <VButton>Center</VButton>
156
+ <VButton>Right</VButton>
157
+ </VButtonGroup>
158
+ </div>
159
+ </template>
160
+
161
+ <script setup lang="ts">
162
+ import { ref } from 'vue';
163
+ import { VButton, VButtonGroup } from '@fastkit/vui';
164
+
165
+ const searching = ref(false);
166
+
167
+ const handleClick = () => {
168
+ console.log('Button clicked');
169
+ };
170
+
171
+ const handleSearch = async () => {
172
+ searching.value = true;
173
+ try {
174
+ // Search processing
175
+ await performSearch();
176
+ } finally {
177
+ searching.value = false;
178
+ }
179
+ };
180
+ </script>
181
+ ```
182
+
183
+ ### Form Components
184
+
185
+ ```vue
186
+ <template>
187
+ <VCard>
188
+ <VCardContent>
189
+ <h2>User Registration</h2>
190
+
191
+ <!-- Text input -->
192
+ <VTextField
193
+ v-model="form.name.value"
194
+ label="Name"
195
+ required
196
+ :rules="[required(), minLength(2)]"
197
+ :invalid="form.name.invalid"
198
+ :error-message="form.name.errorMessage"
199
+ />
200
+
201
+ <!-- Email input -->
202
+ <VTextField
203
+ v-model="form.email.value"
204
+ label="Email Address"
205
+ type="email"
206
+ required
207
+ :rules="[required(), email()]"
208
+ :invalid="form.email.invalid"
209
+ :error-message="form.email.errorMessage"
210
+ />
211
+
212
+ <!-- Select -->
213
+ <VSelect
214
+ v-model="form.category.value"
215
+ label="Category"
216
+ :items="categories"
217
+ placeholder="Select category"
218
+ required
219
+ />
220
+
221
+ <!-- Checkbox -->
222
+ <VCheckbox
223
+ v-model="form.agreement.value"
224
+ :rules="[required()]"
225
+ >
226
+ I agree to the terms of use
227
+ </VCheckbox>
228
+ </VCardContent>
229
+
230
+ <VCardActions>
231
+ <VButton
232
+ color="primary"
233
+ variant="contained"
234
+ :disabled="form.invalid"
235
+ @click="handleSubmit"
236
+ >
237
+ Register
238
+ </VButton>
239
+ <VButton variant="text" @click="handleCancel">
240
+ Cancel
241
+ </VButton>
242
+ </VCardActions>
243
+ </VCard>
244
+ </template>
245
+
246
+ <script setup lang="ts">
247
+ import {
248
+ VCard, VCardContent, VCardActions,
249
+ VTextField, VSelect, VCheckbox, VButton
250
+ } from '@fastkit/vui';
251
+ import { useForm } from '@fastkit/vue-form-control';
252
+ import { required, email, minLength } from '@fastkit/rules';
253
+
254
+ const categories = [
255
+ { value: 'personal', label: 'Personal' },
256
+ { value: 'business', label: 'Business' },
257
+ { value: 'education', label: 'Education' }
258
+ ];
259
+
260
+ const form = useForm({
261
+ name: {
262
+ value: '',
263
+ rules: [required(), minLength(2)]
264
+ },
265
+ email: {
266
+ value: '',
267
+ rules: [required(), email()]
268
+ },
269
+ category: {
270
+ value: '',
271
+ rules: [required()]
272
+ },
273
+ agreement: {
274
+ value: false,
275
+ rules: [required()]
276
+ }
277
+ }, {
278
+ onSubmit: async (values) => {
279
+ console.log('Form submitted:', values);
280
+ await api.register(values);
281
+ }
282
+ });
283
+
284
+ const handleSubmit = () => {
285
+ form.submit();
286
+ };
287
+
288
+ const handleCancel = () => {
289
+ form.reset();
290
+ };
291
+ </script>
292
+ ```
293
+
294
+ ### Data Table
295
+
296
+ ```vue
297
+ <template>
298
+ <VDataTable
299
+ :items="users"
300
+ :headers="headers"
301
+ :loading="loading"
302
+ item-key="id"
303
+ selectable
304
+ @select="handleSelect"
305
+ >
306
+ <!-- Custom column -->
307
+ <template #item.status="{ item }">
308
+ <VChip
309
+ :color="item.status === 'active' ? 'success' : 'warning'"
310
+ size="sm"
311
+ >
312
+ {{ item.status === 'active' ? 'Active' : 'Inactive' }}
313
+ </VChip>
314
+ </template>
315
+
316
+ <template #item.actions="{ item }">
317
+ <VButton size="sm" variant="text" @click="editUser(item)">
318
+ Edit
319
+ </VButton>
320
+ <VButton
321
+ size="sm"
322
+ variant="text"
323
+ color="error"
324
+ @click="deleteUser(item)"
325
+ >
326
+ Delete
327
+ </VButton>
328
+ </template>
329
+ </VDataTable>
330
+ </template>
331
+
332
+ <script setup lang="ts">
333
+ import { ref } from 'vue';
334
+ import { VDataTable, VChip, VButton } from '@fastkit/vui';
335
+
336
+ const loading = ref(false);
337
+ const users = ref([
338
+ { id: 1, name: 'John Tanaka', email: 'tanaka@example.com', status: 'active' },
339
+ { id: 2, name: 'Hanako Sato', email: 'sato@example.com', status: 'inactive' }
340
+ ]);
341
+
342
+ const headers = [
343
+ { key: 'name', title: 'Name', sortable: true },
344
+ { key: 'email', title: 'Email', sortable: true },
345
+ { key: 'status', title: 'Status' },
346
+ { key: 'actions', title: 'Actions', width: 120 }
347
+ ];
348
+
349
+ const handleSelect = (selectedItems: any[]) => {
350
+ console.log('Selected items:', selectedItems);
351
+ };
352
+
353
+ const editUser = (user: any) => {
354
+ console.log('Edit:', user);
355
+ };
356
+
357
+ const deleteUser = (user: any) => {
358
+ console.log('Delete:', user);
359
+ };
360
+ </script>
361
+ ```
362
+
363
+ ### Layout System
364
+
365
+ ```vue
366
+ <template>
367
+ <VApp>
368
+ <!-- Toolbar -->
369
+ <VToolbar color="primary" variant="flat">
370
+ <VToolbarTitle>My App</VToolbarTitle>
371
+ <VToolbarMenu>
372
+ <VButton variant="text" color="on-primary">
373
+ Menu
374
+ </VButton>
375
+ </VToolbarMenu>
376
+ </VToolbar>
377
+
378
+ <!-- Main content -->
379
+ <VGridContainer>
380
+ <VGridItem cols="12" md="3">
381
+ <!-- Side navigation -->
382
+ <VNavigation>
383
+ <VNavigationItem to="/dashboard" icon="mdi-dashboard">
384
+ Dashboard
385
+ </VNavigationItem>
386
+ <VNavigationItem to="/users" icon="mdi-account-group">
387
+ Users
388
+ </VNavigationItem>
389
+ <VNavigationItem to="/settings" icon="mdi-cog">
390
+ Settings
391
+ </VNavigationItem>
392
+ </VNavigation>
393
+ </VGridItem>
394
+
395
+ <VGridItem cols="12" md="9">
396
+ <!-- Page content -->
397
+ <VPaper class="pa-4">
398
+ <router-view />
399
+ </VPaper>
400
+ </VGridItem>
401
+ </VGridContainer>
402
+ </VApp>
403
+ </template>
404
+
405
+ <script setup lang="ts">
406
+ import {
407
+ VApp, VToolbar, VToolbarTitle, VToolbarMenu,
408
+ VGridContainer, VGridItem, VNavigation, VNavigationItem,
409
+ VPaper, VButton
410
+ } from '@fastkit/vui';
411
+ </script>
412
+ ```
413
+
414
+ ## Programmatic UI Operations
415
+
416
+ You can control UI elements from JavaScript using VUI services.
417
+
418
+ ```typescript
419
+ import { useVui } from '@fastkit/vui';
420
+
421
+ const vui = useVui();
422
+
423
+ // Alert dialog
424
+ await vui.alert('Processing completed');
425
+
426
+ // Confirmation dialog
427
+ const confirmed = await vui.confirm({
428
+ title: 'Confirmation',
429
+ message: 'Do you want to execute this operation?',
430
+ okText: 'Execute',
431
+ cancelText: 'Cancel'
432
+ });
433
+
434
+ if (confirmed) {
435
+ // Process when confirmed
436
+ }
437
+
438
+ // Prompt dialog
439
+ const result = await vui.prompt({
440
+ title: 'Enter name',
441
+ message: 'Please enter a new name',
442
+ defaultValue: 'Default value'
443
+ });
444
+
445
+ // Form prompt
446
+ const formResult = await vui.formPrompt(
447
+ {
448
+ state: { name: '', description: '' },
449
+ title: 'Create New'
450
+ },
451
+ (state) => (
452
+ <>
453
+ <VTextField
454
+ label="Name"
455
+ v-model={state.name}
456
+ required
457
+ />
458
+ <VTextarea
459
+ label="Description"
460
+ v-model={state.description}
461
+ rows={3}
462
+ />
463
+ </>
464
+ )
465
+ );
466
+
467
+ // Snackbar notification
468
+ vui.snackbar.show({
469
+ message: 'Saved',
470
+ color: 'success',
471
+ timeout: 3000
472
+ });
473
+
474
+ // Custom dialog
475
+ const dialog = await vui.dialog.show({
476
+ component: MyCustomDialog,
477
+ props: {
478
+ data: someData
479
+ }
480
+ });
481
+ ```
482
+
483
+ ## Theme Customization
484
+
485
+ ### CSS Variables
486
+
487
+ ```css
488
+ :root {
489
+ /* Color palette */
490
+ --color-primary: #1976d2;
491
+ --color-secondary: #424242;
492
+ --color-success: #4caf50;
493
+ --color-warning: #ff9800;
494
+ --color-error: #f44336;
495
+
496
+ /* Size settings */
497
+ --control-field-rem-sm: 0.875rem;
498
+ --control-field-rem-md: 1rem;
499
+ --control-field-rem-lg: 1.125rem;
500
+
501
+ /* Spacing */
502
+ --root-spacing: 8px;
503
+
504
+ /* Font */
505
+ --typo-base-font: Roboto, 'Noto Sans JP', sans-serif;
506
+
507
+ /* Shadow */
508
+ --shadow-1: 0px 2px 1px -1px rgba(0, 0, 0, 0.2);
509
+ --shadow-4: 0px 2px 4px -1px rgba(0, 0, 0, 0.2);
510
+
511
+ /* Transition */
512
+ --transition-primary: cubic-bezier(0.25, 0.8, 0.5, 1);
513
+ }
514
+ ```
515
+
516
+ ### Custom Color Scheme
517
+
518
+ ```typescript
519
+ // Define custom colors
520
+ app.use(VuiPlugin, {
521
+ colorScheme: {
522
+ primary: {
523
+ main: '#1976d2',
524
+ light: '#42a5f5',
525
+ dark: '#1565c0',
526
+ contrast: '#ffffff'
527
+ },
528
+ secondary: {
529
+ main: '#dc004e',
530
+ light: '#ff5983',
531
+ dark: '#9a0036',
532
+ contrast: '#ffffff'
533
+ }
534
+ }
535
+ });
536
+ ```
537
+
538
+ ### Dark Theme Support
539
+
540
+ ```vue
541
+ <template>
542
+ <VApp :theme="currentTheme">
543
+ <VButton @click="toggleTheme">
544
+ {{ currentTheme === 'dark' ? 'Light' : 'Dark' }} Theme
545
+ </VButton>
546
+ <!-- App content -->
547
+ </VApp>
548
+ </template>
549
+
550
+ <script setup lang="ts">
551
+ import { ref } from 'vue';
552
+ import { useColorScheme } from '@fastkit/vui';
553
+
554
+ const { theme: currentTheme, toggle: toggleTheme } = useColorScheme();
555
+ </script>
556
+ ```
557
+
558
+ ## Advanced Usage Examples
559
+
560
+ ### Custom Component Creation
561
+
562
+ ```vue
563
+ <template>
564
+ <VCard class="user-profile">
565
+ <VCardContent>
566
+ <div class="user-profile__header">
567
+ <VAvatar :src="user.avatar" size="lg" />
568
+ <div class="user-profile__info">
569
+ <h3>{{ user.name }}</h3>
570
+ <p>{{ user.role }}</p>
571
+ </div>
572
+ </div>
573
+
574
+ <VTabs v-model="activeTab">
575
+ <VTab value="profile">Profile</VTab>
576
+ <VTab value="settings">Settings</VTab>
577
+ <VTab value="activity">Activity</VTab>
578
+ </VTabs>
579
+
580
+ <VContentSwitcher :value="activeTab">
581
+ <template #profile>
582
+ <UserProfileTab :user="user" />
583
+ </template>
584
+ <template #settings>
585
+ <UserSettingsTab :user="user" />
586
+ </template>
587
+ <template #activity>
588
+ <UserActivityTab :user="user" />
589
+ </template>
590
+ </VContentSwitcher>
591
+ </VCardContent>
592
+ </VCard>
593
+ </template>
594
+
595
+ <script setup lang="ts">
596
+ import { ref } from 'vue';
597
+ import {
598
+ VCard, VCardContent, VAvatar, VTabs, VTab, VContentSwitcher
599
+ } from '@fastkit/vui';
600
+
601
+ interface User {
602
+ name: string;
603
+ role: string;
604
+ avatar: string;
605
+ }
606
+
607
+ const props = defineProps<{
608
+ user: User;
609
+ }>();
610
+
611
+ const activeTab = ref('profile');
612
+ </script>
613
+
614
+ <style scoped>
615
+ .user-profile__header {
616
+ display: flex;
617
+ align-items: center;
618
+ gap: 1rem;
619
+ margin-bottom: 1.5rem;
620
+ }
621
+
622
+ .user-profile__info h3 {
623
+ margin: 0;
624
+ font-size: 1.25rem;
625
+ font-weight: 500;
626
+ }
627
+
628
+ .user-profile__info p {
629
+ margin: 0.25rem 0 0;
630
+ color: var(--color-text-secondary);
631
+ }
632
+ </style>
633
+ ```
634
+
635
+ ### Complex Form Wizard
636
+
637
+ ```vue
638
+ <template>
639
+ <VCard class="form-wizard">
640
+ <VCardContent>
641
+ <VToolbar variant="flat" class="mb-4">
642
+ <VToolbarTitle>Registration Wizard</VToolbarTitle>
643
+ <VToolbarEdge>
644
+ Step {{ currentStep + 1 }} / {{ steps.length }}
645
+ </VToolbarEdge>
646
+ </VToolbar>
647
+
648
+ <!-- Step indicator -->
649
+ <div class="step-indicator">
650
+ <div
651
+ v-for="(step, index) in steps"
652
+ :key="step.name"
653
+ class="step-indicator__item"
654
+ :class="{
655
+ 'step-indicator__item--active': index === currentStep,
656
+ 'step-indicator__item--completed': index < currentStep
657
+ }"
658
+ >
659
+ <VIcon
660
+ :name="index < currentStep ? 'mdi-check' : step.icon"
661
+ size="sm"
662
+ />
663
+ <span>{{ step.title }}</span>
664
+ </div>
665
+ </div>
666
+
667
+ <!-- Step content -->
668
+ <VContentSwitcher :value="currentStep">
669
+ <template #0>
670
+ <PersonalInfoStep v-model="formData.personal" />
671
+ </template>
672
+ <template #1>
673
+ <ContactInfoStep v-model="formData.contact" />
674
+ </template>
675
+ <template #2>
676
+ <PreferencesStep v-model="formData.preferences" />
677
+ </template>
678
+ <template #3>
679
+ <ConfirmationStep :data="formData" />
680
+ </template>
681
+ </VContentSwitcher>
682
+ </VCardContent>
683
+
684
+ <VCardActions>
685
+ <VButton
686
+ variant="text"
687
+ :disabled="currentStep === 0"
688
+ @click="previousStep"
689
+ >
690
+ Back
691
+ </VButton>
692
+
693
+ <div class="flex-grow" />
694
+
695
+ <VButton
696
+ v-if="currentStep < steps.length - 1"
697
+ color="primary"
698
+ variant="contained"
699
+ :disabled="!canProceed"
700
+ @click="nextStep"
701
+ >
702
+ Next
703
+ </VButton>
704
+
705
+ <VButton
706
+ v-else
707
+ color="primary"
708
+ variant="contained"
709
+ :loading="submitting"
710
+ @click="submitForm"
711
+ >
712
+ Complete
713
+ </VButton>
714
+ </VCardActions>
715
+ </VCard>
716
+ </template>
717
+
718
+ <script setup lang="ts">
719
+ import { ref, computed } from 'vue';
720
+ import {
721
+ VCard, VCardContent, VCardActions,
722
+ VToolbar, VToolbarTitle, VToolbarEdge,
723
+ VContentSwitcher, VButton, VIcon
724
+ } from '@fastkit/vui';
725
+
726
+ const currentStep = ref(0);
727
+ const submitting = ref(false);
728
+
729
+ const steps = [
730
+ { name: 'personal', title: 'Personal Info', icon: 'mdi-account' },
731
+ { name: 'contact', title: 'Contact Info', icon: 'mdi-email' },
732
+ { name: 'preferences', title: 'Preferences', icon: 'mdi-cog' },
733
+ { name: 'confirm', title: 'Confirmation', icon: 'mdi-check-circle' }
734
+ ];
735
+
736
+ const formData = ref({
737
+ personal: { name: '', birthday: '' },
738
+ contact: { email: '', phone: '' },
739
+ preferences: { newsletter: false, theme: 'light' }
740
+ });
741
+
742
+ const canProceed = computed(() => {
743
+ // Validation for each step
744
+ switch (currentStep.value) {
745
+ case 0:
746
+ return formData.value.personal.name && formData.value.personal.birthday;
747
+ case 1:
748
+ return formData.value.contact.email;
749
+ case 2:
750
+ return true;
751
+ default:
752
+ return false;
753
+ }
754
+ });
755
+
756
+ const nextStep = () => {
757
+ if (currentStep.value < steps.length - 1) {
758
+ currentStep.value++;
759
+ }
760
+ };
761
+
762
+ const previousStep = () => {
763
+ if (currentStep.value > 0) {
764
+ currentStep.value--;
765
+ }
766
+ };
767
+
768
+ const submitForm = async () => {
769
+ submitting.value = true;
770
+ try {
771
+ await api.submitRegistration(formData.value);
772
+ // Success processing
773
+ } finally {
774
+ submitting.value = false;
775
+ }
776
+ };
777
+ </script>
778
+
779
+ <style scoped>
780
+ .step-indicator {
781
+ display: flex;
782
+ justify-content: space-between;
783
+ margin-bottom: 2rem;
784
+ }
785
+
786
+ .step-indicator__item {
787
+ display: flex;
788
+ flex-direction: column;
789
+ align-items: center;
790
+ gap: 0.5rem;
791
+ opacity: 0.6;
792
+ transition: opacity 0.2s;
793
+ }
794
+
795
+ .step-indicator__item--active,
796
+ .step-indicator__item--completed {
797
+ opacity: 1;
798
+ }
799
+
800
+ .flex-grow {
801
+ flex-grow: 1;
802
+ }
803
+ </style>
804
+ ```
805
+
806
+ ## API
807
+
808
+ ### Composables
809
+
810
+ #### useVui()
811
+
812
+ Access VUI service instance.
813
+
814
+ ```typescript
815
+ const vui = useVui();
816
+
817
+ // Dialog operations
818
+ vui.alert(message)
819
+ vui.confirm(options)
820
+ vui.prompt(options)
821
+ vui.formPrompt(state, renderer)
822
+
823
+ // Notifications
824
+ vui.snackbar.show(options)
825
+ vui.snackbar.hide()
826
+
827
+ // Navigation
828
+ vui.router.push(location)
829
+ vui.location.assign(url)
830
+ ```
831
+
832
+ #### useControl()
833
+
834
+ Provides common functionality for control elements.
835
+
836
+ ```typescript
837
+ const control = useControl(props, options);
838
+
839
+ // Properties
840
+ control.size // 'sm' | 'md' | 'lg'
841
+ control.classes // Computed CSS classes
842
+ control.isDisabled // Disabled state
843
+ ```
844
+
845
+ #### useColorScheme()
846
+
847
+ Provides color theme control.
848
+
849
+ ```typescript
850
+ const { theme, toggle, setTheme } = useColorScheme();
851
+
852
+ theme.value // Current theme
853
+ toggle() // Toggle theme
854
+ setTheme('dark') // Set specific theme
855
+ ```
856
+
857
+ ### Plugin Options
858
+
859
+ ```typescript
860
+ interface VuiPluginOptions {
861
+ router: Router;
862
+ colorScheme?: VueColorSchemePluginSettings;
863
+ uiSettings?: {
864
+ primaryScope: ScopeName;
865
+ buttonDefault: {
866
+ color: ScopeName;
867
+ variant: ColorVariant;
868
+ };
869
+ dialogOk?: {
870
+ color?: ScopeName;
871
+ variant?: ColorVariant;
872
+ };
873
+ };
874
+ icons?: {
875
+ menuDown: IconName;
876
+ navigationExpand: RawIconProp;
877
+ // Other icon settings
878
+ };
879
+ stack?: VueStackPluginOptions;
880
+ form?: VueFormServiceOptions;
881
+ }
882
+ ```
883
+
884
+ ## Accessibility
885
+
886
+ ### Keyboard Navigation
887
+
888
+ - **Tab/Shift+Tab**: Focus movement
889
+ - **Enter/Space**: Button/checkbox operation
890
+ - **Arrow Keys**: Radio button/tab/menu navigation
891
+ - **Escape**: Close dialog/menu
892
+ - **Home/End**: Move to beginning/end of list/table
893
+
894
+ ### ARIA Support
895
+
896
+ ```html
897
+ <!-- Automatically applied ARIA attributes -->
898
+ <button aria-disabled="true" aria-label="Save button">
899
+ <input aria-invalid="true" aria-describedby="error-message">
900
+ <div role="dialog" aria-modal="true" aria-labelledby="dialog-title">
901
+ ```
902
+
903
+ ### Screen Reader Support
904
+
905
+ - Voice reading of form errors
906
+ - State change notifications
907
+ - Proper placement of landmark elements
908
+
909
+ ## Dependencies
910
+
911
+ ```json
912
+ {
913
+ "dependencies": {
914
+ "@fastkit/vue-form-control": "Form functionality",
915
+ "@fastkit/vue-color-scheme": "Color theme",
916
+ "@fastkit/vue-stack": "Stack management",
917
+ "@fastkit/vue-action": "Action functionality",
918
+ "@fastkit/vue-app-layout": "Layout",
919
+ "@fastkit/rules": "Validation",
920
+ "@fastkit/helpers": "Utilities"
921
+ },
922
+ "peerDependencies": {
923
+ "vue": "^3.4.0",
924
+ "vue-router": "^4.0.0"
925
+ }
926
+ }
927
+ ```
928
+
3
929
  ## Documentation
4
- https://dadajam4.github.io/fastkit/vui/
930
+
931
+ For detailed documentation, please visit [here](https://dadajam4.github.io/fastkit/vui/).
932
+
933
+ ## License
934
+
935
+ MIT
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fastkit/vui",
3
- "version": "0.20.0",
3
+ "version": "0.20.2",
4
4
  "description": "A simple, extensible UI kit for Vue applications.",
5
5
  "keywords": [
6
6
  "fastkit",
@@ -44,31 +44,31 @@
44
44
  "src"
45
45
  ],
46
46
  "dependencies": {
47
+ "@fastkit/helpers": "^0.14.5",
47
48
  "@fastkit/color-scheme": "^2.0.10",
48
- "@fastkit/color-scheme-gen": "^0.14.13",
49
49
  "@fastkit/dom": "^0.2.6",
50
- "@fastkit/helpers": "^0.14.5",
50
+ "@fastkit/rules": "^0.14.7",
51
+ "@fastkit/color-scheme-gen": "^0.14.13",
51
52
  "@fastkit/icon-font": "^2.0.7",
52
- "@fastkit/media-match": "^2.0.7",
53
+ "@fastkit/tiny-logger": "^0.14.5",
53
54
  "@fastkit/media-match-gen": "^0.14.13",
54
- "@fastkit/rules": "^0.14.7",
55
+ "@fastkit/vue-body-scroll-lock": "^0.2.13",
56
+ "@fastkit/media-match": "^2.0.7",
55
57
  "@fastkit/stylebase": "^0.13.1",
56
- "@fastkit/tiny-logger": "^0.14.5",
57
- "@fastkit/vue-action": "^0.3.19",
58
58
  "@fastkit/vue-app-layout": "^0.16.2",
59
- "@fastkit/vue-body-scroll-lock": "^0.2.13",
59
+ "@fastkit/vue-action": "^0.3.19",
60
60
  "@fastkit/vue-click-outside": "^0.2.12",
61
+ "@fastkit/vue-keyboard": "^0.2.5",
61
62
  "@fastkit/vue-color-scheme": "^0.15.15",
62
63
  "@fastkit/vue-form-control": "^0.21.0",
63
- "@fastkit/vue-keyboard": "^0.2.5",
64
- "@fastkit/vue-loading": "^0.15.15",
65
64
  "@fastkit/vue-location": "^0.4.2",
66
- "@fastkit/vue-media-match": "^0.14.10",
65
+ "@fastkit/vue-loading": "^0.15.15",
67
66
  "@fastkit/vue-resize": "^0.2.12",
68
67
  "@fastkit/vue-scroller": "^0.15.12",
69
- "@fastkit/vue-stack": "^0.16.19",
68
+ "@fastkit/vue-stack": "^0.17.0",
69
+ "@fastkit/vue-utils": "^0.15.12",
70
70
  "@fastkit/vue-transitions": "^0.2.13",
71
- "@fastkit/vue-utils": "^0.15.12"
71
+ "@fastkit/vue-media-match": "^0.14.10"
72
72
  },
73
73
  "peerDependencies": {
74
74
  "vue": "^3.4.0",