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.
- package/LICENSE +1 -1
- package/README.md +5 -1
- package/dist/combobox.vue_vue_type_script_setup_true_lang-BhVMcx67.js +140 -0
- package/dist/comboboxHiddenInput.vue_vue_type_script_setup_true_lang-Ba-UPd-M.js +29 -0
- package/dist/comboboxInput.vue_vue_type_script_setup_true_lang-DzRfJ5ke.js +33 -0
- package/dist/comboboxOption.vue_vue_type_script_setup_true_lang-OyJxB4Jk.js +42 -0
- package/dist/comboboxOptions.vue_vue_type_script_setup_true_lang-Doy6MfEQ.js +20 -0
- package/dist/composable-ui.js +49 -0
- package/dist/composable-ui10.js +4 -0
- package/dist/composable-ui11.js +4 -0
- package/dist/composable-ui12.js +4 -0
- package/dist/composable-ui13.js +4 -0
- package/dist/composable-ui14.js +4 -0
- package/dist/composable-ui15.js +4 -0
- package/dist/composable-ui16.js +4 -0
- package/dist/composable-ui17.js +31 -0
- package/dist/composable-ui18.js +4 -0
- package/dist/composable-ui19.js +4 -0
- package/dist/composable-ui2.js +55 -0
- package/dist/composable-ui20.js +4 -0
- package/dist/composable-ui21.js +100 -0
- package/dist/composable-ui22.js +144 -0
- package/dist/composable-ui23.js +7 -0
- package/dist/composable-ui24.js +7 -0
- package/dist/composable-ui3.js +4 -0
- package/dist/composable-ui4.js +4 -0
- package/dist/composable-ui5.js +4 -0
- package/dist/composable-ui6.js +4 -0
- package/dist/composable-ui7.js +4 -0
- package/dist/composable-ui8.js +4 -0
- package/dist/composable-ui9.js +4 -0
- package/dist/listbox.vue_vue_type_script_setup_true_lang-Bj1ZXiBX.js +69 -0
- package/dist/listboxOption.vue_vue_type_script_setup_true_lang-B_yRptJm.js +37 -0
- package/dist/menu.vue_vue_type_script_setup_true_lang-Ci7q2rOg.js +82 -0
- package/dist/menuItem.vue_vue_type_script_setup_true_lang-mXtMa4gO.js +63 -0
- package/dist/menuItems.vue_vue_type_script_setup_true_lang-p9vftREy.js +49 -0
- package/dist/popover.vue_vue_type_script_setup_true_lang-DhKF7_nY.js +50 -0
- package/dist/popoverDialog.vue_vue_type_script_setup_true_lang-CDXUO7wZ.js +33 -0
- package/dist/tab.vue_vue_type_script_setup_true_lang-Y5OFGqMB.js +29 -0
- package/dist/tabContainer.vue_vue_type_script_setup_true_lang-fPpLno2Z.js +40 -0
- package/dist/tabList.vue_vue_type_script_setup_true_lang-CZyqGCuj.js +48 -0
- package/dist/tabPanel.vue_vue_type_script_setup_true_lang-CGhP6SHR.js +31 -0
- package/dist/tooltip.vue_vue_type_script_setup_true_lang-DVKYJyfL.js +85 -0
- package/dist/types/components/combobox/combobox.vue.d.ts +45 -0
- package/dist/types/components/combobox/comboboxHiddenInput.vue.d.ts +6 -0
- package/dist/types/components/combobox/comboboxInput.vue.d.ts +9 -0
- package/dist/types/components/combobox/comboboxOption.vue.d.ts +20 -0
- package/dist/types/components/combobox/comboboxOptions.vue.d.ts +12 -0
- package/dist/types/components/injectionKeys.d.ts +43 -0
- package/dist/types/components/listbox/listbox.vue.d.ts +26 -0
- package/dist/types/components/listbox/listboxOption.vue.d.ts +20 -0
- package/dist/types/components/menu/menu.vue.d.ts +42 -0
- package/dist/types/components/menu/menuItem.vue.d.ts +24 -0
- package/dist/types/components/menu/menuItems.vue.d.ts +12 -0
- package/dist/types/components/popover/popover.vue.d.ts +40 -0
- package/dist/types/components/popover/popoverDialog.vue.d.ts +12 -0
- package/dist/types/components/tabs/tab.vue.d.ts +17 -0
- package/dist/types/components/tabs/tabContainer.vue.d.ts +19 -0
- package/dist/types/components/tabs/tabList.vue.d.ts +17 -0
- package/dist/types/components/tabs/tabPanel.vue.d.ts +15 -0
- package/dist/types/components/tooltip.vue.d.ts +34 -0
- package/dist/types/composables/formControl.d.ts +48 -0
- package/dist/types/composables/list.d.ts +107 -0
- package/dist/types/composables/listOption.d.ts +34 -0
- package/dist/types/composables/popover.d.ts +68 -0
- package/dist/types/main.d.ts +22 -0
- package/dist/types/utils/element.d.ts +3 -0
- package/package.json +28 -12
- package/.github/workflows/deploy.yml +0 -21
- package/.github/workflows/docs.yml +0 -62
- package/.vscode/extensions.json +0 -7
- package/docs/.vitepress/config.mts +0 -40
- package/docs/.vitepress/theme/index.js +0 -4
- package/docs/.vitepress/theme/style.scss +0 -155
- package/docs/components/combobox.md +0 -174
- package/docs/components/demos/combobox.vue +0 -142
- package/docs/components/demos/combobox_autocomplete.vue +0 -75
- package/docs/components/demos/combobox_tags.vue +0 -127
- package/docs/components/demos/input.vue +0 -35
- package/docs/components/demos/listbox.vue +0 -64
- package/docs/components/demos/menu.vue +0 -93
- package/docs/components/demos/popover.vue +0 -16
- package/docs/components/demos/tabs.vue +0 -59
- package/docs/components/demos/tooltip.vue +0 -27
- package/docs/components/listbox.md +0 -9
- package/docs/components/menu.md +0 -121
- package/docs/components/popover.md +0 -82
- package/docs/components/tabs.md +0 -9
- package/docs/components/tooltip.md +0 -78
- package/docs/composables/form-control.md +0 -130
- package/docs/composables/list-option.md +0 -47
- package/docs/composables/list.md +0 -192
- package/docs/composables/popover.md +0 -90
- package/docs/index.md +0 -24
- package/docs/intro.md +0 -0
- package/src/components/combobox/combobox.vue +0 -229
- package/src/components/combobox/comboboxFormInput.vue +0 -33
- package/src/components/combobox/comboboxOption.vue +0 -52
- package/src/components/combobox/comboboxOptions.vue +0 -17
- package/src/components/injectionKeys.ts +0 -50
- package/src/components/listbox/listbox.vue +0 -91
- package/src/components/listbox/listboxOption.vue +0 -37
- package/src/components/menu/menu.vue +0 -100
- package/src/components/menu/menuItem.vue +0 -86
- package/src/components/menu/menuItems.vue +0 -51
- package/src/components/popover/popover.vue +0 -68
- package/src/components/popover/popoverDialog.vue +0 -35
- package/src/components/tabs/tab.vue +0 -35
- package/src/components/tabs/tabContainer.vue +0 -50
- package/src/components/tabs/tabList.vue +0 -52
- package/src/components/tabs/tabPanel.vue +0 -36
- package/src/components/tooltip.vue +0 -115
- package/src/composables/formControl.ts +0 -144
- package/src/composables/list.ts +0 -326
- package/src/composables/listOption.ts +0 -80
- package/src/composables/popover.ts +0 -306
- package/src/main.ts +0 -65
- package/src/utils/element.ts +0 -19
- package/src/utils/id.ts +0 -5
- package/src/vite-env.d.ts +0 -1
- package/tsconfig.json +0 -27
- package/tsconfig.node.json +0 -10
- package/vite.config.ts +0 -28
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div
|
|
3
|
-
@keydown="onKeyDown"
|
|
4
|
-
:aria-activedescendant="activeItemId"
|
|
5
|
-
:aria-orientation="orientation"
|
|
6
|
-
:aria-multiselectable="multiselectable"
|
|
7
|
-
role="listbox"
|
|
8
|
-
tabindex="0"
|
|
9
|
-
>
|
|
10
|
-
<slot />
|
|
11
|
-
</div>
|
|
12
|
-
</template>
|
|
13
|
-
|
|
14
|
-
<script setup lang="ts">
|
|
15
|
-
import { computed } from "vue";
|
|
16
|
-
import { useList } from "../../composables/list";
|
|
17
|
-
|
|
18
|
-
const props = withDefaults(
|
|
19
|
-
defineProps<{
|
|
20
|
-
orientation?: "horizontal" | "vertical";
|
|
21
|
-
multiselectable?: boolean;
|
|
22
|
-
loop?: boolean;
|
|
23
|
-
}>(),
|
|
24
|
-
{
|
|
25
|
-
orientation: "vertical",
|
|
26
|
-
multiselectable: false,
|
|
27
|
-
loop: false,
|
|
28
|
-
}
|
|
29
|
-
);
|
|
30
|
-
|
|
31
|
-
const model = defineModel();
|
|
32
|
-
|
|
33
|
-
const {
|
|
34
|
-
isMultiselectable,
|
|
35
|
-
activeItem,
|
|
36
|
-
selectActiveItem,
|
|
37
|
-
activateFirstItem,
|
|
38
|
-
activateLastItem,
|
|
39
|
-
activateNextItem,
|
|
40
|
-
activatePrevItem,
|
|
41
|
-
} = useList(model);
|
|
42
|
-
|
|
43
|
-
const activeItemId = computed(() => activeItem.value?.element.value?.id);
|
|
44
|
-
|
|
45
|
-
function onKeyDown(evt: KeyboardEvent) {
|
|
46
|
-
switch (evt.code) {
|
|
47
|
-
case "Space":
|
|
48
|
-
selectActiveItem();
|
|
49
|
-
break;
|
|
50
|
-
case "ArrowUp":
|
|
51
|
-
if (props.orientation === "horizontal") return;
|
|
52
|
-
activatePrevItem({ focus: false, loop: props.loop });
|
|
53
|
-
if (!isMultiselectable.value) {
|
|
54
|
-
selectActiveItem();
|
|
55
|
-
}
|
|
56
|
-
break;
|
|
57
|
-
case "ArrowDown":
|
|
58
|
-
if (props.orientation === "horizontal") return;
|
|
59
|
-
activateNextItem({ focus: false, loop: props.loop });
|
|
60
|
-
if (!isMultiselectable.value) {
|
|
61
|
-
selectActiveItem();
|
|
62
|
-
}
|
|
63
|
-
break;
|
|
64
|
-
case "ArrowLeft":
|
|
65
|
-
if (props.orientation === "vertical") return;
|
|
66
|
-
activatePrevItem({ focus: false, loop: props.loop });
|
|
67
|
-
if (!isMultiselectable.value) {
|
|
68
|
-
selectActiveItem();
|
|
69
|
-
}
|
|
70
|
-
break;
|
|
71
|
-
case "ArrowRight":
|
|
72
|
-
if (props.orientation === "vertical") return;
|
|
73
|
-
activateNextItem({ focus: false, loop: props.loop });
|
|
74
|
-
if (!isMultiselectable.value) {
|
|
75
|
-
selectActiveItem();
|
|
76
|
-
}
|
|
77
|
-
break;
|
|
78
|
-
case "Home":
|
|
79
|
-
activateFirstItem({ focus: false });
|
|
80
|
-
break;
|
|
81
|
-
case "End":
|
|
82
|
-
activateLastItem({ focus: false });
|
|
83
|
-
break;
|
|
84
|
-
default:
|
|
85
|
-
return;
|
|
86
|
-
}
|
|
87
|
-
evt.preventDefault();
|
|
88
|
-
}
|
|
89
|
-
</script>
|
|
90
|
-
|
|
91
|
-
<style scoped></style>
|
|
@@ -1,37 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div
|
|
3
|
-
ref="itemEl"
|
|
4
|
-
:id="itemId"
|
|
5
|
-
@click="select"
|
|
6
|
-
:aria-disabled="disabled"
|
|
7
|
-
:aria-selected="isSelected"
|
|
8
|
-
:data-active="isActive"
|
|
9
|
-
role="option"
|
|
10
|
-
tabindex="-1"
|
|
11
|
-
>
|
|
12
|
-
<slot :isSelected="isSelected" :isActive="isActive" />
|
|
13
|
-
</div>
|
|
14
|
-
</template>
|
|
15
|
-
|
|
16
|
-
<script setup lang="ts">
|
|
17
|
-
import { ref } from "vue";
|
|
18
|
-
import { useSequentialId } from "../../utils/id";
|
|
19
|
-
import { useListOption } from "../../composables/listOption";
|
|
20
|
-
|
|
21
|
-
const props = defineProps<{
|
|
22
|
-
id?: string;
|
|
23
|
-
value?: any;
|
|
24
|
-
disabled?: boolean;
|
|
25
|
-
}>();
|
|
26
|
-
|
|
27
|
-
const itemId = props.id ?? useSequentialId("list-option");
|
|
28
|
-
|
|
29
|
-
const itemEl = ref<HTMLElement>();
|
|
30
|
-
const { isSelected, isActive, select } = useListOption(
|
|
31
|
-
itemEl,
|
|
32
|
-
props.value,
|
|
33
|
-
props.disabled
|
|
34
|
-
);
|
|
35
|
-
</script>
|
|
36
|
-
|
|
37
|
-
<style scoped></style>
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<slot :attrs="activatorAttrs"></slot>
|
|
3
|
-
</template>
|
|
4
|
-
|
|
5
|
-
<script setup lang="ts">
|
|
6
|
-
import { computed, provide, nextTick } from "vue";
|
|
7
|
-
import { useSequentialId } from "../../utils/id";
|
|
8
|
-
import { usePopover } from "../../composables/popover";
|
|
9
|
-
import { useList } from "../../composables/list";
|
|
10
|
-
import { injectMenu } from "../injectionKeys";
|
|
11
|
-
|
|
12
|
-
const props = withDefaults(
|
|
13
|
-
defineProps<{
|
|
14
|
-
id?: string;
|
|
15
|
-
activatorId?: string;
|
|
16
|
-
direction?: "up" | "down" | "left" | "right";
|
|
17
|
-
align?: "top" | "bottom" | "left" | "right" | "center" | "stretch";
|
|
18
|
-
position?: "fixed" | "absolute";
|
|
19
|
-
}>(),
|
|
20
|
-
{
|
|
21
|
-
direction: "down",
|
|
22
|
-
align: "left",
|
|
23
|
-
position: "fixed",
|
|
24
|
-
}
|
|
25
|
-
);
|
|
26
|
-
|
|
27
|
-
const menuId = props.id ?? useSequentialId("menu");
|
|
28
|
-
const activatorId = props.activatorId ?? useSequentialId("menu-activator");
|
|
29
|
-
|
|
30
|
-
const model = defineModel();
|
|
31
|
-
|
|
32
|
-
const {
|
|
33
|
-
isMultiselectable,
|
|
34
|
-
activeItem,
|
|
35
|
-
activateFirstItem,
|
|
36
|
-
activateLastItem,
|
|
37
|
-
activateNextItem,
|
|
38
|
-
activatePrevItem,
|
|
39
|
-
} = useList(model);
|
|
40
|
-
|
|
41
|
-
const { isOpen, toggle, open, close } = usePopover(
|
|
42
|
-
`#${activatorId}`,
|
|
43
|
-
`#${menuId}`,
|
|
44
|
-
{
|
|
45
|
-
direction: props.direction,
|
|
46
|
-
align: props.align,
|
|
47
|
-
position: props.position,
|
|
48
|
-
closeOnOutsideClick: true,
|
|
49
|
-
closeOnInsideClick: false,
|
|
50
|
-
}
|
|
51
|
-
);
|
|
52
|
-
|
|
53
|
-
function onActivatorKeyDown(evt: KeyboardEvent) {
|
|
54
|
-
switch (evt.code) {
|
|
55
|
-
case "Space":
|
|
56
|
-
case "Enter":
|
|
57
|
-
toggle();
|
|
58
|
-
if (isOpen.value) {
|
|
59
|
-
nextTick(activateFirstItem);
|
|
60
|
-
}
|
|
61
|
-
break;
|
|
62
|
-
case "ArrowUp":
|
|
63
|
-
open();
|
|
64
|
-
nextTick(activateLastItem);
|
|
65
|
-
break;
|
|
66
|
-
case "ArrowDown":
|
|
67
|
-
open();
|
|
68
|
-
nextTick(activateFirstItem);
|
|
69
|
-
break;
|
|
70
|
-
default:
|
|
71
|
-
return;
|
|
72
|
-
}
|
|
73
|
-
evt.preventDefault();
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
const activatorAttrs = computed(() => ({
|
|
77
|
-
id: activatorId,
|
|
78
|
-
"aria-controls": isOpen.value ? menuId : undefined,
|
|
79
|
-
"aria-haspopup": "menu" as "menu",
|
|
80
|
-
"aria-expanded": isOpen.value,
|
|
81
|
-
onclick: toggle,
|
|
82
|
-
onkeydown: onActivatorKeyDown,
|
|
83
|
-
tabindex: 0,
|
|
84
|
-
}));
|
|
85
|
-
|
|
86
|
-
provide(injectMenu, {
|
|
87
|
-
menuId: menuId,
|
|
88
|
-
activatorId: activatorId,
|
|
89
|
-
isOpen,
|
|
90
|
-
close,
|
|
91
|
-
isMultiselectable,
|
|
92
|
-
activeItemId: computed(() => activeItem.value?.element.value?.id),
|
|
93
|
-
activateFirstItem,
|
|
94
|
-
activateLastItem,
|
|
95
|
-
activateNextItem,
|
|
96
|
-
activatePrevItem,
|
|
97
|
-
});
|
|
98
|
-
</script>
|
|
99
|
-
|
|
100
|
-
<style scoped></style>
|
|
@@ -1,86 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div
|
|
3
|
-
ref="itemEl"
|
|
4
|
-
:id="itemId"
|
|
5
|
-
@click="onClick"
|
|
6
|
-
@keydown="onKeyDown"
|
|
7
|
-
@mouseenter="activate({ focus: false })"
|
|
8
|
-
:data-active="isActive"
|
|
9
|
-
:role="role"
|
|
10
|
-
:aria-checked="value !== undefined ? isSelected : undefined"
|
|
11
|
-
:aria-disabled="disabled || undefined"
|
|
12
|
-
tabindex="-1"
|
|
13
|
-
>
|
|
14
|
-
<slot :isSelected="isSelected" :isActive="isActive" />
|
|
15
|
-
</div>
|
|
16
|
-
</template>
|
|
17
|
-
|
|
18
|
-
<script setup lang="ts">
|
|
19
|
-
import { ref, inject, computed } from "vue";
|
|
20
|
-
import { useSequentialId } from "../../utils/id";
|
|
21
|
-
import { useListOption } from "../../composables/listOption";
|
|
22
|
-
import { injectMenu } from "../injectionKeys";
|
|
23
|
-
|
|
24
|
-
const props = defineProps<{
|
|
25
|
-
id?: string;
|
|
26
|
-
value?: any;
|
|
27
|
-
disabled?: boolean;
|
|
28
|
-
}>();
|
|
29
|
-
|
|
30
|
-
const emit = defineEmits<{
|
|
31
|
-
select: [value: any];
|
|
32
|
-
}>();
|
|
33
|
-
|
|
34
|
-
const itemId = props.id ?? useSequentialId("menu-item");
|
|
35
|
-
|
|
36
|
-
const itemEl = ref<HTMLElement>();
|
|
37
|
-
const { isSelected, isActive, select, activate } = useListOption(
|
|
38
|
-
itemEl,
|
|
39
|
-
props.value,
|
|
40
|
-
props.disabled
|
|
41
|
-
);
|
|
42
|
-
|
|
43
|
-
const menu = inject(injectMenu);
|
|
44
|
-
if (!menu) {
|
|
45
|
-
throw new Error("Menu injectable context is not provided");
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const role = computed(() => {
|
|
49
|
-
if (props.value !== undefined) {
|
|
50
|
-
return menu.isMultiselectable.value ? "menuitemcheckbox" : "menuitemradio";
|
|
51
|
-
}
|
|
52
|
-
return "menuitem";
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
function selectAndEmit() {
|
|
56
|
-
select();
|
|
57
|
-
emit("select", props.value);
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function onClick() {
|
|
61
|
-
selectAndEmit();
|
|
62
|
-
if (props.value === undefined || !menu?.isMultiselectable.value) {
|
|
63
|
-
menu!.close();
|
|
64
|
-
}
|
|
65
|
-
}
|
|
66
|
-
|
|
67
|
-
function onKeyDown(evt: KeyboardEvent) {
|
|
68
|
-
switch (evt.code) {
|
|
69
|
-
case "Space":
|
|
70
|
-
selectAndEmit();
|
|
71
|
-
if (props.value === undefined) {
|
|
72
|
-
menu!.close();
|
|
73
|
-
}
|
|
74
|
-
break;
|
|
75
|
-
case "Enter":
|
|
76
|
-
selectAndEmit();
|
|
77
|
-
menu!.close();
|
|
78
|
-
break;
|
|
79
|
-
default:
|
|
80
|
-
return;
|
|
81
|
-
}
|
|
82
|
-
evt.preventDefault();
|
|
83
|
-
}
|
|
84
|
-
</script>
|
|
85
|
-
|
|
86
|
-
<style scoped></style>
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div
|
|
3
|
-
v-if="menu!.isOpen.value"
|
|
4
|
-
@keydown="onKeyDown"
|
|
5
|
-
:id="menu!.menuId"
|
|
6
|
-
:aria-activedescendant="menu!.activeItemId.value"
|
|
7
|
-
:aria-labelledby="menu!.activatorId"
|
|
8
|
-
role="menu"
|
|
9
|
-
tabindex="-1"
|
|
10
|
-
>
|
|
11
|
-
<slot />
|
|
12
|
-
</div>
|
|
13
|
-
</template>
|
|
14
|
-
|
|
15
|
-
<script setup lang="ts">
|
|
16
|
-
import { inject } from "vue";
|
|
17
|
-
import { injectMenu } from "../injectionKeys";
|
|
18
|
-
|
|
19
|
-
const menu = inject(injectMenu);
|
|
20
|
-
if (!menu) {
|
|
21
|
-
throw new Error("Menu injectable context is not provided");
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
function onKeyDown(evt: KeyboardEvent) {
|
|
25
|
-
switch (evt.code) {
|
|
26
|
-
case "ArrowUp":
|
|
27
|
-
menu!.activatePrevItem({ focus: true, loop: false });
|
|
28
|
-
break;
|
|
29
|
-
case "ArrowDown":
|
|
30
|
-
menu!.activateNextItem({ focus: true, loop: false });
|
|
31
|
-
break;
|
|
32
|
-
case "Home":
|
|
33
|
-
menu!.activateFirstItem({ focus: true });
|
|
34
|
-
break;
|
|
35
|
-
case "End":
|
|
36
|
-
menu!.activateLastItem({ focus: true });
|
|
37
|
-
break;
|
|
38
|
-
case "Escape":
|
|
39
|
-
menu!.close();
|
|
40
|
-
break;
|
|
41
|
-
case "Tab":
|
|
42
|
-
menu!.isOpen.value = false;
|
|
43
|
-
return;
|
|
44
|
-
default:
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
evt.preventDefault();
|
|
48
|
-
}
|
|
49
|
-
</script>
|
|
50
|
-
|
|
51
|
-
<style scoped></style>
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<slot
|
|
3
|
-
:attrs="activatorAttrs"
|
|
4
|
-
:isOpen="isOpen"
|
|
5
|
-
:toggle="toggle"
|
|
6
|
-
:open="open"
|
|
7
|
-
:close="close"
|
|
8
|
-
></slot>
|
|
9
|
-
</template>
|
|
10
|
-
|
|
11
|
-
<script setup lang="ts">
|
|
12
|
-
import { provide, computed } from "vue";
|
|
13
|
-
import { useSequentialId } from "../../utils/id";
|
|
14
|
-
import { usePopover } from "../../composables/popover";
|
|
15
|
-
import { injectPopover } from "../injectionKeys";
|
|
16
|
-
|
|
17
|
-
const props = withDefaults(
|
|
18
|
-
defineProps<{
|
|
19
|
-
id?: string;
|
|
20
|
-
activatorId?: string;
|
|
21
|
-
direction?: "up" | "down" | "left" | "right";
|
|
22
|
-
align?: "top" | "bottom" | "left" | "right" | "center" | "stretch";
|
|
23
|
-
position?: "fixed" | "absolute";
|
|
24
|
-
closeOnOutsideClick?: boolean;
|
|
25
|
-
closeOnInsideClick?: boolean;
|
|
26
|
-
role?: "dialog" | "listbox" | "menu" | "tree" | "grid";
|
|
27
|
-
}>(),
|
|
28
|
-
{
|
|
29
|
-
id: useSequentialId("popover"),
|
|
30
|
-
activatorId: useSequentialId("popover-activator"),
|
|
31
|
-
direction: "down",
|
|
32
|
-
align: "left",
|
|
33
|
-
position: "fixed",
|
|
34
|
-
closeOnOutsideClick: true,
|
|
35
|
-
closeOnInsideClick: false,
|
|
36
|
-
role: "dialog",
|
|
37
|
-
}
|
|
38
|
-
);
|
|
39
|
-
|
|
40
|
-
const { isOpen, toggle, open, close } = usePopover(
|
|
41
|
-
`#${props.activatorId}`,
|
|
42
|
-
`#${props.id}`,
|
|
43
|
-
{
|
|
44
|
-
direction: props.direction,
|
|
45
|
-
align: props.align,
|
|
46
|
-
position: props.position,
|
|
47
|
-
closeOnOutsideClick: props.closeOnOutsideClick,
|
|
48
|
-
closeOnInsideClick: props.closeOnInsideClick,
|
|
49
|
-
}
|
|
50
|
-
);
|
|
51
|
-
|
|
52
|
-
const activatorAttrs = computed(() => ({
|
|
53
|
-
id: props.activatorId,
|
|
54
|
-
"aria-controls": isOpen.value ? props.id : undefined,
|
|
55
|
-
"aria-haspopup": props.role,
|
|
56
|
-
"aria-expanded": isOpen.value,
|
|
57
|
-
}));
|
|
58
|
-
|
|
59
|
-
provide(injectPopover, {
|
|
60
|
-
popoverId: props.id,
|
|
61
|
-
activatorId: props.activatorId,
|
|
62
|
-
role: props.role,
|
|
63
|
-
isOpen,
|
|
64
|
-
close,
|
|
65
|
-
});
|
|
66
|
-
</script>
|
|
67
|
-
|
|
68
|
-
<style scoped></style>
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div
|
|
3
|
-
v-if="popover!.isOpen.value"
|
|
4
|
-
@keydown="onKeyDown"
|
|
5
|
-
:id="popover!.popoverId"
|
|
6
|
-
:role="popover!.role"
|
|
7
|
-
:aria-labelledby="popover!.activatorId"
|
|
8
|
-
tabindex="-1"
|
|
9
|
-
>
|
|
10
|
-
<slot />
|
|
11
|
-
</div>
|
|
12
|
-
</template>
|
|
13
|
-
|
|
14
|
-
<script setup lang="ts">
|
|
15
|
-
import { inject } from "vue";
|
|
16
|
-
import { injectPopover } from "../injectionKeys";
|
|
17
|
-
|
|
18
|
-
const popover = inject(injectPopover);
|
|
19
|
-
if (!popover) {
|
|
20
|
-
throw new Error("Popover injectable context is not provided");
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
function onKeyDown(evt: KeyboardEvent) {
|
|
24
|
-
switch (evt.code) {
|
|
25
|
-
case "Escape":
|
|
26
|
-
popover!.close();
|
|
27
|
-
break;
|
|
28
|
-
default:
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
evt.preventDefault();
|
|
32
|
-
}
|
|
33
|
-
</script>
|
|
34
|
-
|
|
35
|
-
<style scoped></style>
|
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<button
|
|
3
|
-
ref="tab"
|
|
4
|
-
@click="select"
|
|
5
|
-
:v="value"
|
|
6
|
-
:id="tabId"
|
|
7
|
-
:aria-selected="isSelected"
|
|
8
|
-
:aria-controls="tabPanelId"
|
|
9
|
-
:tabindex="isSelected ? 0 : -1"
|
|
10
|
-
role="tab"
|
|
11
|
-
>
|
|
12
|
-
<slot />
|
|
13
|
-
</button>
|
|
14
|
-
</template>
|
|
15
|
-
|
|
16
|
-
<script setup lang="ts">
|
|
17
|
-
import { ref } from "vue";
|
|
18
|
-
import { useSequentialId } from "../../utils/id";
|
|
19
|
-
import { useListOption } from "../../composables/listOption";
|
|
20
|
-
|
|
21
|
-
const props = defineProps<{
|
|
22
|
-
id?: string;
|
|
23
|
-
ariaControls?: string;
|
|
24
|
-
value: any;
|
|
25
|
-
}>();
|
|
26
|
-
|
|
27
|
-
const tab = ref<HTMLButtonElement>();
|
|
28
|
-
|
|
29
|
-
const { isSelected, select } = useListOption(tab, props.value);
|
|
30
|
-
|
|
31
|
-
const tabId = props.id ?? useSequentialId("tab");
|
|
32
|
-
const tabPanelId = props.ariaControls ?? useSequentialId("tab-panel");
|
|
33
|
-
</script>
|
|
34
|
-
|
|
35
|
-
<style scoped></style>
|
|
@@ -1,50 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div>
|
|
3
|
-
<slot />
|
|
4
|
-
</div>
|
|
5
|
-
</template>
|
|
6
|
-
|
|
7
|
-
<script setup lang="ts">
|
|
8
|
-
import { provide, computed } from "vue";
|
|
9
|
-
import { useList } from "../../composables/list";
|
|
10
|
-
import { injectTabs } from "../injectionKeys";
|
|
11
|
-
|
|
12
|
-
const props = withDefaults(
|
|
13
|
-
defineProps<{
|
|
14
|
-
orientation?: "horizontal" | "vertical";
|
|
15
|
-
}>(),
|
|
16
|
-
{
|
|
17
|
-
orientation: "horizontal",
|
|
18
|
-
}
|
|
19
|
-
);
|
|
20
|
-
|
|
21
|
-
const model = defineModel();
|
|
22
|
-
|
|
23
|
-
const {
|
|
24
|
-
items,
|
|
25
|
-
selectActiveItem,
|
|
26
|
-
activateFirstItem,
|
|
27
|
-
activateLastItem,
|
|
28
|
-
activateNextItem,
|
|
29
|
-
activatePrevItem,
|
|
30
|
-
} = useList(model);
|
|
31
|
-
|
|
32
|
-
provide(injectTabs, {
|
|
33
|
-
getIds: (value: any) =>
|
|
34
|
-
computed(() => {
|
|
35
|
-
const item = items.value.find((item) => item.value === value);
|
|
36
|
-
return {
|
|
37
|
-
tabId: item?.element.value?.getAttribute("id") || undefined,
|
|
38
|
-
panelId: item?.element.value?.getAttribute("aria-controls") || undefined,
|
|
39
|
-
};
|
|
40
|
-
}),
|
|
41
|
-
selectActiveItem,
|
|
42
|
-
activateFirstItem,
|
|
43
|
-
activateLastItem,
|
|
44
|
-
activateNextItem,
|
|
45
|
-
activatePrevItem,
|
|
46
|
-
orientation: props.orientation,
|
|
47
|
-
});
|
|
48
|
-
</script>
|
|
49
|
-
|
|
50
|
-
<style scoped></style>
|
|
@@ -1,52 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div @keydown="onKeyDown" :aria-orientation="tabs!.orientation" role="tablist">
|
|
3
|
-
<slot />
|
|
4
|
-
</div>
|
|
5
|
-
</template>
|
|
6
|
-
|
|
7
|
-
<script setup lang="ts">
|
|
8
|
-
import { inject } from "vue";
|
|
9
|
-
import { injectTabs } from "../injectionKeys";
|
|
10
|
-
|
|
11
|
-
const tabs = inject(injectTabs);
|
|
12
|
-
if (!tabs) {
|
|
13
|
-
throw new Error("Tabs injectable context is not provided");
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
function onKeyDown(evt: KeyboardEvent) {
|
|
17
|
-
switch (evt.code) {
|
|
18
|
-
case "ArrowUp":
|
|
19
|
-
if (tabs!.orientation === "vertical") {
|
|
20
|
-
tabs!.activatePrevItem();
|
|
21
|
-
}
|
|
22
|
-
break;
|
|
23
|
-
case "ArrowDown":
|
|
24
|
-
if (tabs!.orientation === "vertical") {
|
|
25
|
-
tabs!.activateNextItem();
|
|
26
|
-
}
|
|
27
|
-
break;
|
|
28
|
-
case "ArrowLeft":
|
|
29
|
-
if (tabs!.orientation === "horizontal") {
|
|
30
|
-
tabs!.activatePrevItem();
|
|
31
|
-
}
|
|
32
|
-
break;
|
|
33
|
-
case "ArrowRight":
|
|
34
|
-
if (tabs!.orientation === "horizontal") {
|
|
35
|
-
tabs!.activateNextItem();
|
|
36
|
-
}
|
|
37
|
-
break;
|
|
38
|
-
case "Home":
|
|
39
|
-
tabs!.activateFirstItem();
|
|
40
|
-
break;
|
|
41
|
-
case "End":
|
|
42
|
-
tabs!.activateLastItem();
|
|
43
|
-
break;
|
|
44
|
-
default:
|
|
45
|
-
return;
|
|
46
|
-
}
|
|
47
|
-
tabs!.selectActiveItem();
|
|
48
|
-
evt.preventDefault();
|
|
49
|
-
}
|
|
50
|
-
</script>
|
|
51
|
-
|
|
52
|
-
<style scoped></style>
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
<template>
|
|
2
|
-
<div
|
|
3
|
-
v-if="isSelected"
|
|
4
|
-
:id="ids.panelId"
|
|
5
|
-
:aria-labelledby="ids.tabId"
|
|
6
|
-
tabindex="0"
|
|
7
|
-
role="tabpanel"
|
|
8
|
-
>
|
|
9
|
-
<slot />
|
|
10
|
-
</div>
|
|
11
|
-
</template>
|
|
12
|
-
|
|
13
|
-
<script setup lang="ts">
|
|
14
|
-
import { inject, computed } from "vue";
|
|
15
|
-
import { injectList } from "../../composables/list";
|
|
16
|
-
import { injectTabs } from "../injectionKeys";
|
|
17
|
-
|
|
18
|
-
const props = defineProps<{
|
|
19
|
-
value: string | number;
|
|
20
|
-
}>();
|
|
21
|
-
|
|
22
|
-
const list = inject(injectList);
|
|
23
|
-
if (!list) {
|
|
24
|
-
throw new Error("List injectable context is not provided");
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const tabs = inject(injectTabs);
|
|
28
|
-
if (!tabs) {
|
|
29
|
-
throw new Error("Tabs injectable context is not provided");
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const isSelected = computed(() => props.value === list.value.value);
|
|
33
|
-
const ids = tabs.getIds(props.value);
|
|
34
|
-
</script>
|
|
35
|
-
|
|
36
|
-
<style scoped></style>
|