primitives

Navigation Menu

Navigation Menu — базовый примитив RevueUI (Reka UI + shadcn-совместимый API).

Загрузка превью…

src/ui/navigation-menu/NavigationMenu.vue

<script setup lang="ts">
/**
 * Порт базового радикс-слоя (registry/bases/radix/ui/navigation-menu.tsx, MIT).
 * Radix NavigationMenuPrimitive -> reka-ui NavigationMenu*, один в один.
 */
import type { HTMLAttributes } from "vue"
import { NavigationMenuRoot } from "reka-ui"
import { cn } from "@/lib/utils"
import NavigationMenuViewport from "./NavigationMenuViewport.vue"

const props = withDefaults(
  defineProps<{
    class?: HTMLAttributes["class"]
    viewport?: boolean
  }>(),
  {
    viewport: true,
  }
)
</script>

<template>
  <NavigationMenuRoot
    data-slot="navigation-menu"
    :data-viewport="props.viewport"
    :class="
      cn(
        'cn-navigation-menu group/navigation-menu relative flex max-w-max flex-1 items-center justify-center',
        props.class
      )
    "
  >
    <slot />
    <NavigationMenuViewport v-if="props.viewport" />
  </NavigationMenuRoot>
</template>

src/ui/navigation-menu/NavigationMenuContent.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { NavigationMenuContent } from "reka-ui"
import { cn } from "@/lib/utils"

const props = defineProps<{
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <NavigationMenuContent
    data-slot="navigation-menu-content"
    :class="
      cn(
        'cn-navigation-menu-content top-0 left-0 w-full group-data-[viewport=false]/navigation-menu:top-full group-data-[viewport=false]/navigation-menu:mt-1.5 group-data-[viewport=false]/navigation-menu:overflow-hidden **:data-[slot=navigation-menu-link]:focus:ring-0 **:data-[slot=navigation-menu-link]:focus:outline-none md:absolute md:w-auto',
        props.class
      )
    "
  >
    <slot />
  </NavigationMenuContent>
</template>

src/ui/navigation-menu/NavigationMenuIndicator.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { NavigationMenuIndicator } from "reka-ui"
import { cn } from "@/lib/utils"

const props = defineProps<{
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <NavigationMenuIndicator
    data-slot="navigation-menu-indicator"
    :class="
      cn(
        'cn-navigation-menu-indicator top-full z-1 flex h-1.5 items-end justify-center overflow-hidden',
        props.class
      )
    "
  >
    <div class="cn-navigation-menu-indicator-arrow relative top-[60%] h-2 w-2 rotate-45" />
  </NavigationMenuIndicator>
</template>

src/ui/navigation-menu/NavigationMenuItem.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { NavigationMenuItem } from "reka-ui"
import { cn } from "@/lib/utils"

const props = defineProps<{
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <NavigationMenuItem
    data-slot="navigation-menu-item"
    :class="cn('cn-navigation-menu-item relative', props.class)"
  >
    <slot />
  </NavigationMenuItem>
</template>

src/ui/navigation-menu/NavigationMenuLink.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { NavigationMenuLink } from "reka-ui"
import { cn } from "@/lib/utils"

const props = defineProps<{
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <NavigationMenuLink
    data-slot="navigation-menu-link"
    :class="cn('cn-navigation-menu-link', props.class)"
  >
    <slot />
  </NavigationMenuLink>
</template>

src/ui/navigation-menu/NavigationMenuList.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { NavigationMenuList } from "reka-ui"
import { cn } from "@/lib/utils"

const props = defineProps<{
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <NavigationMenuList
    data-slot="navigation-menu-list"
    :class="
      cn(
        'cn-navigation-menu-list group flex flex-1 list-none items-center justify-center',
        props.class
      )
    "
  >
    <slot />
  </NavigationMenuList>
</template>

src/ui/navigation-menu/NavigationMenuTrigger.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { NavigationMenuTrigger } from "reka-ui"
import { cn } from "@/lib/utils"
import { navigationMenuTriggerStyle } from "./variants"

const props = defineProps<{
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <NavigationMenuTrigger
    data-slot="navigation-menu-trigger"
    :class="cn(navigationMenuTriggerStyle(), 'group', props.class)"
  >
    <slot /> <svg
      class="cn-navigation-menu-trigger-icon"
      aria-hidden="true"
      xmlns="http://www.w3.org/2000/svg"
      width="24"
      height="24"
      viewBox="0 0 24 24"
      fill="none"
      stroke="currentColor"
      stroke-width="2"
      stroke-linecap="round"
      stroke-linejoin="round"
    >
      <path d="m6 9 6 6 6-6" />
    </svg>
  </NavigationMenuTrigger>
</template>

src/ui/navigation-menu/NavigationMenuViewport.vue

<script setup lang="ts">
import type { HTMLAttributes } from "vue"
import { NavigationMenuViewport } from "reka-ui"
import { cn } from "@/lib/utils"

const props = defineProps<{
  class?: HTMLAttributes["class"]
}>()
</script>

<template>
  <div :class="cn('cn-navigation-menu-viewport-wrapper absolute top-full left-0 isolate z-50 flex justify-center')">
    <NavigationMenuViewport
      data-slot="navigation-menu-viewport"
      :class="
        cn(
          'cn-navigation-menu-viewport origin-top-center relative mt-1.5 h-(--radix-navigation-menu-viewport-height) w-full overflow-hidden md:w-(--radix-navigation-menu-viewport-width)',
          props.class
        )
      "
    />
  </div>
</template>

src/ui/navigation-menu/index.ts

export { default as NavigationMenu } from "./NavigationMenu.vue"
export { default as NavigationMenuList } from "./NavigationMenuList.vue"
export { default as NavigationMenuItem } from "./NavigationMenuItem.vue"
export { default as NavigationMenuContent } from "./NavigationMenuContent.vue"
export { default as NavigationMenuTrigger } from "./NavigationMenuTrigger.vue"
export { default as NavigationMenuLink } from "./NavigationMenuLink.vue"
export { default as NavigationMenuIndicator } from "./NavigationMenuIndicator.vue"
export { default as NavigationMenuViewport } from "./NavigationMenuViewport.vue"
export { navigationMenuTriggerStyle } from "./variants"

src/ui/navigation-menu/variants.ts

import { cva } from "class-variance-authority"

export const navigationMenuTriggerStyle = cva(
  "cn-navigation-menu-trigger group/navigation-menu-trigger inline-flex h-9 w-max items-center justify-center outline-none disabled:pointer-events-none"
)

Установка

npx shadcn-vue@latest add https://revueui.rootapi.dev/r/navigation-menu.json

Зависимости реестра

npm-зависимости

  • class-variance-authority
  • reka-ui

Источник: порт из ReUI (Keenthemes, MIT)