Commit 40084ba4 authored by Mark Florian's avatar Mark Florian Committed by David O'Regan

Implement loading icon JS helper

This helper should *only* be used in existing legacy areas of code where
Vue is not in use, as part of the migration strategy defined in
https://gitlab.com/groups/gitlab-org/-/epics/7626.
parent e67ba2d7
import { __ } from '~/locale';
const baseCSSClass = 'gl-spinner';
/**
* Returns a loading icon/spinner element.
*
* This should *only* be used in existing legacy areas of code where Vue is not
* in use, as part of the migration strategy defined in
* https://gitlab.com/groups/gitlab-org/-/epics/7626.
*
* @param {object} props - The props to configure the spinner.
* @param {boolean} inline - Display the spinner inline; otherwise, as a block.
* @param {string} color - The color of the spinner ('dark' or 'light')
* @param {string} size - The size of the spinner ('sm', 'md', 'lg', 'xl')
* @param {string[]} classes - Additional classes to apply to the element.
* @param {string} label - The ARIA label to apply to the spinner.
* @returns {HTMLElement}
*/
export const loadingIconForLegacyJS = ({
inline = false,
color = 'dark',
size = 'sm',
classes = [],
label = __('Loading'),
} = {}) => {
const container = document.createElement(inline ? 'span' : 'div');
container.classList.add(`${baseCSSClass}-container`, ...classes);
container.setAttribute('role', 'status');
const spinner = document.createElement('span');
spinner.classList.add(baseCSSClass, `${baseCSSClass}-${color}`, `${baseCSSClass}-${size}`);
spinner.setAttribute('aria-label', label);
container.appendChild(spinner);
return container;
};
import { loadingIconForLegacyJS } from '~/loading_icon_for_legacy_js';
describe('loadingIconForLegacyJS', () => {
it('sets the correct defaults', () => {
const el = loadingIconForLegacyJS();
expect(el.tagName).toBe('DIV');
expect(el.className).toBe('gl-spinner-container');
expect(el.querySelector('.gl-spinner-sm')).toEqual(expect.any(HTMLElement));
expect(el.querySelector('.gl-spinner-dark')).toEqual(expect.any(HTMLElement));
expect(el.querySelector('[aria-label="Loading"]')).toEqual(expect.any(HTMLElement));
expect(el.getAttribute('role')).toBe('status');
});
it('renders a span if inline = true', () => {
expect(loadingIconForLegacyJS({ inline: true }).tagName).toBe('SPAN');
});
it('can render a different size', () => {
const el = loadingIconForLegacyJS({ size: 'lg' });
expect(el.querySelector('.gl-spinner-lg')).toEqual(expect.any(HTMLElement));
});
it('can render a different color', () => {
const el = loadingIconForLegacyJS({ color: 'light' });
expect(el.querySelector('.gl-spinner-light')).toEqual(expect.any(HTMLElement));
});
it('can render a different aria-label', () => {
const el = loadingIconForLegacyJS({ label: 'Foo' });
expect(el.querySelector('[aria-label="Foo"]')).toEqual(expect.any(HTMLElement));
});
it('can render additional classes', () => {
const classes = ['foo', 'bar'];
const el = loadingIconForLegacyJS({ classes });
expect(el.classList).toContain(...classes);
});
});
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment