UNPKG

@atlassian/aui

Version:

Atlassian User Interface library

170 lines (147 loc) 4.53 kB
import skate from './internal/skate'; import { getMessageLogger } from './internal/deprecation'; import { defaults, find } from 'underscore'; /** * @typedef {"small"|"medium"|"large"} SpinnerSize */ /** * @typedef {Object} SpinnerSizeConfig * @param {SpinnerSize} name * @param {number} px * @param {number} radius */ /** * @enum {SpinnerSizeConfig} * @readonly */ const SIZE = { SMALL: { name: 'small', px: 20, radius: 9, }, MEDIUM: { name: 'medium', px: 30, radius: 13.5, }, LARGE: { name: 'large', px: 50, radius: 22.5, }, }; const DEFAULTS = { filled: false, size: SIZE.MEDIUM.name, }; const filledAttributeReplacementText = `Add CSS to the parent element of the <aui-spinner>. Use CSS flexbox or grid to vertically align it. See https://css-tricks.com/centering-css-complete-guide/ for techniques.`; const filledAttributeDeprecatedLogger = getMessageLogger('<aui-spinner> filled attribute', { sinceVersion: '7.9.4', removeInVersion: '10.0.0', extraInfo: filledAttributeReplacementText }); const filledPropDeprecatedLogger = getMessageLogger('<aui-spinner> filled property', { sinceVersion: '7.9.4', removeInVersion: '10.0.0', extraInfo: filledAttributeReplacementText }); /** @deprecated */ function setMiddleTop(element, height) { const parent = element.parentNode; // only operate on elements, not documentFragment or comment nodes, etc. if (parent && parent.nodeType === 1) { const selfDomRect = element.getBoundingClientRect(); const parentDomRect = parent.getBoundingClientRect(); const parentMiddleTop = parentDomRect.top + parentDomRect.height / 2; const spinnerMiddleTop = selfDomRect.top + height / 2; element.querySelector('svg').style.top = `${parentMiddleTop - spinnerMiddleTop}px`; } } /** @deprecated */ function removeMiddleTop(element) { delete element.querySelector('svg').style.top; } function validateSize(size) { let result = SIZE.MEDIUM.name; if (typeof size === 'string') { size = size.toLowerCase(); const possibleSizes = Object.keys(SIZE).map(key => key.toLowerCase()); if (possibleSizes.indexOf(size) > -1) { result = size; } } return result; } function setSize(element, size, radius) { const svg = element.querySelector('svg'); const circle = element.querySelector('circle'); svg.setAttribute('size', size); svg.setAttribute('height', size); svg.setAttribute('width', size); svg.setAttribute('viewBox', `0 0 ${size} ${size}`); const circleSize = size / 2; circle.setAttribute('cx', circleSize); circle.setAttribute('cy', circleSize); circle.setAttribute('r', radius); } function refresh(element) { const { px, radius } = find(SIZE, s => s.name === element._data.size) || SIZE.MEDIUM; setSize(element, px, radius); if (element._data.filled) { setMiddleTop(element, px); } else { removeMiddleTop(element); } } const SpinnerEl = skate('aui-spinner', { template(element) { element.innerHTML = '<div class="aui-spinner spinner"><svg focusable="false"><circle></circle></svg></div>'; refresh(element); }, attached(element) { refresh(element); }, attributes: { filled: { /** @deprecated */ created: function(element) { filledAttributeDeprecatedLogger(); element._data.filled = true; refresh(element); }, /** @deprecated */ removed: function(element) { element._data.filled = false; refresh(element); } }, size(element, data) { element._data.size = validateSize(data.newValue); refresh(element); }, }, prototype: { get _data() { return this.__data || (this._data = defaults({}, DEFAULTS)); }, set _data(data) { return this.__data = data; }, /** @deprecated */ set filled(isFilled) { filledPropDeprecatedLogger(); !!isFilled ? this.setAttribute('filled', '') : this.removeAttribute('filled'); }, set size(newSize) { const size = validateSize(newSize); this.setAttribute('size', size); }, }, }); export default SpinnerEl; export { SIZE };