Skip to content

Instantly share code, notes, and snippets.

@StephanHoyer
Created January 4, 2016 08:30
Show Gist options
  • Select an option

  • Save StephanHoyer/f34c685cfc1b31534039 to your computer and use it in GitHub Desktop.

Select an option

Save StephanHoyer/f34c685cfc1b31534039 to your computer and use it in GitHub Desktop.

Revisions

  1. StephanHoyer created this gist Jan 4, 2016.
    105 changes: 105 additions & 0 deletions tooltip.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,105 @@
    'use strict';

    var m = require('mithril');
    var isFunction = require('lodash/lang/isFunction');
    var assign = require('lodash/object/assign');
    var minMax = require('client/utils').minMax;

    var content, targetDimensions, options, showTimer, isVisible;

    function px(value) {
    return value + 'px';
    }

    function show(_content, _options) {
    var wrapInRedraw = require('client/utils/viewhelper').wrapInRedraw;

    return function(event) {
    targetDimensions = event.currentTarget.getBoundingClientRect();
    options = assign({
    position: 'bottom',
    delay: 500
    }, _options);
    content = _content;
    showTimer = setTimeout(wrapInRedraw(function() {
    isVisible = true;
    }), options.delay);
    };
    }

    function hide() {
    clearTimeout(showTimer);
    isVisible = false;
    }

    function withTooltip(el, content, options) {
    el.attrs.onmouseenter = show(content, assign({
    position: 'bottom',
    delay: 500
    }, options));
    el.attrs.onmouseout = hide;
    return el;
    }

    function view() {
    var classy = require('client/utils/viewhelper').classy;

    if (!content) {
    return;
    }
    var classes = {
    'tooltip-hidden': !isVisible,
    'tooltip-dark': options.dark
    };
    classes['tooltip-' + options.position] = true;
    return m('.tooltip', {
    className: classy(classes),
    config: function(element) {
    var contentDimensions = element.getBoundingClientRect();
    var targetVerticalCenter = targetDimensions.top + targetDimensions.height/2;
    var targetHorizontalCenter = targetDimensions.left + targetDimensions.width/2;

    // ensure that bubble is on screen
    if (targetHorizontalCenter + contentDimensions.width / 2 > window.innerWidth) {
    options.position = 'left';
    }
    if (targetHorizontalCenter - contentDimensions.width / 2 < 0) {
    options.position = 'right';
    }
    if (targetVerticalCenter - contentDimensions.height / 2 < 0) {
    options.position = 'bottom';
    }
    if (targetVerticalCenter + contentDimensions.height / 2 > window.innerHeight) {
    options.position = 'top';
    }

    // default bottom
    var left = targetHorizontalCenter - contentDimensions.width/2;
    var top = targetDimensions.bottom;
    if (options.position === 'right') {
    left = targetDimensions.right;
    top = targetVerticalCenter - contentDimensions.height/2;
    } else if (options.position === 'top') {
    left = targetHorizontalCenter - contentDimensions.width/2;
    top = targetDimensions.top - contentDimensions.height;
    } else if (options.position === 'left') {
    left = targetDimensions.left - contentDimensions.width;
    top = targetVerticalCenter - contentDimensions.height/2;
    }

    // again ensure that bubble is on screen in case it's in one of the screen edges
    left = minMax(0, left, window.innerWidth - contentDimensions.width);
    top = minMax(0, top, window.innerHeight - contentDimensions.height);

    element.style.left = px(Math.floor(window.scrollX + left));
    element.style.top = px(Math.floor(window.scrollY + top));
    }
    }, isFunction(content) ? content() : content);
    }

    module.exports = {
    show: show,
    hide: hide,
    view: view,
    withTooltip: withTooltip
    };
    42 changes: 42 additions & 0 deletions tooltip.styl
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,42 @@
    .tooltip
    font-size: 0.8rem
    text-align: center
    z-index: zIndexTooltip
    transition: opacity 0.3s ease-in-out
    opacity: 1
    position: absolute
    display: block
    max-width: 17rem
    line-height: 1rem
    .tooltip-hidden
    transition: none
    pointer-events: none
    opacity: 0
    .tooltip-dark
    .icon svg
    fill: white
    color: white
    .tooltip-right
    margin-left: triangleSize
    &.tooltip-dark
    bubble: left center rgba(black, 0.8)
    &:not(.tooltip-dark)
    bubble: left center white defaultBorderColor
    .tooltip-bottom
    margin-top: triangleSize
    &.tooltip-dark
    bubble: top center rgba(black, 0.8)
    &:not(.tooltip-dark)
    bubble: top center white defaultBorderColor
    .tooltip-top
    margin-top: - triangleSize
    &.tooltip-dark
    bubble: bottom center rgba(black, 0.8)
    &:not(.tooltip-dark)
    bubble: bottom center white defaultBorderColor
    .tooltip-left
    margin-left: - triangleSize
    &.tooltip-dark
    bubble: right center rgba(black, 0.8)
    &:not(.tooltip-dark)
    bubble: right center white defaultBorderColor