feat(primitives): add menu, dropdown-menu, context-menu, and menubar primitives

Implements WAI-ARIA APG-compliant headless menu primitive families:

- menu: base primitive with MenuRoot, MenuContent, MenuItem,
  MenuCheckboxItem, MenuRadioGroup/Item, MenuSub, and helpers
- dropdown-menu: DropdownMenuRoot with trigger anchoring
- context-menu: ContextMenuRoot with right-click virtual anchor
- menubar: MenubarRoot with keyboard navigation between menus

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
2026-05-17 18:48:43 +07:00
parent 333a18cbaf
commit 1d3efa5028
81 changed files with 2554 additions and 0 deletions
@@ -0,0 +1,38 @@
<script lang="ts">
import type { PrimitiveProps } from '../primitive';
export interface MenuRadioGroupProps extends PrimitiveProps {
modelValue?: string;
defaultValue?: string;
}
export interface MenuRadioGroupEmits {
'update:modelValue': [value: string];
}
</script>
<script setup lang="ts">
import { computed, ref } from 'vue';
import { Primitive } from '../primitive';
import { provideMenuRadioGroupContext } from './context';
const { modelValue, defaultValue, as = 'div', asChild } = defineProps<MenuRadioGroupProps>();
const emit = defineEmits<MenuRadioGroupEmits>();
const local = ref(defaultValue);
const value = computed(() => modelValue !== undefined ? modelValue : local.value);
provideMenuRadioGroupContext({
modelValue: value,
onValueChange: (v) => {
local.value = v;
emit('update:modelValue', v);
},
});
</script>
<template>
<Primitive :as="as" :as-child="asChild" role="group">
<slot />
</Primitive>
</template>