UNPKG

@atlassian/aui

Version:

Atlassian User Interface Framework

160 lines (131 loc) 4.6 kB
'use strict'; import Tether from 'tether'; var ATTR_ALIGNMENT = 'alignment'; var ATTR_ALIGNMENT_STATIC = 'alignment-static'; var ATTR_CONTAINER = 'alignment-container'; var CLASS_PREFIX_ALIGNMENT = 'aui-alignment'; var CLASS_PREFIX_SIDE = 'aui-alignment-side-'; var CLASS_PREFIX_SNAP = 'aui-alignment-snap-'; var DEFAULT_ATTACHMENT = 'right middle'; var attachmentMap = { 'top left': {el: 'bottom left', target: 'top left'}, 'top center': {el: 'bottom center', target: 'top center'}, 'top right': {el: 'bottom right', target: 'top right'}, 'right top': {el: 'top left', target: 'top right'}, 'right middle': {el: 'middle left', target: 'middle right'}, 'right bottom': {el: 'bottom left', target: 'bottom right'}, 'bottom left': {el: 'top left', target: 'bottom left'}, 'bottom center': {el: 'top center', target: 'bottom center'}, 'bottom right': {el: 'top right', target: 'bottom right'}, 'left top': {el: 'top right', target: 'top left'}, 'left middle': {el: 'middle right', target: 'middle left'}, 'left bottom': {el: 'bottom right', target: 'bottom left'}, 'submenu left': {el: 'top left', target: 'top right'}, 'submenu right': {el: 'top right', target: 'top left'} }; function hasClass(element, className) { return (' ' + element.className + ' ').indexOf(' ' + className + ' ') !== -1; } function addAlignmentClasses (element, side, snap) { var sideClass = CLASS_PREFIX_SIDE + side; var snapClass = CLASS_PREFIX_SNAP + snap; if (!hasClass(element, sideClass)) { element.className += ' ' + sideClass; } if (!hasClass(element, snapClass)) { element.className += ' ' + snapClass; } } function getAttribute (element, name) { return element.getAttribute(name) || element.getAttribute('data-aui-' + name); } function hasAttribute (element, name) { return element.hasAttribute(name) || element.hasAttribute('data-aui-' + name); } function getAlignment (element) { let [side, snap] = (getAttribute(element, ATTR_ALIGNMENT) || DEFAULT_ATTACHMENT).split(' '); return { side, snap }; } function getContainer (element) { var container = getAttribute(element, ATTR_CONTAINER) || window; if (typeof container === 'string') { container = document.querySelector(container); } return container; } function calculateBestAlignmentSnap (target, container) { var snap = 'left'; if (!container || container === window || container === document) { container = document.documentElement; } if (container && container.nodeType && container.nodeType === Node.ELEMENT_NODE) { let containerBounds = container.getBoundingClientRect(); let targetBounds = target.getBoundingClientRect(); if (targetBounds.left > containerBounds.right / 2) { snap = 'right'; } } return snap; } function getAttachment (side, snap) { return attachmentMap[side + ' ' + snap] || attachmentMap[DEFAULT_ATTACHMENT]; } function Alignment (element, target) { var container = getContainer(element); var alignment = getAlignment(element); if (!alignment.snap || alignment.snap === 'auto') { alignment.snap = calculateBestAlignmentSnap(target, container); } var attachment = getAttachment(alignment.side, alignment.snap); var isStaticallyAligned = hasAttribute(element, ATTR_ALIGNMENT_STATIC); var tether = new Tether({ enabled: false, element: element, target: target, attachment: attachment.el, targetAttachment: attachment.target, classPrefix: CLASS_PREFIX_ALIGNMENT, constraints: [ { // Try and keep the element on page to: (container === window) ? 'window' : container, attachment: isStaticallyAligned === true ? 'none' : 'together' } ] }); addAlignmentClasses(element, alignment.side, alignment.snap); this._auiTether = tether; } Alignment.prototype = { /** * Stops aligning and cleans up. * * @returns {Alignment} */ destroy: function () { this._auiTether.destroy(); return this; }, /** * Disables alignment. * * @returns {Alignment} */ disable: function () { this._auiTether.disable(); return this; }, /** * Enables alignment. * * @returns {Alignment} */ enable: function () { this._auiTether.enable(); return this; } }; export default Alignment;