mirror of
https://github.com/robonen/tools.git
synced 2026-03-20 19:04:46 +00:00
feat(packages/platform): add focusGuard brwoser util
This commit is contained in:
69
packages/platform/src/browsers/focusGuard/index.test.ts
Normal file
69
packages/platform/src/browsers/focusGuard/index.test.ts
Normal file
@@ -0,0 +1,69 @@
|
||||
import { describe, it, expect, beforeEach } from 'vitest';
|
||||
import { focusGuard, createGuardAttrs } from '.';
|
||||
|
||||
describe('focusGuard', () => {
|
||||
beforeEach(() => {
|
||||
document.body.innerHTML = '';
|
||||
});
|
||||
|
||||
it('initialize with the correct default namespace', () => {
|
||||
const guard = focusGuard();
|
||||
|
||||
expect(guard.selector).toBe('data-focus-guard');
|
||||
});
|
||||
|
||||
it('create focus guards in the DOM', () => {
|
||||
const guard = focusGuard();
|
||||
guard.createGuard();
|
||||
|
||||
const guards = document.querySelectorAll(`[${guard.selector}]`);
|
||||
expect(guards.length).toBe(2);
|
||||
|
||||
guards.forEach((element) => {
|
||||
expect(element.tagName).toBe('SPAN');
|
||||
expect(element.getAttribute('tabindex')).toBe('0');
|
||||
});
|
||||
});
|
||||
|
||||
it('remove focus guards from the DOM correctly', () => {
|
||||
const guard = focusGuard();
|
||||
guard.createGuard();
|
||||
guard.removeGuard();
|
||||
|
||||
const guards = document.querySelectorAll(`[${guard.selector}]`);
|
||||
|
||||
expect(guards.length).toBe(0);
|
||||
});
|
||||
|
||||
it('reuse the same guards when calling createGuard multiple times', () => {
|
||||
const guard = focusGuard();
|
||||
guard.createGuard();
|
||||
guard.createGuard();
|
||||
|
||||
guard.removeGuard();
|
||||
const guards = document.querySelectorAll(`[${guard.selector}]`);
|
||||
|
||||
expect(guards.length).toBe(0);
|
||||
});
|
||||
|
||||
it('allow custom namespaces', () => {
|
||||
const namespace = 'custom-guard';
|
||||
const guard = focusGuard(namespace);
|
||||
guard.createGuard();
|
||||
|
||||
expect(guard.selector).toBe(`data-${namespace}`);
|
||||
|
||||
const guards = document.querySelectorAll(`[${guard.selector}]`);
|
||||
expect(guards.length).toBe(2);
|
||||
});
|
||||
|
||||
it('createGuardAttrs should create a valid guard element', () => {
|
||||
const namespace = 'custom-guard';
|
||||
const element = createGuardAttrs(namespace);
|
||||
|
||||
expect(element.tagName).toBe('SPAN');
|
||||
expect(element.getAttribute(namespace)).toBe('');
|
||||
expect(element.getAttribute('tabindex')).toBe('0');
|
||||
expect(element.getAttribute('style')).toBe('outline: none; opacity: 0; pointer-events: none; position: fixed;');
|
||||
});
|
||||
});
|
||||
50
packages/platform/src/browsers/focusGuard/index.ts
Normal file
50
packages/platform/src/browsers/focusGuard/index.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* @name focusGuard
|
||||
* @category Browsers
|
||||
* @description Adds a pair of focus guards at the boundaries of the DOM tree to ensure consistent focus behavior
|
||||
*
|
||||
* @param {string} namespace - The namespace to use for the guard attributes
|
||||
* @returns {Object} - An object containing the selector, createGuard, and removeGuard functions
|
||||
*
|
||||
* @example
|
||||
* const guard = focusGuard();
|
||||
* guard.createGuard();
|
||||
* guard.removeGuard();
|
||||
*
|
||||
* @example
|
||||
* const guard = focusGuard('focus-guard');
|
||||
* guard.createGuard();
|
||||
* guard.removeGuard();
|
||||
*
|
||||
* @since 0.0.3
|
||||
*/
|
||||
export function focusGuard(namespace: string = 'focus-guard') {
|
||||
const guardAttr = `data-${namespace}`;
|
||||
|
||||
const createGuard = () => {
|
||||
const edges = document.querySelectorAll(`[${guardAttr}]`);
|
||||
|
||||
document.body.insertAdjacentElement('afterbegin', edges[0] ?? createGuardAttrs(guardAttr));
|
||||
document.body.insertAdjacentElement('beforeend', edges[1] ?? createGuardAttrs(guardAttr));
|
||||
};
|
||||
|
||||
const removeGuard = () => {
|
||||
document.querySelectorAll(`[${guardAttr}]`).forEach((element) => element.remove());
|
||||
};
|
||||
|
||||
return {
|
||||
selector: guardAttr,
|
||||
createGuard,
|
||||
removeGuard,
|
||||
};
|
||||
}
|
||||
|
||||
export function createGuardAttrs(namespace: string) {
|
||||
const element = document.createElement('span');
|
||||
|
||||
element.setAttribute(namespace, '');
|
||||
element.setAttribute('tabindex', '0');
|
||||
element.setAttribute('style', 'outline: none; opacity: 0; pointer-events: none; position: fixed;');
|
||||
|
||||
return element;
|
||||
}
|
||||
1
packages/platform/src/browsers/index.ts
Normal file
1
packages/platform/src/browsers/index.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from './focusGuard';
|
||||
Reference in New Issue
Block a user