pgo-uiux2 1.0.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 (180) hide show
  1. package/.env +1 -0
  2. package/.env.production +1 -0
  3. package/.prettierrc +13 -0
  4. package/.vscode/extensions.json +3 -0
  5. package/BUTTON_GUIDE.md +257 -0
  6. package/README.md +49 -0
  7. package/THEME_REFERENCE.md +310 -0
  8. package/eslint.config.ts +27 -0
  9. package/index.html +13 -0
  10. package/package.json +85 -0
  11. package/public/favicon.ico +0 -0
  12. package/src/App.vue +368 -0
  13. package/src/assets/fonts/Faruma.ttf +0 -0
  14. package/src/components/examples/AppBarExample.vue +101 -0
  15. package/src/components/examples/AvatarExample.vue +47 -0
  16. package/src/components/examples/BannerExample.vue +287 -0
  17. package/src/components/examples/BaseInputExample.vue +25 -0
  18. package/src/components/examples/BreadcrumbExample.vue +53 -0
  19. package/src/components/examples/CardExample.vue +77 -0
  20. package/src/components/examples/ChipExample.vue +225 -0
  21. package/src/components/examples/DatePickerExample.vue +31 -0
  22. package/src/components/examples/DropdownExample.vue +84 -0
  23. package/src/components/examples/EditorExample.vue +200 -0
  24. package/src/components/examples/ExpansionPanelExample.vue +42 -0
  25. package/src/components/examples/FileUploadExample.vue +40 -0
  26. package/src/components/examples/FormExample.vue +121 -0
  27. package/src/components/examples/HugeTest.vue +8 -0
  28. package/src/components/examples/LayoutContainerExample.vue +80 -0
  29. package/src/components/examples/ModalExample.vue +82 -0
  30. package/src/components/examples/NavDrawerExample.vue +170 -0
  31. package/src/components/examples/NumberFieldExample.vue +145 -0
  32. package/src/components/examples/RadioButtonExample.vue +161 -0
  33. package/src/components/examples/SearchExample.vue +322 -0
  34. package/src/components/examples/SelectExample.vue +121 -0
  35. package/src/components/examples/StackedTableViewExample.vue +53 -0
  36. package/src/components/examples/TabExample.vue +336 -0
  37. package/src/components/examples/TableExample.vue +228 -0
  38. package/src/components/examples/TextFieldExample.vue +181 -0
  39. package/src/components/examples/TextareaExample.vue +173 -0
  40. package/src/components/examples/ThemeToggle.vue +50 -0
  41. package/src/components/examples/TimelineExample.vue +66 -0
  42. package/src/components/examples/TipTapEditorExample.vue +20 -0
  43. package/src/components/examples/TooltipExample.vue +53 -0
  44. package/src/components/examples/VueDatePickerShowcase.vue +214 -0
  45. package/src/components/examples/_DatePickerExample.vue +33 -0
  46. package/src/components/examples/__FormExample.vue +77 -0
  47. package/src/components/index.ts +25 -0
  48. package/src/components/pgo/AppBar.vue +347 -0
  49. package/src/components/pgo/Avatar.vue +139 -0
  50. package/src/components/pgo/Banner.vue +300 -0
  51. package/src/components/pgo/Breadcrumb.vue +101 -0
  52. package/src/components/pgo/Button.vue +171 -0
  53. package/src/components/pgo/Card.vue +178 -0
  54. package/src/components/pgo/ConfirmationModel.vue +32 -0
  55. package/src/components/pgo/DataTable.vue +845 -0
  56. package/src/components/pgo/DatePicker/CalendarPanel.vue +43 -0
  57. package/src/components/pgo/DatePicker/__DatePicker.vue +122 -0
  58. package/src/components/pgo/DatePicker/types.ts +11 -0
  59. package/src/components/pgo/DatePicker/useCalendar.ts +39 -0
  60. package/src/components/pgo/DatePicker/useDatePicker.ts +31 -0
  61. package/src/components/pgo/Deprecated/ToastContainer.vue +51 -0
  62. package/src/components/pgo/Deprecated/ToastItem.vue +55 -0
  63. package/src/components/pgo/Dropdown.vue +296 -0
  64. package/src/components/pgo/DropdownItem.vue +40 -0
  65. package/src/components/pgo/Editor.vue +511 -0
  66. package/src/components/pgo/ExpansionPanel.vue +185 -0
  67. package/src/components/pgo/Footer.vue +39 -0
  68. package/src/components/pgo/HeroIcon.vue +124 -0
  69. package/src/components/pgo/InputSearch.vue +194 -0
  70. package/src/components/pgo/LayoutContainer.vue +104 -0
  71. package/src/components/pgo/Main.vue +37 -0
  72. package/src/components/pgo/Modal.vue +273 -0
  73. package/src/components/pgo/NavDrawer.vue +127 -0
  74. package/src/components/pgo/NavDrawerItem.vue +161 -0
  75. package/src/components/pgo/NavigationDrawer.vue +849 -0
  76. package/src/components/pgo/OLDNavDrawer.vue +661 -0
  77. package/src/components/pgo/OldAppBar.vue +223 -0
  78. package/src/components/pgo/PApp.vue +102 -0
  79. package/src/components/pgo/Pagination.vue +242 -0
  80. package/src/components/pgo/Search copy.vue +310 -0
  81. package/src/components/pgo/Search.vue +411 -0
  82. package/src/components/pgo/StackedTableView.vue +167 -0
  83. package/src/components/pgo/Tab.vue +617 -0
  84. package/src/components/pgo/TestInput.vue +395 -0
  85. package/src/components/pgo/Timeline.vue +367 -0
  86. package/src/components/pgo/TimelineItem.vue +80 -0
  87. package/src/components/pgo/TipTapEditor.vue +315 -0
  88. package/src/components/pgo/Tooltip.NOTES.md +12 -0
  89. package/src/components/pgo/Tooltip.PROPS.md +21 -0
  90. package/src/components/pgo/Tooltip.vue +281 -0
  91. package/src/components/pgo/base/Base.vue +444 -0
  92. package/src/components/pgo/buttons/Chip.vue +324 -0
  93. package/src/components/pgo/buttons/ChipGroup.vue +224 -0
  94. package/src/components/pgo/buttons/Radio.vue +424 -0
  95. package/src/components/pgo/filters/FilterSection.vue +188 -0
  96. package/src/components/pgo/filters/Searchbar.vue +216 -0
  97. package/src/components/pgo/forms/DynamicForm.vue +45 -0
  98. package/src/components/pgo/forms/Form.vue +132 -0
  99. package/src/components/pgo/index.ts +15 -0
  100. package/src/components/pgo/inputs/Checkbox.vue +320 -0
  101. package/src/components/pgo/inputs/DatePicker.vue +395 -0
  102. package/src/components/pgo/inputs/FileUpload.vue +326 -0
  103. package/src/components/pgo/inputs/NumberField.vue +243 -0
  104. package/src/components/pgo/inputs/Radio.vue +162 -0
  105. package/src/components/pgo/inputs/RadioGroup.vue +188 -0
  106. package/src/components/pgo/inputs/Select.vue +535 -0
  107. package/src/components/pgo/inputs/TextField.vue +194 -0
  108. package/src/components/pgo/inputs/Textarea.vue +181 -0
  109. package/src/main.js +12 -0
  110. package/src/pgo-components/_index.js +31 -0
  111. package/src/pgo-components/assets/fonts/Faruma.ttf +0 -0
  112. package/src/pgo-components/assets/fonts/logo.png +0 -0
  113. package/src/pgo-components/composables/useTheme.js +10 -0
  114. package/src/pgo-components/directives/tooltip-directive.ts +393 -0
  115. package/src/pgo-components/index.js +96 -0
  116. package/src/pgo-components/lib/componentConfig.js +147 -0
  117. package/src/pgo-components/lib/core/composables/_useCalendar.ts +127 -0
  118. package/src/pgo-components/lib/core/composables/useDefaults.ts +15 -0
  119. package/src/pgo-components/lib/core/composables/useLanguageSelect.js +0 -0
  120. package/src/pgo-components/lib/core/composables/useRtl.ts +12 -0
  121. package/src/pgo-components/lib/core/defaults/createDefaults.ts +5 -0
  122. package/src/pgo-components/lib/core/defaults/defaults.ts +7 -0
  123. package/src/pgo-components/lib/core/rtl/rtl.ts +3 -0
  124. package/src/pgo-components/lib/core/rtl/setRtl.ts +19 -0
  125. package/src/pgo-components/lib/drawerState.ts +3 -0
  126. package/src/pgo-components/lib/i18n/defaultLables.js +71 -0
  127. package/src/pgo-components/lib/i18n/i18nPlugin.js +52 -0
  128. package/src/pgo-components/lib/i18n/useI18n.js +35 -0
  129. package/src/pgo-components/lib/index.ts +38 -0
  130. package/src/pgo-components/pages/Component.vue +7 -0
  131. package/src/pgo-components/pages/ComponentRenderer.vue +85 -0
  132. package/src/pgo-components/pages/Home.vue +130 -0
  133. package/src/pgo-components/pages/ListView.vue +370 -0
  134. package/src/pgo-components/pages/Page1.vue +296 -0
  135. package/src/pgo-components/pages/_Page1.vue +180 -0
  136. package/src/pgo-components/plugins/SnackBar.vue +251 -0
  137. package/src/pgo-components/plugins/SnackBarContainer.vue +53 -0
  138. package/src/pgo-components/plugins/SnackBarPlugin.ts +136 -0
  139. package/src/pgo-components/plugins/theme-plugin.js +114 -0
  140. package/src/pgo-components/plugins/types.ts +46 -0
  141. package/src/pgo-components/plugins/useSnackBar.js +11 -0
  142. package/src/pgo-components/plugins/useSnackBar.ts +21 -0
  143. package/src/pgo-components/plugins/validation-plugin.js +11 -0
  144. package/src/pgo-components/services/Entry.json +813 -0
  145. package/src/pgo-components/services/axios.js +54 -0
  146. package/src/pgo-components/services/data.json +90 -0
  147. package/src/pgo-components/services/person.json +260 -0
  148. package/src/pgo-components/services/toast.ts +44 -0
  149. package/src/pgo-components/styles/global.css +234 -0
  150. package/src/pgo-components/styles/reset.css +96 -0
  151. package/src/pgo-components/styles/tokens.css +18 -0
  152. package/src/pgo-components/styles/utilities/border-radius.css +57 -0
  153. package/src/pgo-components/styles/utilities/borders.css +85 -0
  154. package/src/pgo-components/styles/utilities/colors.css +38 -0
  155. package/src/pgo-components/styles/utilities/cursor.css +19 -0
  156. package/src/pgo-components/styles/utilities/display.css +78 -0
  157. package/src/pgo-components/styles/utilities/elevation.css +33 -0
  158. package/src/pgo-components/styles/utilities/flex.css +403 -0
  159. package/src/pgo-components/styles/utilities/float.css +41 -0
  160. package/src/pgo-components/styles/utilities/hover.css +9 -0
  161. package/src/pgo-components/styles/utilities/index.css +18 -0
  162. package/src/pgo-components/styles/utilities/opacity.css +27 -0
  163. package/src/pgo-components/styles/utilities/overflow.css +26 -0
  164. package/src/pgo-components/styles/utilities/palette.css +515 -0
  165. package/src/pgo-components/styles/utilities/position.css +14 -0
  166. package/src/pgo-components/styles/utilities/sizing.css +70 -0
  167. package/src/pgo-components/styles/utilities/spacing.css +578 -0
  168. package/src/pgo-components/styles/utilities/transitions.css +58 -0
  169. package/src/pgo-components/styles/utilities/typography.css +91 -0
  170. package/src/pgo-components/styles/utilities/z-index.css +11 -0
  171. package/src/pgo-components/tokens/index.js +337 -0
  172. package/src/router/index.js +88 -0
  173. package/src/shims-vue.d.ts +14 -0
  174. package/src/validations/validationRules.js +50 -0
  175. package/tailwind.config.js +73 -0
  176. package/test.php +5 -0
  177. package/tsconfig.json +25 -0
  178. package/ui +31 -0
  179. package/ui.pgo.mv.conf +18 -0
  180. package/vite.config.js +42 -0
@@ -0,0 +1,162 @@
1
+ <template>
2
+ <label
3
+ :class="['inline-flex gap-2 items-center', { 'opacity-50 cursor-not-allowed': disabled, 'cursor-pointer': !disabled }]"
4
+ >
5
+ <input
6
+ ref="inputRef"
7
+ v-bind="attrs"
8
+ class="sr-only"
9
+ type="radio"
10
+ :name="name"
11
+ :value="value"
12
+ :disabled="disabled"
13
+ :checked="isChecked"
14
+ @change="onChange"
15
+ @keydown.enter.prevent="onChange"
16
+ />
17
+
18
+ <!-- Outer circle -->
19
+ <span
20
+ :class="[
21
+ 'relative flex items-center justify-center rounded-full border transition-colors duration-150',
22
+ sizeOuter,
23
+ isChecked ? checkedOuter : uncheckedOuter,
24
+ focusClass
25
+ ]"
26
+ aria-hidden="true"
27
+ >
28
+ <!-- inner dot -->
29
+ <span
30
+ v-if="isChecked"
31
+ :class="['rounded-full bg-white transition-transform', sizeInner]"
32
+ />
33
+ </span>
34
+
35
+ <!-- Label -->
36
+ <span v-if="$slots.default || label" class="select-none ml-2 text-sm" :class="labelClass">
37
+ <slot>{{ selectedlabel }}</slot>
38
+ </span>
39
+ </label>
40
+ </template>
41
+
42
+ <script setup lang="ts">
43
+ import { computed, ref, inject, useAttrs, withDefaults, defineProps, defineEmits } from 'vue'
44
+ import { useLanguageSelected } from '../../../pgo-components/lib/componentConfig'
45
+
46
+ const { language } = inject<{ language: { value: string } }>('i18n') || { language: { value: 'en' } }
47
+
48
+ const props = withDefaults(defineProps<{
49
+ modelValue?: string|number|boolean|null,
50
+ value: string|number|boolean,
51
+ name?: string,
52
+ label?: string|object,
53
+ disabled?: boolean,
54
+ size?: 'sm'|'md'|'lg',
55
+ lang?: string,
56
+ dir?: string,
57
+ color?: string
58
+ }>(), {
59
+ size: 'md',
60
+ disabled: false,
61
+ color: 'primary'
62
+ })
63
+
64
+ const emit = defineEmits(['update:modelValue', 'change'])
65
+
66
+ const attrs = useAttrs()
67
+ const inputRef = ref<HTMLInputElement | null>(null)
68
+
69
+ const isChecked = computed(() => {
70
+ // Loose equality to support number/string matching
71
+ // but keep it predictable; change if strict equality preferred
72
+ // (e.g. Number/ String conversion)
73
+ // eslint-disable-next-line eqeqeq
74
+ return props.modelValue == props.value
75
+ })
76
+
77
+ const selectedDirection = computed(() => {
78
+ let selected = ''
79
+ if (props.dir == 'rtl') selected = 'rtl'
80
+ else if (props.lang == 'dv') selected = 'rtl'
81
+ else if (props.dir == 'ltr') selected = 'ltr'
82
+ else if (props.lang == 'en') selected = 'ltr'
83
+ else selected = ''
84
+ return selected
85
+ })
86
+
87
+ const selectLanguage = computed(() => {
88
+ let Selected = ''
89
+ if (props.lang != ''){
90
+ Selected = props.lang
91
+ }
92
+ else if (props.dir == 'rtl') {
93
+ Selected = 'dv'
94
+ }
95
+ else if (props.dir == 'ltr') {
96
+ Selected = 'en'
97
+ }
98
+ else {
99
+ Selected = language.value
100
+ }
101
+ console.log('selectLanguage in Card222:', Selected)
102
+ return (Selected === 'dv') ? 'dv' : 'en'
103
+ })
104
+
105
+ const faruma = computed(() => {
106
+ if (selectLanguage.value == 'dv') return 'faruma'
107
+ return ''
108
+ })
109
+
110
+ const selectedlabel = computed(() => {
111
+ return useLanguageSelected(props.label, selectLanguage.value, '')
112
+ })
113
+
114
+ const onChange = (e?: Event) => {
115
+ if (props.disabled) return
116
+ emit('update:modelValue', props.value)
117
+ emit('change', props.value)
118
+ }
119
+
120
+ // Size classes
121
+ const sizeOuter = computed(() => {
122
+ switch (props.size) {
123
+ case 'sm': return 'w-4 h-4'
124
+ case 'lg': return 'w-6 h-6'
125
+ default: return 'w-5 h-5'
126
+ }
127
+ })
128
+ const sizeInner = computed(() => {
129
+ switch (props.size) {
130
+ case 'sm': return 'w-2 h-2'
131
+ case 'lg': return 'w-3 h-3'
132
+ default: return 'w-2.5 h-2.5'
133
+ }
134
+ })
135
+
136
+ // Color mapping (common tokens in your project). Accept a Tailwind class string too.
137
+ const colorClass = computed(() => {
138
+ const c = String(props.color || 'primary')
139
+ // If user passed a tailwind color class like "bg-red-500" or "text-red-500", use it.
140
+ if (/^(bg-|text-|border-)/.test(c)) return c
141
+ // Map simple tokens to classes — adapt to your project's tokens
142
+ const map: Record<string, string> = {
143
+ primary: 'bg-primary',
144
+ secondary: 'bg-secondary',
145
+ success: 'bg-green-500',
146
+ danger: 'bg-red-500',
147
+ info: 'bg-sky-500',
148
+ warning: 'bg-amber-500'
149
+ }
150
+ return map[c] || 'bg-primary'
151
+ })
152
+
153
+ // Checked / unchecked classes
154
+ const checkedOuter = computed(() => `${colorClass.value} border-transparent`)
155
+ const uncheckedOuter = computed(() => 'bg-white border-gray-300 dark:border-gray-600')
156
+
157
+ // Focus ring
158
+ const focusClass = 'focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-offset-1 focus-visible:ring-primary'
159
+
160
+ // Optional label color
161
+ const labelClass = computed(() => props.disabled ? 'text-gray-400' : 'text-text')
162
+ </script>
@@ -0,0 +1,188 @@
1
+ <template>
2
+ <div
3
+ :id="id"
4
+ role="radiogroup"
5
+ :aria-labelledby="ariaLabelledby"
6
+ :aria-disabled="disabled ? 'true' : undefined"
7
+ :class="['inline-flex', direction === 'vertical' ? 'flex-col' : 'items-center', gapClass]"
8
+ @keydown="onKeydown"
9
+ >
10
+ <!-- Render from options prop if provided -->
11
+ <template v-if="Array.isArray(options) && options.length > 0">
12
+ <label
13
+ v-for="(opt, idx) in options"
14
+ :key="`opt-${idx}-${String(opt?.value)}`"
15
+ :class="['inline-flex items-center', { 'opacity-50 pointer-events-none': disabled || opt.disabled }]"
16
+ >
17
+ <Radio
18
+ ref="setOptionRef(idx)"
19
+ v-model="internalValue"
20
+ :value="opt.value"
21
+ :name="groupName"
22
+ :disabled="disabled || !!opt.disabled"
23
+ :size="size"
24
+ :color="opt.color || color"
25
+ @change="onChange(opt.value)"
26
+ >
27
+ <template #default>
28
+ <div class="flex flex-col">
29
+ <div class="select-none ml-2 text-sm" :class="labelClass">{{ opt.label }}</div>
30
+ <small v-if="opt.description" class="text-xs text-gray-500 ml-2">{{ opt.description }}</small>
31
+ </div>
32
+ </template>
33
+ </Radio>
34
+ </label>
35
+ </template>
36
+
37
+ <!-- Fallback: render default slot - expected to contain Radio children -->
38
+ <slot v-else />
39
+ </div>
40
+ </template>
41
+
42
+ <script setup lang="ts">
43
+ import { ref, computed, watch, nextTick } from 'vue'
44
+ import Radio from './Radio.vue'
45
+
46
+ /**
47
+ Props
48
+ - modelValue: the v-model value
49
+ - options: optional array of { label, value, disabled?, description?, color? }
50
+ - name: optional group name (if not provided a unique name is generated)
51
+ - disabled, size, color, direction
52
+ - ariaLabelledby: optional id for label element (for accessibility)
53
+ */
54
+ const props = defineProps<{
55
+ modelValue?: unknown,
56
+ options?: Array<{
57
+ label: string,
58
+ value: any,
59
+ disabled?: boolean,
60
+ description?: string,
61
+ color?: string
62
+ }>,
63
+ name?: string,
64
+ disabled?: boolean,
65
+ size?: 'sm'|'md'|'lg',
66
+ color?: string,
67
+ direction?: 'horizontal'|'vertical',
68
+ gap?: string,
69
+ ariaLabelledby?: string
70
+ }>()
71
+
72
+ const emit = defineEmits<{
73
+ (e: 'update:modelValue', value: any): void
74
+ (e: 'change', value: any): void
75
+ }>()
76
+
77
+ // local id + group name
78
+ const uid = Math.random().toString(36).slice(2, 9)
79
+ const id = `radio-group-${uid}`
80
+ const groupName = computed(() => props.name || `rg-${uid}`)
81
+ const ariaLabelledby = computed(() => props.ariaLabelledby || undefined)
82
+
83
+ // layout helpers
84
+ const direction = computed(() => props.direction || 'horizontal')
85
+ const gapClass = computed(() => {
86
+ if (props.gap) return props.gap
87
+ return direction.value === 'vertical' ? 'space-y-2' : 'space-x-4'
88
+ })
89
+
90
+ // simple defaults
91
+ const size = computed(() => props.size || 'md')
92
+ const color = computed(() => props.color || 'primary')
93
+ const disabled = computed(() => !!props.disabled)
94
+ const labelClass = computed(() => disabled.value ? 'text-gray-400' : 'text-text')
95
+
96
+ // internal v-model proxy
97
+ const internalValue = ref(props.modelValue)
98
+ watch(() => props.modelValue, v => { internalValue.value = v }, { immediate: true })
99
+ watch(internalValue, (val) => {
100
+ emit('update:modelValue', val)
101
+ })
102
+
103
+ // refs to child radios for keyboard navigation
104
+ const optionRefs = ref<Array<HTMLElement | null>>([])
105
+
106
+ function setOptionRef(index: number) {
107
+ return (el: HTMLElement | null) => {
108
+ optionRefs.value[index] = el
109
+ }
110
+ }
111
+
112
+ // update:modelValue already emitted via watcher above; this emits a change event too
113
+ function onChange(val: any) {
114
+ return () => {
115
+ emit('change', val)
116
+ }
117
+ }
118
+
119
+ // Keyboard navigation: ArrowRight/ArrowDown => next, ArrowLeft/ArrowUp => prev, Home/End
120
+ function focusIndex(index: number) {
121
+ const el = optionRefs.value[index]
122
+ if (el && typeof (el as any).focus === 'function') {
123
+ ;(el as any).focus()
124
+ }
125
+ }
126
+
127
+ function findEnabledIndex(start = 0, step = 1) {
128
+ const len = optionRefs.value.length
129
+ if (len === 0) return -1
130
+ let i = (start + len) % len
131
+ for (let iter = 0; iter < len; iter++) {
132
+ const idx = (i + iter * step + len) % len
133
+ const el = optionRefs.value[idx]
134
+ if (!el) continue
135
+ const radioEl = el.querySelector ? el.querySelector('input[type="radio"]') : el
136
+ if (!radioEl) continue
137
+ if ((radioEl as HTMLInputElement).disabled) continue
138
+ return idx
139
+ }
140
+ return -1
141
+ }
142
+
143
+ async function onKeydown(e: KeyboardEvent) {
144
+ if (!Array.isArray(props.options) || props.options.length === 0) return
145
+ const len = props.options.length
146
+ if (len === 0) return
147
+
148
+ const currentIndex = props.options.findIndex(o => o.value == internalValue.value)
149
+
150
+ if (e.key === 'ArrowRight' || e.key === 'ArrowDown') {
151
+ e.preventDefault()
152
+ const next = findEnabledIndex((currentIndex >= 0 ? currentIndex : -1) + 1, 1)
153
+ if (next >= 0) {
154
+ internalValue.value = props.options[next].value
155
+ await nextTick()
156
+ focusIndex(next)
157
+ emit('change', internalValue.value)
158
+ }
159
+ } else if (e.key === 'ArrowLeft' || e.key === 'ArrowUp') {
160
+ e.preventDefault()
161
+ const prev = findEnabledIndex((currentIndex >= 0 ? currentIndex : len) - 1, -1)
162
+ if (prev >= 0) {
163
+ internalValue.value = props.options[prev].value
164
+ await nextTick()
165
+ focusIndex(prev)
166
+ emit('change', internalValue.value)
167
+ }
168
+ } else if (e.key === 'Home') {
169
+ e.preventDefault()
170
+ const first = findEnabledIndex(0, 1)
171
+ if (first >= 0) {
172
+ internalValue.value = props.options[first].value
173
+ await nextTick()
174
+ focusIndex(first)
175
+ emit('change', internalValue.value)
176
+ }
177
+ } else if (e.key === 'End') {
178
+ e.preventDefault()
179
+ const last = findEnabledIndex(len - 1, -1)
180
+ if (last >= 0) {
181
+ internalValue.value = props.options[last].value
182
+ await nextTick()
183
+ focusIndex(last)
184
+ emit('change', internalValue.value)
185
+ }
186
+ }
187
+ }
188
+ </script>