vue-composable-ui 0.0.1 → 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.
Files changed (123) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +5 -1
  3. package/dist/combobox.vue_vue_type_script_setup_true_lang-BhVMcx67.js +140 -0
  4. package/dist/comboboxHiddenInput.vue_vue_type_script_setup_true_lang-Ba-UPd-M.js +29 -0
  5. package/dist/comboboxInput.vue_vue_type_script_setup_true_lang-DzRfJ5ke.js +33 -0
  6. package/dist/comboboxOption.vue_vue_type_script_setup_true_lang-OyJxB4Jk.js +42 -0
  7. package/dist/comboboxOptions.vue_vue_type_script_setup_true_lang-Doy6MfEQ.js +20 -0
  8. package/dist/composable-ui.js +49 -0
  9. package/dist/composable-ui10.js +4 -0
  10. package/dist/composable-ui11.js +4 -0
  11. package/dist/composable-ui12.js +4 -0
  12. package/dist/composable-ui13.js +4 -0
  13. package/dist/composable-ui14.js +4 -0
  14. package/dist/composable-ui15.js +4 -0
  15. package/dist/composable-ui16.js +4 -0
  16. package/dist/composable-ui17.js +31 -0
  17. package/dist/composable-ui18.js +4 -0
  18. package/dist/composable-ui19.js +4 -0
  19. package/dist/composable-ui2.js +55 -0
  20. package/dist/composable-ui20.js +4 -0
  21. package/dist/composable-ui21.js +100 -0
  22. package/dist/composable-ui22.js +144 -0
  23. package/dist/composable-ui23.js +7 -0
  24. package/dist/composable-ui24.js +7 -0
  25. package/dist/composable-ui3.js +4 -0
  26. package/dist/composable-ui4.js +4 -0
  27. package/dist/composable-ui5.js +4 -0
  28. package/dist/composable-ui6.js +4 -0
  29. package/dist/composable-ui7.js +4 -0
  30. package/dist/composable-ui8.js +4 -0
  31. package/dist/composable-ui9.js +4 -0
  32. package/dist/listbox.vue_vue_type_script_setup_true_lang-Bj1ZXiBX.js +69 -0
  33. package/dist/listboxOption.vue_vue_type_script_setup_true_lang-B_yRptJm.js +37 -0
  34. package/dist/menu.vue_vue_type_script_setup_true_lang-Ci7q2rOg.js +82 -0
  35. package/dist/menuItem.vue_vue_type_script_setup_true_lang-mXtMa4gO.js +63 -0
  36. package/dist/menuItems.vue_vue_type_script_setup_true_lang-p9vftREy.js +49 -0
  37. package/dist/popover.vue_vue_type_script_setup_true_lang-DhKF7_nY.js +50 -0
  38. package/dist/popoverDialog.vue_vue_type_script_setup_true_lang-CDXUO7wZ.js +33 -0
  39. package/dist/tab.vue_vue_type_script_setup_true_lang-Y5OFGqMB.js +29 -0
  40. package/dist/tabContainer.vue_vue_type_script_setup_true_lang-fPpLno2Z.js +40 -0
  41. package/dist/tabList.vue_vue_type_script_setup_true_lang-CZyqGCuj.js +48 -0
  42. package/dist/tabPanel.vue_vue_type_script_setup_true_lang-CGhP6SHR.js +31 -0
  43. package/dist/tooltip.vue_vue_type_script_setup_true_lang-DVKYJyfL.js +85 -0
  44. package/dist/types/components/combobox/combobox.vue.d.ts +45 -0
  45. package/dist/types/components/combobox/comboboxHiddenInput.vue.d.ts +6 -0
  46. package/dist/types/components/combobox/comboboxInput.vue.d.ts +9 -0
  47. package/dist/types/components/combobox/comboboxOption.vue.d.ts +20 -0
  48. package/dist/types/components/combobox/comboboxOptions.vue.d.ts +12 -0
  49. package/dist/types/components/injectionKeys.d.ts +43 -0
  50. package/dist/types/components/listbox/listbox.vue.d.ts +26 -0
  51. package/dist/types/components/listbox/listboxOption.vue.d.ts +20 -0
  52. package/dist/types/components/menu/menu.vue.d.ts +42 -0
  53. package/dist/types/components/menu/menuItem.vue.d.ts +24 -0
  54. package/dist/types/components/menu/menuItems.vue.d.ts +12 -0
  55. package/dist/types/components/popover/popover.vue.d.ts +40 -0
  56. package/dist/types/components/popover/popoverDialog.vue.d.ts +12 -0
  57. package/dist/types/components/tabs/tab.vue.d.ts +17 -0
  58. package/dist/types/components/tabs/tabContainer.vue.d.ts +19 -0
  59. package/dist/types/components/tabs/tabList.vue.d.ts +17 -0
  60. package/dist/types/components/tabs/tabPanel.vue.d.ts +15 -0
  61. package/dist/types/components/tooltip.vue.d.ts +34 -0
  62. package/dist/types/composables/formControl.d.ts +48 -0
  63. package/dist/types/composables/list.d.ts +107 -0
  64. package/dist/types/composables/listOption.d.ts +34 -0
  65. package/dist/types/composables/popover.d.ts +68 -0
  66. package/dist/types/main.d.ts +22 -0
  67. package/dist/types/utils/element.d.ts +3 -0
  68. package/package.json +28 -12
  69. package/.github/workflows/deploy.yml +0 -21
  70. package/.github/workflows/docs.yml +0 -62
  71. package/.vscode/extensions.json +0 -7
  72. package/docs/.vitepress/config.mts +0 -40
  73. package/docs/.vitepress/theme/index.js +0 -4
  74. package/docs/.vitepress/theme/style.scss +0 -155
  75. package/docs/components/combobox.md +0 -174
  76. package/docs/components/demos/combobox.vue +0 -142
  77. package/docs/components/demos/combobox_autocomplete.vue +0 -75
  78. package/docs/components/demos/combobox_tags.vue +0 -127
  79. package/docs/components/demos/input.vue +0 -35
  80. package/docs/components/demos/listbox.vue +0 -64
  81. package/docs/components/demos/menu.vue +0 -93
  82. package/docs/components/demos/popover.vue +0 -16
  83. package/docs/components/demos/tabs.vue +0 -59
  84. package/docs/components/demos/tooltip.vue +0 -27
  85. package/docs/components/listbox.md +0 -9
  86. package/docs/components/menu.md +0 -121
  87. package/docs/components/popover.md +0 -82
  88. package/docs/components/tabs.md +0 -9
  89. package/docs/components/tooltip.md +0 -78
  90. package/docs/composables/form-control.md +0 -130
  91. package/docs/composables/list-option.md +0 -47
  92. package/docs/composables/list.md +0 -192
  93. package/docs/composables/popover.md +0 -90
  94. package/docs/index.md +0 -24
  95. package/docs/intro.md +0 -0
  96. package/src/components/combobox/combobox.vue +0 -229
  97. package/src/components/combobox/comboboxFormInput.vue +0 -33
  98. package/src/components/combobox/comboboxOption.vue +0 -52
  99. package/src/components/combobox/comboboxOptions.vue +0 -17
  100. package/src/components/injectionKeys.ts +0 -50
  101. package/src/components/listbox/listbox.vue +0 -91
  102. package/src/components/listbox/listboxOption.vue +0 -37
  103. package/src/components/menu/menu.vue +0 -100
  104. package/src/components/menu/menuItem.vue +0 -86
  105. package/src/components/menu/menuItems.vue +0 -51
  106. package/src/components/popover/popover.vue +0 -68
  107. package/src/components/popover/popoverDialog.vue +0 -35
  108. package/src/components/tabs/tab.vue +0 -35
  109. package/src/components/tabs/tabContainer.vue +0 -50
  110. package/src/components/tabs/tabList.vue +0 -52
  111. package/src/components/tabs/tabPanel.vue +0 -36
  112. package/src/components/tooltip.vue +0 -115
  113. package/src/composables/formControl.ts +0 -144
  114. package/src/composables/list.ts +0 -326
  115. package/src/composables/listOption.ts +0 -80
  116. package/src/composables/popover.ts +0 -306
  117. package/src/main.ts +0 -65
  118. package/src/utils/element.ts +0 -19
  119. package/src/utils/id.ts +0 -5
  120. package/src/vite-env.d.ts +0 -1
  121. package/tsconfig.json +0 -27
  122. package/tsconfig.node.json +0 -10
  123. package/vite.config.ts +0 -28
@@ -1,115 +0,0 @@
1
- <template>
2
- <slot :attrs="activatorAttrs" />
3
-
4
- <Teleport to="body">
5
- <div
6
- ref="popupEl"
7
- v-if="isOpen"
8
- :id="tooltipId"
9
- v-bind="$attrs"
10
- role="tooltip"
11
- >
12
- <slot name="content">{{ text }}</slot>
13
- </div>
14
- </Teleport>
15
- </template>
16
-
17
- <script setup lang="ts">
18
- import { onBeforeUnmount, onMounted, ref, useSlots } from "vue";
19
- import { useSequentialId } from "../utils/id";
20
- import { usePopover } from "../composables/popover";
21
-
22
- defineOptions({
23
- inheritAttrs: false,
24
- });
25
-
26
- const props = withDefaults(
27
- defineProps<{
28
- id?: string;
29
- text?: string;
30
- delay?: string | number;
31
- direction?: "up" | "down" | "left" | "right";
32
- }>(),
33
- {
34
- direction: "up",
35
- }
36
- );
37
- const slots = useSlots();
38
-
39
- const popupEl = ref();
40
- let timer: NodeJS.Timeout;
41
-
42
- const tooltipId = props.id ?? useSequentialId("tooltip");
43
-
44
- const { isOpen } = usePopover(`[aria-describedby=${tooltipId}]`, popupEl, {
45
- direction: props.direction,
46
- align: "center",
47
- });
48
-
49
- function open() {
50
- timer = setTimeout(
51
- () => {
52
- isOpen.value = true;
53
- },
54
- typeof props.delay === "string" ? parseInt(props.delay) : props.delay
55
- );
56
- }
57
-
58
- function close() {
59
- isOpen.value = false;
60
- clearTimeout(timer);
61
- }
62
-
63
- function onKeyDown(evt: KeyboardEvent) {
64
- if (evt.key === "Escape") {
65
- close();
66
- }
67
- }
68
-
69
- const activatorAttrs = {
70
- "aria-describedby": tooltipId,
71
- onmouseenter: open,
72
- onmouseleave: close,
73
- onfocus: open,
74
- onblur: close,
75
- onkeydown: onKeyDown,
76
- };
77
-
78
- const controller = new AbortController();
79
-
80
- onMounted(() => {
81
- if (slots.default) return;
82
- const activator = document.querySelector(
83
- `[aria-describedby=${tooltipId}]`
84
- ) as HTMLElement;
85
- if (!activator) {
86
- throw new Error(`Tooltip activator not found: ${tooltipId}`);
87
- }
88
- activator.addEventListener("mouseenter", open, {
89
- signal: controller.signal,
90
- passive: true,
91
- });
92
- activator.addEventListener("mouseleave", close, {
93
- signal: controller.signal,
94
- passive: true,
95
- });
96
- activator.addEventListener("focus", open, {
97
- signal: controller.signal,
98
- passive: true,
99
- });
100
- activator.addEventListener("blur", close, {
101
- signal: controller.signal,
102
- passive: true,
103
- });
104
- activator.addEventListener("keydown", onKeyDown, {
105
- signal: controller.signal,
106
- passive: true,
107
- });
108
- });
109
-
110
- onBeforeUnmount(() => {
111
- controller.abort();
112
- });
113
- </script>
114
-
115
- <style scoped></style>
@@ -1,144 +0,0 @@
1
- import type { MaybeRef, Ref } from "vue";
2
- import { ref, unref, onBeforeUnmount, onMounted, readonly } from "vue";
3
-
4
- import type { TemplateRefOrSelector } from "../utils/element";
5
- import { useHTMLElement } from "../utils/element";
6
-
7
- type FormElement = HTMLInputElement | HTMLTextAreaElement | HTMLSelectElement;
8
-
9
- /**
10
- * A validating function must return `true` or a string describing the error
11
- */
12
- export type FormValidator = (value: string) => boolean | string;
13
-
14
- export interface useFormControlReturn {
15
- /**
16
- * Focus the form control
17
- */
18
- focus: () => void;
19
- /**
20
- * Validate the form control
21
- *
22
- * @returns Validation result
23
- */
24
- validate: () => boolean;
25
- /**
26
- * Whether the form control is valid. A shorthand for `validity.valid`, but can be manually overriden.
27
- */
28
- isValid: Ref<boolean>;
29
- /**
30
- * The validity state of the form control
31
- *
32
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/API/ValidityState}
33
- */
34
- validity: Readonly<Ref<ValidityState | undefined>>;
35
- /**
36
- * A string representing a localized message that describes the validation constraints that the control does not satisfy (if any)
37
- */
38
- validationMessage: Readonly<Ref<string>>;
39
- /**
40
- * Whether the value has been changed since the form control was mounted
41
- */
42
- isChanged: Ref<boolean>;
43
- }
44
-
45
- /**
46
- * Utilizes Constraint Validation API to enable custom validation constrains for a form control
47
- *
48
- * @param el A template ref or a CSS selector
49
- * @param validators An array of validating functions
50
- * @param showValidationError Whether to show the default browser validation error (true by default)
51
- *
52
- * @see {@link https://developer.mozilla.org/en-US/docs/Web/HTML/Constraint_validation}
53
- */
54
- export function useFormControl(
55
- el: TemplateRefOrSelector<FormElement>,
56
- validators: MaybeRef<FormValidator[]> = [],
57
- showValidationError: MaybeRef<boolean> = true
58
- ): useFormControlReturn {
59
- const isChanged = ref(false);
60
- const isValid = ref(true);
61
- const validity = ref<ValidityState>();
62
- const validationMessage = ref("");
63
-
64
- let formElement: FormElement | undefined;
65
- let initValue: string;
66
-
67
- function focus() {
68
- formElement?.focus();
69
- }
70
-
71
- function updateValidationState() {
72
- isValid.value = formElement!.validity.valid;
73
- validity.value = formElement!.validity;
74
- validationMessage.value = formElement!.validationMessage;
75
- }
76
-
77
- function validate() {
78
- if (!formElement) throw new Error("Form element is undefined");
79
- formElement.setCustomValidity("");
80
-
81
- if (formElement.validity.valid) {
82
- const value = formElement.value;
83
- for (const validator of unref(validators)) {
84
- const check = validator(value);
85
- if (check !== true) {
86
- formElement.setCustomValidity(check as string);
87
- break;
88
- }
89
- }
90
- }
91
-
92
- updateValidationState();
93
- return isValid.value;
94
- }
95
-
96
- function onInvalid(event: Event) {
97
- updateValidationState();
98
- if (!unref(showValidationError)) {
99
- event.preventDefault();
100
- }
101
- }
102
-
103
- function onChange() {
104
- validate();
105
- isChanged.value = initValue !== formElement!.value;
106
- }
107
-
108
- let abortController = new AbortController();
109
-
110
- onMounted(() => {
111
- formElement = useHTMLElement(el).value;
112
- if (!formElement) throw new Error("Form element is undefined");
113
-
114
- initValue = formElement.value;
115
-
116
- formElement.addEventListener("change", onChange, {
117
- signal: abortController.signal,
118
- passive: true,
119
- });
120
- formElement.addEventListener("invalid", onInvalid, {
121
- signal: abortController.signal,
122
- });
123
-
124
- // Fix autofocus?
125
- if (formElement?.autofocus) {
126
- focus();
127
- }
128
- });
129
-
130
- onBeforeUnmount(() => {
131
- abortController.abort();
132
- });
133
-
134
- return {
135
- focus,
136
- validate,
137
-
138
- isValid,
139
- validity: readonly(validity),
140
- validationMessage: readonly(validationMessage),
141
-
142
- isChanged,
143
- };
144
- }
@@ -1,326 +0,0 @@
1
- import type { ComputedRef, MaybeRef, Ref, ShallowRef, InjectionKey } from "vue";
2
- import {
3
- ref,
4
- shallowRef,
5
- unref,
6
- provide,
7
- computed,
8
- readonly,
9
- shallowReadonly,
10
- triggerRef,
11
- } from "vue";
12
- import { useHTMLElement, TemplateRefOrSelector } from "../utils/element";
13
-
14
- export type ItemValue = unknown;
15
- export interface Item {
16
- id: number;
17
- element: Ref<HTMLElement | undefined>;
18
- value: ItemValue;
19
- disabled: MaybeRef<boolean>;
20
- }
21
-
22
- export interface ActivationOptions {
23
- /**
24
- * Focus the corresponding HTML element
25
- *
26
- * @defaultValue `false`
27
- */
28
- focus?: boolean;
29
- }
30
-
31
- interface NavigationOptions {
32
- /**
33
- * Infinitely cycle throught the items
34
- *
35
- * @defaultValue `false`
36
- */
37
- loop?: boolean;
38
- }
39
-
40
- export interface UseListReturn {
41
- /**
42
- * Array of items
43
- */
44
- items: Readonly<ShallowRef<Item[]>>;
45
- /**
46
- * Multiselection flag
47
- */
48
- isMultiselectable: Readonly<Ref<boolean>>;
49
- /**
50
- * Currently active item
51
- */
52
- activeItem: ComputedRef<Item | undefined>;
53
- /**
54
- * Select the currently active item
55
- */
56
- selectActiveItem: () => void;
57
- /**
58
- * Activate the currently selected item
59
- */
60
- activateSelectedItem: (options?: ActivationOptions) => void;
61
- /**
62
- * Activate the first item
63
- */
64
- activateFirstItem: (options?: ActivationOptions) => void;
65
- /**
66
- * Activate the last item
67
- */
68
- activateLastItem: (options?: ActivationOptions) => void;
69
- /**
70
- * Activate next item
71
- */
72
- activateNextItem: (options?: ActivationOptions & NavigationOptions) => void;
73
- /**
74
- * Activate previous item
75
- */
76
- activatePrevItem: (options?: ActivationOptions & NavigationOptions) => void;
77
- }
78
-
79
- interface UseListInjectionKey {
80
- /**
81
- * The list value
82
- */
83
- value: Readonly<Ref<unknown>>;
84
- /**
85
- * Select an item by ID
86
- */
87
- selectItem: (itemId: number) => void;
88
- /**
89
- * Activate an item by ID
90
- */
91
- activateItem: (itemId: number, options?: ActivationOptions) => void;
92
- /**
93
- * Check if an item is selected
94
- */
95
- isSelected: (itemId: number) => boolean;
96
- /**
97
- * Check if an item is active
98
- */
99
- isActive: (itemId: number) => boolean;
100
- /**
101
- * Add an item to the list
102
- *
103
- * @returns New item ID
104
- */
105
- addItem: (
106
- itemEl: TemplateRefOrSelector,
107
- itemVal: ItemValue,
108
- disabled?: MaybeRef<boolean>
109
- ) => number;
110
- /**
111
- * Remove an item from the list by ID
112
- */
113
- removeItem: (itemId: number) => void;
114
- }
115
-
116
- export const injectList: InjectionKey<UseListInjectionKey> = Symbol();
117
-
118
- function isValuesEqual(v1: ItemValue, v2: ItemValue) {
119
- const [_v1, _v2] = [unref(v1), unref(v2)];
120
- if (typeof _v1 === "object") {
121
- if (typeof _v2 === "object") {
122
- return JSON.stringify(_v1) === JSON.stringify(_v2);
123
- }
124
- return false;
125
- }
126
- return _v1 === _v2;
127
- }
128
-
129
- /**
130
- * Creates a reactive list of HTML elements with assigned values.
131
- *
132
- * @param value A ref to store the list value. Set to an array to enable multiselection.
133
- */
134
- export function useList(value: Ref<unknown>): UseListReturn {
135
- let lastId = 0;
136
-
137
- const items: ShallowRef<Item[]> = shallowRef([]);
138
- const activeItemId: Ref<number | undefined> = ref();
139
-
140
- const isMultiselectable = computed(() => Array.isArray(value.value));
141
-
142
- function getItem(itemId: number) {
143
- const item = items.value.find((_item) => {
144
- return _item.id === itemId;
145
- });
146
- if (!item) throw new Error(`Item not found: (${itemId})`);
147
- return item;
148
- }
149
-
150
- function focusItem(item: Item) {
151
- const el = unref(item.element);
152
- if (!el) return;
153
- el.focus();
154
- return el;
155
- }
156
-
157
- function activateItem(
158
- item?: Item,
159
- { focus = false }: ActivationOptions = {}
160
- ) {
161
- activeItemId.value = item?.id ?? undefined;
162
- if (item !== undefined && focus) focusItem(item);
163
- }
164
-
165
- function activateItemById(
166
- itemId: number,
167
- { focus = false }: ActivationOptions = {}
168
- ) {
169
- const item = getItem(itemId);
170
- return activateItem(item, { focus });
171
- }
172
-
173
- function isActive(itemId: number) {
174
- return activeItemId.value === itemId;
175
- }
176
-
177
- function addItem(
178
- itemEl: TemplateRefOrSelector,
179
- itemVal: ItemValue,
180
- disabled: MaybeRef<boolean> = false
181
- ) {
182
- const el = useHTMLElement(itemEl);
183
- const id = lastId++;
184
- items.value.push({
185
- id,
186
- value: itemVal,
187
- element: el,
188
- disabled,
189
- });
190
- triggerRef(items);
191
- return id;
192
- }
193
-
194
- function removeItem(itemId: number) {
195
- const item = getItem(itemId);
196
- const idx = items.value.indexOf(item);
197
- items.value.splice(idx, 1);
198
- triggerRef(items);
199
- if (isActive(itemId)) {
200
- activateItem();
201
- }
202
- }
203
-
204
- function selectItem(itemId: number) {
205
- const item = getItem(itemId);
206
- if (unref(item.disabled)) return;
207
- const v = unref(item.value);
208
- if (v === undefined) return;
209
- if (unref(isMultiselectable)) {
210
- const idx = (value.value as ItemValue[]).findIndex((iv) =>
211
- isValuesEqual(v, iv)
212
- );
213
- if (idx > -1) {
214
- (value.value as ItemValue[]).splice(idx, 1);
215
- } else {
216
- value.value = [...(value.value as ItemValue[]), v];
217
- }
218
- } else {
219
- value.value = v;
220
- }
221
- activateItem(item);
222
- }
223
-
224
- function isSelected(item: Item) {
225
- return unref(isMultiselectable)
226
- ? !!(value.value as ItemValue[]).find((iv) =>
227
- isValuesEqual(item.value, iv)
228
- )
229
- : isValuesEqual(value, item.value);
230
- }
231
-
232
- function isSelectedById(itemId: number) {
233
- try {
234
- const item = getItem(itemId);
235
- return isSelected(item);
236
- } catch {
237
- return false;
238
- }
239
- }
240
-
241
- function activateSelectedItem({ focus = false }: ActivationOptions = {}) {
242
- for (let item of items.value) {
243
- if (isSelected(item)) {
244
- return activateItem(item, { focus });
245
- }
246
- }
247
- }
248
-
249
- function activateFirstItem({ focus = false }: ActivationOptions = {}) {
250
- if (!items.value.length) return;
251
- return activateItem(items.value[0], { focus });
252
- }
253
-
254
- function activateLastItem({ focus = false }: ActivationOptions = {}) {
255
- if (!items.value.length) return;
256
- return activateItem(items.value[items.value.length - 1], { focus });
257
- }
258
-
259
- function activateNextItem({
260
- focus = false,
261
- loop = false,
262
- }: ActivationOptions & NavigationOptions = {}) {
263
- if (activeItemId.value === undefined) return activateFirstItem({ focus });
264
- const item = getItem(activeItemId.value);
265
- const idx = items.value.indexOf(item);
266
- let nextItem: Item;
267
- if (idx + 1 < items.value.length) {
268
- nextItem = items.value[idx + 1];
269
- } else {
270
- if (loop) {
271
- nextItem = items.value[0];
272
- } else {
273
- return;
274
- }
275
- }
276
- return activateItem(nextItem, { focus });
277
- }
278
-
279
- function activatePrevItem({
280
- focus = false,
281
- loop = false,
282
- }: ActivationOptions & NavigationOptions = {}) {
283
- if (activeItemId.value === undefined) return activateLastItem({ focus });
284
- const item = getItem(activeItemId.value);
285
- const idx = items.value.indexOf(item);
286
- let prevItem: Item;
287
- if (idx - 1 > -1) {
288
- prevItem = items.value[idx - 1];
289
- } else {
290
- if (loop) {
291
- prevItem = items.value[items.value.length - 1];
292
- } else {
293
- return;
294
- }
295
- }
296
- return activateItem(prevItem, { focus });
297
- }
298
-
299
- provide(injectList, {
300
- value: readonly(value),
301
- selectItem,
302
- activateItem: activateItemById,
303
- isSelected: isSelectedById,
304
- isActive,
305
- addItem,
306
- removeItem,
307
- });
308
-
309
- return {
310
- items: shallowReadonly(items),
311
- isMultiselectable: readonly(isMultiselectable),
312
- activeItem: computed(() =>
313
- activeItemId.value !== undefined ? getItem(activeItemId.value) : undefined
314
- ),
315
- selectActiveItem: () => {
316
- if (activeItemId.value !== undefined) {
317
- selectItem(activeItemId.value);
318
- }
319
- },
320
- activateSelectedItem,
321
- activateFirstItem,
322
- activateLastItem,
323
- activateNextItem,
324
- activatePrevItem,
325
- };
326
- }
@@ -1,80 +0,0 @@
1
- import type { ComputedRef, MaybeRef } from "vue";
2
- import {
3
- ref,
4
- unref,
5
- inject,
6
- computed,
7
- onBeforeUnmount,
8
- onBeforeMount,
9
- } from "vue";
10
-
11
- import type { TemplateRefOrSelector } from "../utils/element";
12
-
13
- import type { ItemValue, ActivationOptions } from "./list";
14
- import { injectList } from "./list";
15
-
16
- interface UseListOptionReturn {
17
- /**
18
- * Whether the item is selected
19
- */
20
- isSelected: ComputedRef<boolean>;
21
- /**
22
- * Whether the item is active
23
- */
24
- isActive: ComputedRef<boolean>;
25
- /**
26
- * Select the item
27
- */
28
- select: () => void;
29
- /**
30
- * Activate the item
31
- */
32
- activate: (options?: ActivationOptions) => void;
33
- }
34
-
35
- /**
36
- * Registers an HTML element and an associated value in the list created in the parent component
37
- *
38
- * @param el A template ref or a CSS selector
39
- * @param value A value of any type
40
- * @param disabled Whether the item is disabled (false by default)
41
- */
42
- export function useListOption(
43
- el: TemplateRefOrSelector,
44
- value: ItemValue,
45
- disabled?: MaybeRef<boolean>
46
- ): UseListOptionReturn {
47
- const list = inject(injectList);
48
- if (!list) {
49
- throw new Error("List injectable context is not provided");
50
- }
51
-
52
- const itemId = ref(-1);
53
-
54
- const _isSelected = computed(() => list.isSelected(itemId.value));
55
- const _isActive = computed(() => list.isActive(itemId.value));
56
-
57
- function select() {
58
- list!.selectItem(itemId.value);
59
- }
60
-
61
- function activate({ focus = true } = {}) {
62
- if (unref(disabled)) return;
63
- list!.activateItem(itemId.value, { focus });
64
- }
65
-
66
- onBeforeMount(() => {
67
- itemId.value = list.addItem(el, value, disabled);
68
- });
69
-
70
- onBeforeUnmount(() => {
71
- list.removeItem(itemId.value);
72
- });
73
-
74
- return {
75
- isSelected: _isSelected,
76
- isActive: _isActive,
77
- select,
78
- activate,
79
- };
80
- }