@econnect/webcomponents-library
Documentation
Styleguide
Documentation
Styleguide
  • Getting Started

    • Installation
    • Patch Notes
    • Styleguide
  • Styling

    • e-connect colors
  • UI Components

    • Form

      • Search Field
      • Form Field
      • Forms
    • Filter

      • Filter
      • Search Filter
    • Grid

      • Grid
      • Grid Row
    • Inputs

      • File Input
      • Input Checkbox
      • Input Dropdown
      • Input Date
      • Input Date Time
      • Input Date Time Local
      • Input File
      • Input Label
      • Input Multi Select
      • Input Number
      • Input Radio
      • Input Range
      • Input Select
      • Input Switch
      • Input Slider
      • Input Text
      • Input TextArea
      • Input Time
      • Input Time Range
    • Controls

      • Booleans
      • Button
      • Checkboxes
      • Date Displays
      • Dropdown Lists
      • Text Displays
    • Headers

      • e-header
    • Cards

      • e-card
    • Images

      • Icon
      • Images
      • Flag Image
      • Hamburger
    • Iframe
    • Pager
    • Settings
    • Document Validation
    • Navigation

      • Navigation
      • Navigation Menu
      • Navigation Footer
      • Navigation Button
      • Navigation Button Item
      • Navigation Search Item

Navigation Button v1.0

The <e-navigation-button> component is a component that can be used for .

Usage

An e-navigation-button has attributes that must be provided,

<e-navigation-button
  :menu-item=""
  :is-opened=""
  :is-mobile=""
  @toggle=""
  @toggle:nav-menu=""
/>

Attributes

menuItem | Type: Array | required
isOpened | Type: Boolean | Default: false
isMobile | Type: Boolean | Default: false
@toggle | Type: Function | required
@toggle:nav-menu | Type: Function | required

Examples

Below a few interactive examples of e-navigation-button can be found.

Default
const menuItem = {
  displayText: 'Standard Item',
  icon: ['heart'],
  url: 'https://econnect.eu/',
  key: '1'
}
<e-navigation-button
  :menu-item='menuItem'
/>
Highlighted Button
const menuItem = {
  displayText: 'Highlighted Item',
  icon: ['star'],
  type: 'highlight',
  url: 'https://econnect.eu/',
  key: '2'
}
<e-navigation-button
  :menu-item='menuItem'
/>
Disabled Button
const menuItem = {
  displayText: 'Disabled Item',
  disabled: true,
  icon: ['close'],
  url: 'https://econnect.eu/',
  key: '3'
}
<e-navigation-button
  :menu-item='menuItem'
/>

Source Code

e-navigation-button.vue
<script setup lang="ts">
import { computed, ref, watch } from 'vue';
import { RouteLocation, useRouter } from 'vue-router';
import { isEmpty } from 'lodash-es';

import { EMenuItem } from 'types/menu';

import ENavigationButtonDisplay from '../e-navigation-button-display/e-navigation-button-display.vue';
import ENavigationButtonItem from '../e-navigation-button-item/e-navigation-button-item.vue';

export type Props = {
  menuItem: EMenuItem;
  route: RouteLocation;
  isOpened?: boolean;
  isMobile?: boolean;
};
const props = withDefaults(defineProps<Props>(), {
  isOpened: false,
  isMobile: false
});

const emit = defineEmits<{
  (e: 'toggle'): void;
  (e: 'toggle:nav-menu'): void;
}>();

const router = useRouter();

const navigationItem = computed(() => {
  return props.menuItem;
});

const subMenuItems = computed(() => {
  return navigationItem.value?.menuItems ?? [];
});

const hasSubItems = computed(() => {
  return !isEmpty(subMenuItems.value);
});

const localOpen = ref(props.isOpened);

const isHighlight = computed(() => {
  return navigationItem.value?.type === 'highlight';
});

const isActive = computed(() => {
  let result: boolean;

  const encodedRoute = encodeURI(navigationItem.value?.url);
  const encodedCurrentRoute = encodeURI(props.route?.fullPath);

  switch (navigationItem.value?.url) {
    case '/':
      // Home requires exact match
      result = encodedRoute === encodedCurrentRoute;
      break;
    default:
      result = encodedCurrentRoute.includes(encodedRoute);
  }
  return result || navigationItem.value?.active;
});

const isDisabled = computed(() => {
  return navigationItem.value?.disabled === true;
});

const isOpen = computed(() => {
  if (hasSubItems.value) {
    return isActive.value || showSubItems.value || localOpen.value;
  } else {
    return false;
  }
});

const showSubItems = computed(() => {
  if (hasSubItems.value) {
    return props.isMobile ? isActive.value || localOpen.value : isActive.value;
  } else {
    return false;
  }
});

const classes = computed(() => {
  return {
    active: isActive.value,
    disabled: isDisabled.value,
    open: isOpen.value || showSubItems.value,
    highlight: isHighlight.value
  };
});

function clickedIcon() {
  clickedToggle();
}

function clickedToggle() {
  if (subMenuItems?.value.length > 0) {
    localOpen.value = !localOpen.value;
    emit('toggle');
  }
}

function clicked() {
  emit('toggle:nav-menu');
  router.push(navigationItem.value?.url);
}

watch(
  () => navigationItem.value?.active,
  newValue => {
    localOpen.value = newValue === true;
  },
  {
    deep: true,
    immediate: true
  }
);
</script>

<template>
  <div
    class="e-navigation-button"
    :class="classes"
  >
    <e-navigation-button-display
      :class="{
        active: classes['active']
      }"
      :menu-item="navigationItem"
      :is-highlight="isHighlight"
      :is-open="isOpen"
      :is-mobile="isMobile"
      :route="route"
      @click:text="clicked"
      @click:icon="clickedIcon"
      @click:toggle="clickedToggle"
    />

    <div
      v-if="subMenuItems.length"
      class="e-navigation-button-items"
    >
      <e-navigation-button-item
        v-for="subMenuItem in subMenuItems"
        :key="subMenuItem?.key"
        :menu-item="subMenuItem"
        :route="route"
        :router="router"
        :parent-key="navigationItem?.displayText"
        @toggle:nav-menu="emit('toggle:nav-menu')"
      />
    </div>
  </div>
</template>

<style scoped lang="scss">
$icon-size: 20px;

@mixin color-nav-button(
  $background-color: var(--e-white),
  $content-background-color: inherit,
  $border-color: transparent
) {
  & {
    border-color: $border-color;
    background-color: $background-color;
  }

  .e-navigation-button-display {
    background-color: $content-background-color;
  }
}

.e-navigation-button {
  border: transparent 2px solid;
  width: 276px;
  border-radius: 15px;
  margin-right: 25px;
  user-select: none;
  display: flex;
  flex-direction: column;
  min-height: calc($icon-size + 24px);

  &:not(&.open) {
    overflow: hidden;
  }

  .e-navigation-button-items,
  .e-navigation-button-display {
    justify-content: space-between;
  }

  .e-navigation-button-display {
    gap: 10px;
    padding: 10px 13px;
  }

  .e-navigation-button-items {
    display: none;
    flex-direction: column;
    padding: 5px 13px;
  }

  @include color-nav-button();

  &.active {
    @include color-nav-button(
      var(--e-background),
      var(--e-navigation-button-background-active),
      var(--e-background)
    );
  }

  &.open {
    min-height: fit-content;

    .e-navigation-button-items {
      display: flex;
    }

    @include color-nav-button(var(--e-background), inherit, transparent);
  }

  &.highlight {
    @include color-nav-button(
      var(--e-accent),
      var(--e-navigation-button-background-highlight-active) var(--e-accent)
    );

    &.active {
      @include color-nav-button(
        var(--e-navigation-button-background-highlight-active),
        inherit,
        var(--e-accent)
      );
    }

    &.open {
      @include color-nav-button((var(--e-accent), 0%), transparent, var(--e-accent));
    }
  }

  &:focus-within,
  &:hover {
    transition: none;

    @include color-nav-button(transparent, var(--e-navigation-button-hover-color), transparent);

    &.active {
      @include color-nav-button(
        var(--e-navigation-button-background-highlight-active),
        var(--e-navigation-button-background-highlight-active),
        var(--e-accent)
      );
    }

    &.open {
      @include color-nav-button(var(--e-background), inherit, transparent);
    }

    &.highlight {
      @include color-nav-button(
        var(--e-navigation-button-background-highlight-active),
        var(--e-background),
        var(--e-accent)
      );
    }
  }

  &.disabled {
    cursor: not-allowed;

    @include color-nav-button(var(--e-background), inherit, transparent);

    &.highlight {
      @include color-nav-button(transparent, transparent, var(--e-disabled));
    }
  }
}
</style>
Last Updated:: 10/10/24, 2:56 PM
Contributors: Antony Elfferich, Roeland Krijgsman, AzureAD\MarcelLommers, Marcel Lommers
Prev
Navigation Footer
Next
Navigation Button Item