@xen-orchestra/web-core 0.20.1 → 0.21.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/lib/components/backup-state/VtsBackupState.vue +20 -17
- package/lib/components/cell-object/VtsCellObject.vue +4 -1
- package/lib/components/console/VtsActionsConsole.vue +7 -4
- package/lib/components/console/VtsClipboardConsole.vue +9 -6
- package/lib/components/copy-button/VtsCopyButton.vue +7 -14
- package/lib/components/dropdown/DropdownTitle.vue +5 -2
- package/lib/components/icon/NewVtsIcon.vue +49 -0
- package/lib/components/input-group/VtsInputGroup.vue +41 -0
- package/lib/components/input-wrapper/VtsInputWrapper.vue +2 -2
- package/lib/components/layout/VtsLayoutSidebar.vue +6 -3
- package/lib/components/linear-chart/VtsLinearChart.vue +4 -0
- package/lib/components/object-icon/VtsObjectIcon.vue +22 -0
- package/lib/components/quick-info-card/VtsQuickInfoCard.vue +4 -1
- package/lib/components/select/VtsOption.vue +10 -6
- package/lib/components/select/VtsSelect.vue +74 -50
- package/lib/components/state-hero/VtsAllDoneHero.vue +4 -1
- package/lib/components/state-hero/VtsAllGoodHero.vue +4 -1
- package/lib/components/state-hero/VtsComingSoonHero.vue +4 -1
- package/lib/components/state-hero/VtsErrorNoDataHero.vue +4 -1
- package/lib/components/state-hero/VtsLoadingHero.vue +4 -1
- package/lib/components/state-hero/VtsNoDataHero.vue +4 -1
- package/lib/components/state-hero/VtsNoSelectionHero.vue +4 -1
- package/lib/components/state-hero/VtsObjectNotFoundHero.vue +4 -1
- package/lib/components/state-hero/VtsOfflineHero.vue +4 -1
- package/lib/components/state-hero/VtsPageNotFoundHero.vue +4 -1
- package/lib/components/table/ColumnTitle.vue +2 -2
- package/lib/components/task/VtsQuickTaskButton.vue +4 -1
- package/lib/components/task/VtsQuickTaskList.vue +5 -2
- package/lib/components/task/VtsQuickTaskTabBar.vue +8 -5
- package/lib/components/ui/card-numbers/UiCardNumbers.vue +4 -1
- package/lib/components/ui/character-limit/UiCharacterLimit.vue +4 -1
- package/lib/components/ui/input/UiInput.vue +2 -2
- package/lib/components/ui/label/UiLabel.vue +4 -1
- package/lib/components/ui/progress-bar/UiProgressBar.vue +5 -2
- package/lib/components/ui/query-search-bar/UiQuerySearchBar.vue +9 -6
- package/lib/components/ui/quick-task-item/UiQuickTaskItem.vue +6 -3
- package/lib/components/ui/stacked-bar/StackedBarSegment.vue +4 -1
- package/lib/components/ui/table-pagination/UiTablePagination.vue +6 -3
- package/lib/components/ui/text-area/UiTextarea.vue +4 -1
- package/lib/components/ui/top-bottom-table/UiTopBottomTable.vue +6 -3
- package/lib/components/ui/tree-item-label/UiTreeItemLabel.vue +4 -1
- package/lib/composables/local-time-ago.composable.ts +53 -0
- package/lib/composables/locale-time-ago.composable.ts +53 -0
- package/lib/icons/fa-icons.ts +164 -0
- package/lib/icons/index.ts +15 -0
- package/lib/icons/legacy-icons.ts +80 -0
- package/lib/icons/object-icons.ts +187 -0
- package/lib/layouts/CoreLayout.vue +7 -3
- package/lib/locales/cs.json +0 -1
- package/lib/locales/de.json +1 -1
- package/lib/locales/en.json +32 -4
- package/lib/locales/es.json +1 -1
- package/lib/locales/fr.json +31 -3
- package/lib/locales/it.json +1 -1
- package/lib/locales/nl.json +1 -1
- package/lib/locales/ru.json +1 -1
- package/lib/locales/sv.json +1 -2
- package/lib/packages/collection/README.md +23 -18
- package/lib/packages/collection/create-collection.ts +22 -21
- package/lib/packages/collection/create-item.ts +21 -20
- package/lib/packages/collection/create-use-subset.ts +23 -0
- package/lib/packages/collection/guess-item-id.ts +26 -16
- package/lib/packages/collection/index.ts +4 -0
- package/lib/packages/collection/types.ts +65 -37
- package/lib/packages/collection/use-collection.ts +68 -18
- package/lib/packages/collection/use-flag-registry.ts +38 -17
- package/lib/packages/form-select/guess-label.ts +45 -0
- package/lib/packages/form-select/guess-value.ts +23 -0
- package/lib/packages/form-select/index.ts +6 -0
- package/lib/packages/form-select/normalize-search-term.ts +11 -0
- package/lib/packages/form-select/types.ts +90 -42
- package/lib/packages/form-select/use-form-option-controller.ts +7 -3
- package/lib/packages/form-select/use-form-select-controller.ts +38 -27
- package/lib/packages/form-select/use-form-select-keyboard-navigation.ts +1 -1
- package/lib/packages/form-select/use-form-select.ts +308 -130
- package/lib/packages/icon/DisplayIcon.vue +25 -0
- package/lib/packages/icon/DisplayIconAny.vue +16 -0
- package/lib/packages/icon/DisplayIconSingle.vue +35 -0
- package/lib/packages/icon/DisplayIconStack.vue +34 -0
- package/lib/packages/icon/README.md +286 -0
- package/lib/packages/icon/create-icon-bindings.ts +27 -0
- package/lib/packages/icon/define-icon-pack.ts +23 -0
- package/lib/packages/icon/define-icon-single.ts +17 -0
- package/lib/packages/icon/define-icon-stack.ts +20 -0
- package/lib/packages/icon/define-icon.ts +40 -0
- package/lib/packages/icon/generate-icon-variants.ts +17 -0
- package/lib/packages/icon/index.ts +8 -0
- package/lib/packages/icon/is-icon-stack.ts +5 -0
- package/lib/packages/icon/merge-icons.ts +25 -0
- package/lib/packages/icon/merge-transforms.ts +12 -0
- package/lib/packages/icon/normalize-icon.ts +25 -0
- package/lib/packages/icon/to-tuple.ts +7 -0
- package/lib/packages/icon/types.ts +72 -0
- package/lib/packages/job/README.md +2 -2
- package/lib/packages/mapper/README.md +166 -0
- package/lib/packages/mapper/convert-to-map.ts +5 -0
- package/lib/packages/mapper/create-mapper.ts +30 -0
- package/lib/packages/mapper/index.ts +4 -0
- package/lib/packages/mapper/types.ts +1 -0
- package/lib/packages/mapper/use-mapper.ts +31 -0
- package/lib/stores/sidebar.store.ts +1 -1
- package/lib/types/chart.ts +2 -2
- package/lib/types/utility.type.ts +9 -0
- package/lib/utils/object.util.ts +16 -0
- package/lib/utils/size.util.ts +4 -2
- package/package.json +2 -1
- package/lib/components/backup-item/VtsBackupItem.vue +0 -47
- package/lib/composables/mapper.composable.md +0 -74
- package/lib/composables/mapper.composable.ts +0 -18
|
@@ -1,45 +1,38 @@
|
|
|
1
|
-
import type {
|
|
2
|
-
import type {
|
|
3
|
-
import type { ComputedRef, InjectionKey, Reactive,
|
|
1
|
+
import type { CollectionItem, CollectionItemProperties } from '@core/packages/collection'
|
|
2
|
+
import type { KeyOfByValue } from '@core/types/utility.type.ts'
|
|
3
|
+
import type { ComputedRef, InjectionKey, Reactive, Ref, UnwrapRef } from 'vue'
|
|
4
4
|
|
|
5
|
-
export type
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
export type FormSelectId<
|
|
6
|
+
TCustomProperties extends CollectionItemProperties = CollectionItemProperties,
|
|
7
|
+
TSource = unknown,
|
|
8
|
+
TValue = unknown,
|
|
9
|
+
TMultiple extends boolean = boolean,
|
|
10
|
+
> = InjectionKey<FormSelect<TCustomProperties, TSource, TValue, TMultiple>>
|
|
9
11
|
|
|
10
|
-
export type
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
12
|
+
export type FormSelectIdToOption<TSelectId extends FormSelectId> =
|
|
13
|
+
TSelectId extends FormSelectId<infer TCustomProperties, infer TSource, infer TValue>
|
|
14
|
+
? FormOption<TCustomProperties, TSource, TValue>
|
|
15
|
+
: never
|
|
14
16
|
|
|
15
|
-
export type
|
|
17
|
+
export type ExtractValue<TOptionSource, TGetValue> = TGetValue extends keyof TOptionSource
|
|
18
|
+
? TOptionSource[TGetValue]
|
|
19
|
+
: TGetValue extends (source: TOptionSource) => infer R
|
|
20
|
+
? R
|
|
21
|
+
: TOptionSource
|
|
16
22
|
|
|
17
|
-
export type
|
|
18
|
-
|
|
19
|
-
label: string
|
|
20
|
-
|
|
21
|
-
disabled: boolean
|
|
22
|
-
matching: boolean
|
|
23
|
-
}
|
|
23
|
+
export type FormOptionCollectionItemProperties<TCustomProperties extends CollectionItemProperties, TValue> = {
|
|
24
|
+
value: ComputedRef<TValue>
|
|
25
|
+
label: ComputedRef<string>
|
|
26
|
+
selectedLabel: ComputedRef<string | undefined>
|
|
27
|
+
disabled: ComputedRef<boolean>
|
|
28
|
+
matching: ComputedRef<boolean>
|
|
29
|
+
} & TCustomProperties
|
|
24
30
|
|
|
25
31
|
export type FormOption<
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
> = CollectionItem<TSource, '
|
|
30
|
-
|
|
31
|
-
export type UseFormSelectReturn<
|
|
32
|
-
TSource,
|
|
33
|
-
TValue extends FormOptionValue,
|
|
34
|
-
TProperties extends CollectionConfigProperties,
|
|
35
|
-
> = {
|
|
36
|
-
searchTerm: WritableComputedRef<string>
|
|
37
|
-
allOptions: ComputedRef<FormOption<TSource, TValue, TProperties>[]>
|
|
38
|
-
options: ComputedRef<FormOption<TSource, TValue, TProperties>[]>
|
|
39
|
-
selectedOptions: ComputedRef<FormOption<TSource, TValue, TProperties>[]>
|
|
40
|
-
selectedValues: ComputedRef<TValue[]>
|
|
41
|
-
selectedLabel: ComputedRef<string>
|
|
42
|
-
}
|
|
32
|
+
TCustomProperties extends CollectionItemProperties = CollectionItemProperties,
|
|
33
|
+
TSource = any,
|
|
34
|
+
TValue = any,
|
|
35
|
+
> = CollectionItem<TSource, 'selected' | 'active', FormOptionCollectionItemProperties<TCustomProperties, TValue>>
|
|
43
36
|
|
|
44
37
|
export type FormOptionIndex =
|
|
45
38
|
| number
|
|
@@ -51,6 +44,16 @@ export type FormOptionIndex =
|
|
|
51
44
|
| 'last'
|
|
52
45
|
| 'selected'
|
|
53
46
|
|
|
47
|
+
export type FormSelectController = Reactive<{
|
|
48
|
+
isDisabled: ComputedRef<boolean>
|
|
49
|
+
isMultiple: ComputedRef<boolean>
|
|
50
|
+
isNavigatingWithKeyboard: Ref<boolean>
|
|
51
|
+
closeDropdown(keepFocus: boolean): void
|
|
52
|
+
focusSearchOrTrigger(): void
|
|
53
|
+
}>
|
|
54
|
+
|
|
55
|
+
export const IK_FORM_SELECT_CONTROLLER = Symbol('IK_FORM_SELECT_CONTROLLER') as InjectionKey<FormSelectController>
|
|
56
|
+
|
|
54
57
|
export enum FORM_SELECT_HANDLED_KEY {
|
|
55
58
|
DOWN = 'ArrowDown',
|
|
56
59
|
UP = 'ArrowUp',
|
|
@@ -66,10 +69,55 @@ export enum FORM_SELECT_HANDLED_KEY {
|
|
|
66
69
|
PAGE_UP = 'PageUp',
|
|
67
70
|
}
|
|
68
71
|
|
|
69
|
-
export type
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
72
|
+
export type FormSelect<
|
|
73
|
+
TCustomProperties extends CollectionItemProperties = CollectionItemProperties,
|
|
74
|
+
TSource = unknown,
|
|
75
|
+
TValue = unknown,
|
|
76
|
+
TMultiple extends boolean = boolean,
|
|
77
|
+
TFormOption extends FormOption<TCustomProperties, TSource, TValue> = FormOption<TCustomProperties, TSource, TValue>,
|
|
78
|
+
> = {
|
|
79
|
+
isMultiple: ComputedRef<TMultiple>
|
|
80
|
+
isDisabled: ComputedRef<boolean>
|
|
81
|
+
isRequired: ComputedRef<boolean>
|
|
82
|
+
isSearchable: ComputedRef<boolean>
|
|
83
|
+
isLoading: ComputedRef<boolean>
|
|
84
|
+
placeholder: ComputedRef<string>
|
|
85
|
+
searchPlaceholder: ComputedRef<string>
|
|
86
|
+
searchTerm: Ref<string>
|
|
87
|
+
allOptions: ComputedRef<TFormOption[]>
|
|
88
|
+
options: ComputedRef<TFormOption[]>
|
|
89
|
+
selectedLabel: ComputedRef<string>
|
|
90
|
+
} & (TMultiple extends true
|
|
91
|
+
? {
|
|
92
|
+
selectedValues: ComputedRef<UnwrapRef<TValue>[]>
|
|
93
|
+
selectedOptions: ComputedRef<TFormOption[]>
|
|
94
|
+
}
|
|
95
|
+
: {
|
|
96
|
+
selectedValue: ComputedRef<UnwrapRef<TValue>>
|
|
97
|
+
selectedOption: ComputedRef<TFormOption>
|
|
98
|
+
})
|
|
74
99
|
|
|
75
|
-
export
|
|
100
|
+
export type UseFormSelectReturn<
|
|
101
|
+
TCustomProperties extends CollectionItemProperties,
|
|
102
|
+
TSource,
|
|
103
|
+
TValue,
|
|
104
|
+
TMultiple extends boolean,
|
|
105
|
+
$TSelect extends FormSelect<TCustomProperties, TSource, TValue, TMultiple> = FormSelect<
|
|
106
|
+
TCustomProperties,
|
|
107
|
+
TSource,
|
|
108
|
+
TValue,
|
|
109
|
+
TMultiple
|
|
110
|
+
>,
|
|
111
|
+
> = $TSelect & {
|
|
112
|
+
id: FormSelectId<TCustomProperties, TSource, TValue, TMultiple>
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export type GetOptionValue<TSource, TCustomProperties extends CollectionItemProperties> =
|
|
116
|
+
| undefined
|
|
117
|
+
| keyof TSource
|
|
118
|
+
| ((source: TSource, properties: TCustomProperties) => unknown)
|
|
119
|
+
|
|
120
|
+
export type GetOptionLabel<TSource, TCustomProperties extends CollectionItemProperties> =
|
|
121
|
+
| undefined
|
|
122
|
+
| KeyOfByValue<TSource, string>
|
|
123
|
+
| ((source: TSource, properties: TCustomProperties) => string)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { type FormOption, IK_FORM_SELECT_CONTROLLER } from '@core/packages/form-select/types.ts'
|
|
2
1
|
import { unrefElement, useEventListener, whenever } from '@vueuse/core'
|
|
3
2
|
import { computed, inject, type MaybeRefOrGetter, ref, toValue } from 'vue'
|
|
3
|
+
import { type FormOption, IK_FORM_SELECT_CONTROLLER } from './types.ts'
|
|
4
4
|
|
|
5
5
|
export function useFormOptionController<TOption extends FormOption>(_option: MaybeRefOrGetter<TOption>) {
|
|
6
6
|
const controller = inject(IK_FORM_SELECT_CONTROLLER)
|
|
@@ -21,13 +21,17 @@ export function useFormOptionController<TOption extends FormOption>(_option: May
|
|
|
21
21
|
)
|
|
22
22
|
|
|
23
23
|
useEventListener(elementRef, 'click', event => {
|
|
24
|
+
if (controller.isDisabled) {
|
|
25
|
+
return
|
|
26
|
+
}
|
|
27
|
+
|
|
24
28
|
event.preventDefault()
|
|
25
29
|
|
|
26
30
|
if (option.value.properties.disabled) {
|
|
27
31
|
return
|
|
28
32
|
}
|
|
29
33
|
|
|
30
|
-
if (
|
|
34
|
+
if (controller.isMultiple) {
|
|
31
35
|
option.value.toggleFlag('selected')
|
|
32
36
|
controller.focusSearchOrTrigger()
|
|
33
37
|
} else {
|
|
@@ -37,7 +41,7 @@ export function useFormOptionController<TOption extends FormOption>(_option: May
|
|
|
37
41
|
})
|
|
38
42
|
|
|
39
43
|
useEventListener(elementRef, 'mouseenter', () => {
|
|
40
|
-
if (option.value.properties.disabled || controller.isNavigatingWithKeyboard) {
|
|
44
|
+
if (controller.isDisabled || option.value.properties.disabled || controller.isNavigatingWithKeyboard) {
|
|
41
45
|
return
|
|
42
46
|
}
|
|
43
47
|
|
|
@@ -1,20 +1,13 @@
|
|
|
1
|
-
import { type FormOption, type FormOptionIndex, IK_FORM_SELECT_CONTROLLER } from '@core/packages/form-select/types.ts'
|
|
2
|
-
import { useFormSelectKeyboardNavigation } from '@core/packages/form-select/use-form-select-keyboard-navigation.ts'
|
|
3
1
|
import { ifElse } from '@core/utils/if-else.utils'
|
|
4
|
-
import { type MaybeElement, useFloating } from '@floating-ui/vue'
|
|
2
|
+
import { autoUpdate, flip, type MaybeElement, shift, size, useFloating } from '@floating-ui/vue'
|
|
5
3
|
import { clamp, onClickOutside, useEventListener, useFocusWithin, whenever } from '@vueuse/core'
|
|
6
4
|
import { logicOr } from '@vueuse/math'
|
|
7
|
-
import { computed,
|
|
5
|
+
import { computed, provide, reactive, ref, watch } from 'vue'
|
|
6
|
+
import { type FormOptionIndex, type FormSelect, IK_FORM_SELECT_CONTROLLER } from './types.ts'
|
|
7
|
+
import { useFormSelectKeyboardNavigation } from './use-form-select-keyboard-navigation.ts'
|
|
8
8
|
|
|
9
|
-
export function useFormSelectController
|
|
10
|
-
options
|
|
11
|
-
searchTerm: Ref<string | undefined>
|
|
12
|
-
}) {
|
|
13
|
-
const options = computed(() => toValue(config.options))
|
|
14
|
-
|
|
15
|
-
const isMultiple = computed(() => options.value[0]?.properties.multiple ?? false)
|
|
16
|
-
|
|
17
|
-
const activeOption = computed(() => options.value.find(option => option.flags.active))
|
|
9
|
+
export function useFormSelectController(select: FormSelect) {
|
|
10
|
+
const activeOption = computed(() => select.options.value.find(option => option.flags.active))
|
|
18
11
|
|
|
19
12
|
const isOpen = ref(false)
|
|
20
13
|
|
|
@@ -36,7 +29,7 @@ export function useFormSelectController<TOption extends FormOption>(config: {
|
|
|
36
29
|
|
|
37
30
|
const { isNavigatingWithKeyboard, stopKeyboardNavigation } = useFormSelectKeyboardNavigation({
|
|
38
31
|
isActive,
|
|
39
|
-
isMultiple,
|
|
32
|
+
isMultiple: select.isMultiple,
|
|
40
33
|
isOpen,
|
|
41
34
|
onSelect: () => activeOption.value?.toggleFlag('selected', true),
|
|
42
35
|
onToggle: () => activeOption.value?.toggleFlag('selected'),
|
|
@@ -56,13 +49,15 @@ export function useFormSelectController<TOption extends FormOption>(config: {
|
|
|
56
49
|
/* DROPDOWN PLACEMENT */
|
|
57
50
|
|
|
58
51
|
const { floatingStyles } = useFloating(triggerRef, dropdownRef, {
|
|
52
|
+
whileElementsMounted: autoUpdate,
|
|
53
|
+
middleware: [shift(), flip(), size()],
|
|
59
54
|
placement: 'bottom-start',
|
|
60
55
|
open: isOpen,
|
|
61
56
|
})
|
|
62
57
|
|
|
63
58
|
/* SEARCH */
|
|
64
59
|
|
|
65
|
-
watch(
|
|
60
|
+
watch(select.searchTerm, () => stopKeyboardNavigation())
|
|
66
61
|
|
|
67
62
|
const searchRef = ref<MaybeElement<HTMLElement> & { focus?: () => void }>()
|
|
68
63
|
|
|
@@ -78,13 +73,17 @@ export function useFormSelectController<TOption extends FormOption>(config: {
|
|
|
78
73
|
|
|
79
74
|
whenever(isOpen, () => focusSearch(), { flush: 'post' })
|
|
80
75
|
|
|
81
|
-
const currentIndex = computed(() => options.value.findIndex(option => option.flags.active))
|
|
76
|
+
const currentIndex = computed(() => select.options.value.findIndex(option => option.flags.active))
|
|
82
77
|
|
|
83
|
-
whenever(options, () => moveToOptionIndex('first'), { flush: 'post' })
|
|
78
|
+
whenever(select.options, () => moveToOptionIndex('first'), { flush: 'post' })
|
|
84
79
|
|
|
85
80
|
ifElse(isOpen, () => moveToOptionIndex('selected'), clear, { flush: 'post' })
|
|
86
81
|
|
|
87
82
|
function openDropdown() {
|
|
83
|
+
if (select.isDisabled.value) {
|
|
84
|
+
return
|
|
85
|
+
}
|
|
86
|
+
|
|
88
87
|
if (!isOpen.value) {
|
|
89
88
|
isOpen.value = true
|
|
90
89
|
}
|
|
@@ -103,16 +102,14 @@ export function useFormSelectController<TOption extends FormOption>(config: {
|
|
|
103
102
|
}
|
|
104
103
|
|
|
105
104
|
function clear() {
|
|
106
|
-
|
|
107
|
-
config.searchTerm.value = ''
|
|
108
|
-
}
|
|
105
|
+
select.searchTerm.value = ''
|
|
109
106
|
}
|
|
110
107
|
|
|
111
108
|
const boundaryIndexes = computed(() => {
|
|
112
109
|
let firstIndex: number | undefined
|
|
113
110
|
let lastIndex: number | undefined
|
|
114
111
|
|
|
115
|
-
options.value.forEach((option, index) => {
|
|
112
|
+
select.options.value.forEach((option, index) => {
|
|
116
113
|
if (option.properties.disabled) {
|
|
117
114
|
return
|
|
118
115
|
}
|
|
@@ -141,15 +138,15 @@ export function useFormSelectController<TOption extends FormOption>(config: {
|
|
|
141
138
|
case 'next':
|
|
142
139
|
return currentIndex.value + 1
|
|
143
140
|
case 'previous-page':
|
|
144
|
-
return currentIndex.value - 7 // TODO:
|
|
141
|
+
return currentIndex.value - 7 // TODO: Handle page size in a better way
|
|
145
142
|
case 'next-page':
|
|
146
|
-
return currentIndex.value + 7 // TODO:
|
|
143
|
+
return currentIndex.value + 7 // TODO: Handle page size in a better way
|
|
147
144
|
case 'first':
|
|
148
145
|
return 0
|
|
149
146
|
case 'last':
|
|
150
|
-
return options.value.length - 1
|
|
147
|
+
return select.options.value.length - 1
|
|
151
148
|
case 'selected':
|
|
152
|
-
return options.value.findIndex(option => option.flags.selected)
|
|
149
|
+
return select.options.value.findIndex(option => option.flags.selected)
|
|
153
150
|
default:
|
|
154
151
|
return index
|
|
155
152
|
}
|
|
@@ -163,7 +160,15 @@ export function useFormSelectController<TOption extends FormOption>(config: {
|
|
|
163
160
|
|
|
164
161
|
const index = clamp(parseIndex(_index), boundaryIndexes.value.first, boundaryIndexes.value.last)
|
|
165
162
|
|
|
166
|
-
|
|
163
|
+
const closestIndex = getClosestEnabledIndex(index)
|
|
164
|
+
|
|
165
|
+
if (closestIndex === undefined) {
|
|
166
|
+
activeOption.value?.toggleFlag('active', false)
|
|
167
|
+
|
|
168
|
+
return
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
select.options.value[closestIndex]?.toggleFlag('active', true)
|
|
167
172
|
}
|
|
168
173
|
|
|
169
174
|
function getClosestEnabledIndex(expectedIndex: number) {
|
|
@@ -171,10 +176,14 @@ export function useFormSelectController<TOption extends FormOption>(config: {
|
|
|
171
176
|
|
|
172
177
|
const direction = expectedIndex < currentIndex.value ? -1 : 1
|
|
173
178
|
|
|
174
|
-
while (options.value[index]?.properties.disabled) {
|
|
179
|
+
while (select.options.value[index]?.properties.disabled) {
|
|
175
180
|
index += direction
|
|
176
181
|
}
|
|
177
182
|
|
|
183
|
+
if (index > (boundaryIndexes.value?.last ?? -1)) {
|
|
184
|
+
return undefined
|
|
185
|
+
}
|
|
186
|
+
|
|
178
187
|
return index
|
|
179
188
|
}
|
|
180
189
|
|
|
@@ -187,6 +196,8 @@ export function useFormSelectController<TOption extends FormOption>(config: {
|
|
|
187
196
|
provide(
|
|
188
197
|
IK_FORM_SELECT_CONTROLLER,
|
|
189
198
|
reactive({
|
|
199
|
+
isDisabled: select.isDisabled,
|
|
200
|
+
isMultiple: select.isMultiple,
|
|
190
201
|
isNavigatingWithKeyboard,
|
|
191
202
|
focusSearchOrTrigger,
|
|
192
203
|
closeDropdown,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { FORM_SELECT_HANDLED_KEY, type FormOptionIndex } from '@core/packages/form-select/types.ts'
|
|
2
1
|
import { ifElse } from '@core/utils/if-else.utils.ts'
|
|
3
2
|
import { onKeyStroke } from '@vueuse/core'
|
|
4
3
|
import { type EffectScope, effectScope, ref, type Ref } from 'vue'
|
|
4
|
+
import { FORM_SELECT_HANDLED_KEY, type FormOptionIndex } from './types.ts'
|
|
5
5
|
|
|
6
6
|
export function useFormSelectKeyboardNavigation({
|
|
7
7
|
isActive,
|