Skip to content

Commit

Permalink
feat(NavigationMenu)!: replace hardcoded CSS values with custom prope…
Browse files Browse the repository at this point in the history
…rties (#1481)
  • Loading branch information
gu-stav authored Dec 11, 2024
1 parent 6f9e1d3 commit 693483c
Show file tree
Hide file tree
Showing 5 changed files with 44 additions and 27 deletions.
2 changes: 1 addition & 1 deletion docs/components/demo/NavigationMenu/tailwind/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ const currentTrigger = ref('')
</NavigationMenuItem>

<NavigationMenuIndicator
class="data-[state=hidden]:opacity-0 duration-200 data-[state=visible]:animate-fadeIn data-[state=hidden]:animate-fadeOut top-full mt-[1px] z-[100] flex h-[10px] items-end justify-center overflow-hidden transition-[all,transform_250ms_ease]"
class="absolute data-[state=hidden]:opacity-0 duration-200 data-[state=visible]:animate-fadeIn data-[state=hidden]:animate-fadeOut top-full w-[--reka-navigation-menu-indicator-size] translate-x-[--reka-navigation-menu-indicator-position] mt-[1px] z-[100] flex h-[10px] items-end justify-center overflow-hidden transition-[all,transform_250ms_ease]"
>
<div class="relative top-[70%] h-[12px] w-[12px] rotate-[45deg] bg-white border" />
</NavigationMenuIndicator>
Expand Down
20 changes: 19 additions & 1 deletion docs/content/docs/components/navigation-menu.md
Original file line number Diff line number Diff line change
Expand Up @@ -213,6 +213,19 @@ An optional indicator element that renders below the list, is used to highlight
]"
/>

<CssVariablesTable
:data="[
{
cssVariable: '--reka-navigation-menu-indicator-size',
description: 'The size of the indicator.',
},
{
cssVariable: '--reka-navigation-menu-indicator-position',
description: 'The position of the indicator',
},
]"
/>

### Viewport

An optional viewport element that is used to render active content outside of the list.
Expand Down Expand Up @@ -360,10 +373,15 @@ import {
/* styles.css */
.NavigationMenuIndicator {
background-color: grey;
position: absolute;
transition: width, transform, 250ms ease;
}

.NavigationMenuIndicator[data-orientation="horizontal"] {
left: 0;
height: 3px;
transition: width, transform, 250ms ease;
transform: translateX(var(--reka-navigation-menu-indicator-position));
width: var(--reka-navigation-menu-indicator-size);
}
```

Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/NavigationMenu/NavigationMenuContent.vue
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ const isLastActiveValue = computed(() => {

<template>
<Teleport
:to=" isClient && menuContext.viewport.value ? menuContext.viewport.value : 'body'"
:to="isClient && menuContext.viewport.value ? menuContext.viewport.value : 'body'"
:disabled="isClient && menuContext.viewport.value ? !menuContext.viewport.value : true"
>
<Presence
Expand Down
42 changes: 18 additions & 24 deletions packages/core/src/NavigationMenu/NavigationMenuIndicator.vue
Original file line number Diff line number Diff line change
Expand Up @@ -27,27 +27,29 @@ const props = defineProps<NavigationMenuIndicatorProps>()
const { forwardRef } = useForwardExpose()
const menuContext = injectNavigationMenuContext()
const position = ref<{ size: number, offset: number }>()
const indicatorStyle = ref<{ size: number, position: number }>()
const isHorizontal = computed(() => menuContext.orientation === 'horizontal')
const isVisible = computed(() => !!menuContext.modelValue.value)
const { activeTrigger } = menuContext
function handlePositionChange() {
if (activeTrigger.value) {
position.value = {
size: isHorizontal.value
? activeTrigger.value.offsetWidth
: activeTrigger.value.offsetHeight,
offset: isHorizontal.value
? activeTrigger.value.offsetLeft
: activeTrigger.value.offsetTop,
}
if (!activeTrigger.value) {
return
}
indicatorStyle.value = {
size: isHorizontal.value
? activeTrigger.value.offsetWidth
: activeTrigger.value.offsetHeight,
position: isHorizontal.value
? activeTrigger.value.offsetLeft
: activeTrigger.value.offsetTop,
}
}
watchEffect(() => {
if (!menuContext.modelValue.value) {
position.value = undefined
indicatorStyle.value = undefined
return
}
handlePositionChange()
Expand All @@ -62,7 +64,7 @@ useResizeObserver(menuContext.indicatorTrack, handlePositionChange)
v-if="menuContext.indicatorTrack.value"
:to="menuContext.indicatorTrack.value"
>
<Presence :present="(forceMount || isVisible) && !!position?.size">
<Presence :present="(forceMount || isVisible) && !!indicatorStyle?.size">
<Primitive
:ref="forwardRef"
aria-hidden="true"
Expand All @@ -71,18 +73,10 @@ useResizeObserver(menuContext.indicatorTrack, handlePositionChange)
:as-child="props.asChild"
:as="as"
:style="{
position: 'absolute',
...(isHorizontal
? {
left: 0,
width: `${position?.size}px`,
transform: `translateX(${position?.offset}px)`,
}
: {
top: 0,
height: `${position?.size}px`,
transform: `translateY(${position?.offset}px)`,
}),
...(indicatorStyle ? {
'--reka-navigation-menu-indicator-size': `${indicatorStyle.size}px`,
'--reka-navigation-menu-indicator-position': `${indicatorStyle.position}px`,
} : {}),
}"
v-bind="$attrs"
>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { Icon } from '@iconify/vue'
import { reactive, ref } from 'vue'
import {
NavigationMenuContent,
NavigationMenuIndicator,
NavigationMenuItem,
NavigationMenuLink,
NavigationMenuList,
Expand Down Expand Up @@ -107,6 +108,10 @@ const state = reactive({
Link
</NavigationMenuLink>
</NavigationMenuItem>

<NavigationMenuIndicator
class="absolute bg-green10 left-0 h-[2px] bottom-0 w-[--reka-navigation-menu-indicator-size] translate-x-[--reka-navigation-menu-indicator-position] rounded-full transition-[width,transform] duration-300"
/>
</NavigationMenuList>
</NavigationMenuRoot>
</StoryFrame>
Expand Down

0 comments on commit 693483c

Please sign in to comment.