Statusindicator

<div class="border border--rounded margin--x--m padding--m">
    <div class="status-indicator" data-status-list="Stap overgeslagen|Stap voltooid|Huidige stap|Toekomstige stap">
        <div class="status-indicator__lines">
            <span class="status-indicator__background"></span>
            <span class="status-indicator__progress"></span>
        </div>
        <ol class="status-indicator__content">
            <li class="status-indicator__step status-indicator__skip-step">
                <div class="status-indicator__title-container">
                    <span class="status-indicator__icon"></span>
                    <button class="status-indicator__label">Basisinformatie<span>(Stap overgeslagen)</span></button>
                </div>
            </li>

            <li class="status-indicator__step status-indicator__done-step">
                <div class="status-indicator__title-container">
                    <span class="status-indicator__icon"></span>
                    <button class="status-indicator__label">Aanvullende informatie</button>
                </div>
                <ol class="status-indicator__description-list">
                    <li class="status-indicator__description-container">
                        <span class="status-indicator__dot"></span>
                        <span class="status-indicator__description">
                            13 maart: Uw aanvraag is in goed orde ontvangen. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consectetur explicabo nisi officiis tempore totam? Blanditiis dicta.<br>
                        </span>
                    </li>
                </ol>
            </li>

            <li class="status-indicator__step status-indicator__current-step">
                <div class="status-indicator__title-container">
                    <span class="status-indicator__icon"></span>
                    <button class="status-indicator__label">Intake</button>
                    <button type="button" class="button button--icon tooltip-trigger" data-placement="top" data-title="De gemeente heeft uw aanvraag van een omgevingsvergunning in behandeling genomen. De gemeente beoordeelt inhoudelijk uw aanvraag.">
                        <span aria-hidden="true">
                            <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 16 16" class="icon">
                                <path d="M9.07,4.43A1.3,1.3,0,0,0,7.61,3.07a2.78,2.78,0,0,0-2,1L3.89,2.46A5.5,5.5,0,0,1,8,.5c2.33,0,4.1,1.15,4.1,3.71s-3.25,3.47-3,6H6.34C5.9,7.28,9.07,6.06,9.07,4.43ZM5.81,13.5a1.92,1.92,0,1,1,3.83,0,1.92,1.92,0,1,1-3.83,0Z"></path>
                            </svg>
                        </span>
                        <span class="screen-reader-only">De gemeente heeft uw aanvraag van een omgevingsvergunning in behandeling genomen. De gemeente beoordeelt inhoudelijk uw aanvraag.</span>
                    </button>
                </div>
                <ol class="status-indicator__description-list">
                    <li class="status-indicator__description-container">
                        <span class="status-indicator__dot"></span>
                        <span class="status-indicator__description">19 maart: Uw aanvraag is in goed orde ontvangen. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consectetur explicabo nisi officiis tempore totam? Blanditiis dicta.</span>
                    </li>
                    <li class="status-indicator__description-container">
                        <span class="status-indicator__dot"></span>
                        <span class="status-indicator__description">22 maart: Uw aanvraag is in goed orde ontvangen. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consectetur explicabo nisi officiis tempore totam? Blanditiis dicta.</span>
                    </li>
                </ol>
            </li>

            <li class="status-indicator__step">
                <div class="status-indicator__title-container">
                    <span class="status-indicator__icon"></span>
                    <button class="status-indicator__label">Samenvatting</button>
                </div>
                <ol class="status-indicator__description-list">
                    <li class="status-indicator__description-container" tabindex="-1">
                        <span class="status-indicator__dot"></span>
                        <span class="status-indicator__description">21 maart: Uw aanvraag is in goed orde ontvangen. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consectetur explicabo nisi officiis tempore totam? Blanditiis dicta.</span>
                    </li>
                </ol>
            </li>
        </ol>
    </div>
</div>
<div class="border border--rounded margin--x--m padding--m">
  <div class="status-indicator" data-status-list="Stap overgeslagen|Stap voltooid|Huidige stap|Toekomstige stap">
    <div class="status-indicator__lines">
      <span class="status-indicator__background"></span>
      <span class="status-indicator__progress"></span>
    </div>
    <ol class="status-indicator__content">
      <li class="status-indicator__step status-indicator__skip-step">
        <div class="status-indicator__title-container">
          <span class="status-indicator__icon"></span>
          <button class="status-indicator__label">Basisinformatie<span>(Stap overgeslagen)</span></button>
        </div>
      </li>

      <li class="status-indicator__step status-indicator__done-step">
        <div class="status-indicator__title-container">
          <span class="status-indicator__icon"></span>
          <button class="status-indicator__label">Aanvullende informatie</button>
        </div>
        <ol class="status-indicator__description-list">
          <li class="status-indicator__description-container">
            <span class="status-indicator__dot"></span>
            <span class="status-indicator__description">
              13 maart: Uw aanvraag is in goed orde ontvangen. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consectetur explicabo nisi officiis tempore totam? Blanditiis dicta.<br>
            </span>
          </li>
        </ol>
      </li>

      <li class="status-indicator__step status-indicator__current-step">
        <div class="status-indicator__title-container">
          <span class="status-indicator__icon"></span>
          <button class="status-indicator__label">Intake</button>
            <button type="button" class="button button--icon tooltip-trigger" data-placement="top" data-title="De gemeente heeft uw aanvraag van een omgevingsvergunning in behandeling genomen. De gemeente beoordeelt inhoudelijk uw aanvraag.">
              <span aria-hidden="true">
                <svg xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 16 16" class="icon">
                  <path d="M9.07,4.43A1.3,1.3,0,0,0,7.61,3.07a2.78,2.78,0,0,0-2,1L3.89,2.46A5.5,5.5,0,0,1,8,.5c2.33,0,4.1,1.15,4.1,3.71s-3.25,3.47-3,6H6.34C5.9,7.28,9.07,6.06,9.07,4.43ZM5.81,13.5a1.92,1.92,0,1,1,3.83,0,1.92,1.92,0,1,1-3.83,0Z"></path>
                </svg>
              </span>
                <span class="screen-reader-only">De gemeente heeft uw aanvraag van een omgevingsvergunning in behandeling genomen. De gemeente beoordeelt inhoudelijk uw aanvraag.</span>
            </button>
        </div>
        <ol class="status-indicator__description-list">
          <li class="status-indicator__description-container">
            <span class="status-indicator__dot"></span>
            <span class="status-indicator__description">19 maart: Uw aanvraag is in goed orde ontvangen. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consectetur explicabo nisi officiis tempore totam? Blanditiis dicta.</span>
          </li>
          <li class="status-indicator__description-container">
            <span class="status-indicator__dot"></span>
            <span class="status-indicator__description">22 maart: Uw aanvraag is in goed orde ontvangen. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consectetur explicabo nisi officiis tempore totam? Blanditiis dicta.</span>
          </li>
        </ol>
      </li>

      <li class="status-indicator__step">
        <div class="status-indicator__title-container">
          <span class="status-indicator__icon"></span>
          <button class="status-indicator__label">Samenvatting</button>
        </div>
        <ol class="status-indicator__description-list">
          <li class="status-indicator__description-container" tabindex="-1">
            <span class="status-indicator__dot"></span>
            <span class="status-indicator__description">21 maart: Uw aanvraag is in goed orde ontvangen. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Consectetur explicabo nisi officiis tempore totam? Blanditiis dicta.</span>
          </li>
        </ol>
      </li>
    </ol>
  </div>
</div>
/* No context defined for this component. */
  • Content:
    // Component variables
    $status-indicator-default-color: $grey-dark;
    $status-indicator-mute-color: $grey-light;
    $status-indicator-done-color: $blue;
    $status-indicator-passed-color: $green;
    $status-indicator-background-color: $white;
    $status-indicator-bold: $fw-medium;
    $status-indicator-line-width: 2px;
    $status-indicator-icon-container-width: 24px;
    $status-indicator-label-icon-space: $space-xs;
    $status-indicator-x-axis-spacing: $space-l;
    $status-indicator-icon-width: 16px;
    $status-indicator-margin: 1.5px;
    $status-indicator-small-text: $fs-down-1;
    $status-indicator-first-layer: $layer-status-indicator;
    $status-indicator-second-layer: $layer-status-indicator + 1;
    $status-indicator-third-layer: $layer-status-indicator + 2;
    
    .status-indicator {
    
      $parent: &;
    
      display: flex;
      flex-direction: column;
      position: relative;
    
      &__status {
        font-weight: $fw-medium;
      }
    
      &__lines {
        position: absolute;
        width: 100%;
        height: 100%;
    
        #{$parent}__background,
        #{$parent}__progress {
          content: '';
          position: absolute;
          top: math.div($status-indicator-icon-container-width, 2) + $status-indicator-margin;
          left: (math.div($status-indicator-icon-container-width, 2) - math.div($status-indicator-line-width, 2));
          width: $status-indicator-line-width;
        }
    
        #{$parent}__background {
          background-color: $status-indicator-mute-color;
          z-index: $status-indicator-second-layer;
          bottom: math.div($status-indicator-icon-container-width, 2) + $status-indicator-margin;
        }
    
        #{$parent}__progress {
          background-color: $status-indicator-passed-color;
          z-index: $status-indicator-second-layer;
        }
      }
    
      ol {
        padding: 0;
        margin: 0;
        list-style: none;
      }
    
      &__content {
        z-index: $status-indicator-second-layer;
      }
    
      &__title-container,
      &__description-container {
        padding-top: $status-indicator-x-axis-spacing;
      }
    
      &__title-container {
        display: flex;
        flex-direction: row;
        align-items: center;
        color: $status-indicator-mute-color;
    
        #{$parent}__step:first-child & {
          padding-top: 0;
        }
      }
    
      &__icon {
        display: flex;
        justify-content: center;
        align-items: center;
        width: $status-indicator-icon-container-width;
        height: $status-indicator-icon-container-width;
        background-color: $status-indicator-background-color;
        border: $status-indicator-line-width solid $status-indicator-mute-color;
        border-radius: 50%;
    
        .icon {
          width: $status-indicator-icon-width;
          height: $status-indicator-icon-width;
        }
    
        // Status depending styles.
        #{$parent}__done-step &,
        #{$parent}__current-step & {
          border-color: $status-indicator-passed-color;
          color: $status-indicator-passed-color;
        }
      }
    
      &__description {
        margin-left: $status-indicator-label-icon-space;
      }
    
      &__label {
        display: flex;
        align-items: center;
        border: none;
        margin: 0 0 0 $status-indicator-label-icon-space;
        padding: 0;
        width: auto;
        overflow: visible;
        background: transparent;
        font-family: $font-sans;
        font-size: $fs-base;
        line-height: $base-line-height;
        -webkit-font-smoothing: inherit;
        -moz-osx-font-smoothing: inherit;
        -webkit-appearance: none;
    
        &::-moz-focus-inner {
          border: 0;
          padding: 0;
        }
    
        &:focus {
          color: $black;
          background-color: $yellow;
          border-color: $black;
        }
    
        #{$parent}__skip-step & span {
          font-size: $fs-down-2;
          font-weight: $fw-normal;
          margin-left: $space-xxs;
        }
    
        #{$parent}__current-step &,
        #{$parent}__done-step & {
          color: $status-indicator-done-color;
          text-decoration: underline;
    
          &:hover {
            cursor: pointer;
          }
        }
    
        #{$parent}__open & {
          color: $status-indicator-default-color;
          font-weight: $status-indicator-bold;
          text-decoration: none;
    
          &:hover {
            cursor: default;
          }
        }
      }
    
      &__description {
        font-size: $status-indicator-small-text;
      }
    
      &__description-container {
        display: none;
        flex-direction: row;
        align-items: center;
    
        #{$parent}__open & {
          display: flex;
        }
      }
    
      &__dot {
        z-index: $status-indicator-third-layer;
        flex-shrink: 0;
        background-color: $status-indicator-passed-color;
        border: $status-indicator-line-width solid $status-indicator-background-color;
        width: ($status-indicator-icon-width - ($status-indicator-line-width * 2));
        height: ($status-indicator-icon-width - ($status-indicator-line-width * 2));
        border-radius: 50%;
        margin: (($status-indicator-icon-container-width - $status-indicator-icon-width) * .5) + $status-indicator-line-width;
      }
    
      button + .tooltip-trigger {
        margin-left: $space-xxs;
      }
    }
    
    @media (max-width: $mobile) {
      .status-indicator__label {
        font-size: $fs-down-1;
      }
    }
    
  • URL: /components/raw/status-indicator/_status-indicator.scss
  • Filesystem Path: src/components/01-componenten/status-indicator/_status-indicator.scss
  • Size: 4.9 KB
  • Content:
    import {
      getElementRectPlus,
      calculateDistance,
    } from '../../../js/utils/dom-geometry';
    
    var STEP_STATUS = {
      OPEN: 'OPEN',
      CURRENT: 'CURRENT',
      DONE: 'DONE',
      SKIP: 'SKIP',
    };
    
    var circleIcon = '' +
      '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 16 16" xml:space="preserve" class="icon" aria-hidden="true" role="presentation" focusable="false">' +
      '<g>' +
      '<circle fill="currentColor" cx="8" cy="8" r="8"/>' +
      '</g>' +
      '</svg>';
    
    var checkIcon = '<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 16 16" class="icon" aria-hidden="true" role="presentation" focusable="false">' +
      '<g>' +
      '<polygon fill="currentColor" points="16,3.8 14.1,1.8 12,3.9 5.6,10.3 1.9,6.6 0,8.6 3.7,12.2 3.7,12.2 5.6,14.2 7.5,12.2 7.5,12.2"/>' +
      '</g>' +
      '</svg>';
    
    /**
     * Initialize status indicator.
     *
     * @param {Element} statusIndicatorElement Status indicator DOM element.
     */
    export default function StatusIndicator (statusIndicatorElement) {
      var component = {
        statusIndicatorElement: statusIndicatorElement,
        backgroundLineElement: statusIndicatorElement.getElementsByClassName(
          'status-indicator__background')[0],
        progressLineElement: statusIndicatorElement.getElementsByClassName(
          'status-indicator__progress')[0],
        allStepsDone: true,
        steps: [],
        setProgress: setProgress,
        statusTextList: parseStepStatusStringToObject(
          statusIndicatorElement.dataset.statusList),
      };
    
      // Set toggle trigger if exist.
      // Why do we need this? If initially the content is hidden
      // getBoundingClientRect will return zero, which will also result in step
      // center not calculated correctly.
      var toggleTriggerElement = null;
      if (component.statusIndicatorElement.dataset.toggleTrigger) {
        toggleTriggerElement = document.getElementById(
          component.statusIndicatorElement.dataset.toggleTrigger);
      }
      if (toggleTriggerElement) {
        toggleTriggerElement.addEventListener('click', function () {
          component.setProgress();
        });
      }
    
      var stepItems = component.statusIndicatorElement.getElementsByClassName(
        'status-indicator__step');
      for (var stepItemIndex = 0; stepItemIndex <
      stepItems.length; stepItemIndex++) {
        var stepElement = stepItems[stepItemIndex];
        var step = {
          element: stepElement,
          iconElement: stepElement.getElementsByClassName(
            'status-indicator__icon')[0],
          labelElement: stepElement.getElementsByClassName(
            'status-indicator__label')[0],
          status: null,
          isLastStep: false,
        };
    
        // Toggle step description content.
        step.element.addEventListener('click', handleToggle(component));
    
        // Initially set state and icon depending on class name.
        if (stepElement.classList.contains('status-indicator__skip-step')) {
          step.status = STEP_STATUS.SKIP;
          step.iconElement.innerHTML = generateIconElementContent(
            component.statusTextList[step.status], checkIcon);
          step.labelElement.disabled = true;
        } else if (stepElement.classList.contains('status-indicator__done-step')) {
          step.status = STEP_STATUS.DONE;
          step.iconElement.innerHTML = generateIconElementContent(
            component.statusTextList[step.status], checkIcon);
          step.labelElement.disabled = false;
        } else if (stepElement.classList.contains(
          'status-indicator__current-step')) {
          step.status = STEP_STATUS.CURRENT;
          step.element.classList.add('status-indicator__open');
          step.iconElement.innerHTML = generateIconElementContent(
            component.statusTextList[step.status], circleIcon);
          step.labelElement.disabled = true;
          component.allStepsDone = false;
        } else {
          step.status = STEP_STATUS.OPEN;
          step.iconElement.innerHTML = generateIconElementContent(
            component.statusTextList[step.status]);
          step.labelElement.disabled = true;
        }
    
        component.steps[stepItemIndex] = step;
      }
    
      // Handle last step
      var lastStep = component.steps[component.steps.length - 1];
      lastStep.isLastStep = true;
    
      // In case all steps are done, open the last step.
      if (component.allStepsDone) {
        lastStep.element.classList.add('status-indicator__open');
      }
    
      component.setProgress();
    
      // Recalculate progress line on window resize (responsive behaviour).
      window.addEventListener('resize', function () {
        component.setProgress();
      });
    }
    
    /**
     * Parse the list of step statuses to object.
     *
     * @param {string} statusesAsString
     * @return {{[p: string]: string}}
     */
    function parseStepStatusStringToObject (statusesAsString) {
      var splitString = statusesAsString.split('|');
      return {
        'SKIP': splitString[0],
        'DONE': splitString[1],
        'CURRENT': splitString[2],
        'OPEN': splitString[3],
      };
    }
    
    /**
     * Generate content for the step icon element. Depending on the status a screen
     * reader text is put in place.
     *
     * @param {string} statusText
     * @param {string} iconSnippet
     * @return {string}
     */
    function generateIconElementContent (statusText, iconSnippet) {
      iconSnippet = (typeof iconSnippet !== 'undefined') ? iconSnippet : '';
    
      return '' +
        iconSnippet +
        '<span class="screen-reader-only">' + statusText + '</span>';
    }
    
    /**
     * Handle toggling of title description.
     *
     * @param {Object} component Status indicator container.
     * @returns {EventListener} Click event.
     */
    function handleToggle (component) {
      return function (event) {
        // Don't need to toggle open step.
        if (this.classList.contains('status-indicator__open')) {
          return;
        }
    
        // Steps to come are not togglable.
        if (!this.classList.contains('status-indicator__current-step') &&
          !this.classList.contains('status-indicator__done-step')) {
          return;
        }
    
        // Only handle clicks on the title.
        if (event.target.classList.contains('status-indicator__label')) {
          var currentStepElement = component.statusIndicatorElement.getElementsByClassName(
            'status-indicator__open')[0];
    
          // Toggle disabled mode for button.
          currentStepElement.getElementsByClassName(
            'status-indicator__label')[0].disabled = false;
          event.target.disabled = true;
    
          // Toggle open state on step.
          currentStepElement.classList.remove('status-indicator__open');
          this.classList.toggle('status-indicator__open');
    
          // Recalculate progress line.
          component.setProgress();
    
          // Set focus on collapsed content.
          this.getElementsByClassName('status-indicator__description')[0].focus();
        }
      };
    }
    
    /**
     * Set progress depending on the steps that are already done.
     */
    function setProgress () {
      var progressHeight = 0;
      var backgroundHeight = 0;
      var previousStepRectPlus = null;
    
      for (var i = 0; i < this.steps.length; i++) {
        var step = this.steps[i];
        var currentStepRectPlus = getElementRectPlus(step.iconElement);
        var distance = 0;
    
        if (previousStepRectPlus) {
          distance = calculateDistance(previousStepRectPlus.center,
            currentStepRectPlus.center);
        }
    
        backgroundHeight += distance;
    
        if (
          step.status === STEP_STATUS.DONE
          || step.status === STEP_STATUS.SKIP
          || step.status === STEP_STATUS.CURRENT
        ) {
          progressHeight += distance;
        }
    
        if ((step.status === STEP_STATUS.CURRENT || step.isLastStep) &&
          step.element.classList.contains('status-indicator__open')) {
          var subStepDotElementList = step.element.querySelectorAll(
            '.status-indicator__dot');
          var subStepDotElementListRectPlus = getElementRectPlus(
            subStepDotElementList[subStepDotElementList.length - 1]);
          progressHeight += calculateDistance(currentStepRectPlus.center,
            subStepDotElementListRectPlus.center);
        }
    
        previousStepRectPlus = currentStepRectPlus;
      }
    
      this.progressLineElement.style.height = progressHeight + 'px';
      this.backgroundLineElement.style.height = backgroundHeight + 'px';
    }
    
  • URL: /components/raw/status-indicator/status-indicator.js
  • Filesystem Path: src/components/01-componenten/status-indicator/status-indicator.js
  • Size: 8 KB
  • Handle: @status-indicator
  • Preview:
  • Filesystem Path: src/components/01-componenten/status-indicator/status-indicator.hbs

There are no notes for this item.