Refactor #3965 - For FocusTrap
parent
eea680f535
commit
a6e8c4d163
|
@ -8,6 +8,89 @@
|
|||
*/
|
||||
import { DirectiveBinding, ObjectDirective } from 'vue';
|
||||
|
||||
/**
|
||||
* Custom passthrough(pt) hooks options.
|
||||
*/
|
||||
export interface FocusTrapPassThroughHooksOptions {
|
||||
/**
|
||||
* Called before bound element's attributes or event listeners are applied.
|
||||
*/
|
||||
created?: DirectiveBinding;
|
||||
/**
|
||||
* Called right before the element is inserted into the DOM.
|
||||
*/
|
||||
beforeMount?: DirectiveBinding;
|
||||
/**
|
||||
* Called when the bound element's parent component and all its children are mounted.
|
||||
*/
|
||||
mounted?: DirectiveBinding;
|
||||
/**
|
||||
* Called before the parent component is updated.
|
||||
*/
|
||||
beforeUpdate?: DirectiveBinding;
|
||||
/**
|
||||
* Called after the parent component and all of its children have updated all of its children have updated.
|
||||
*/
|
||||
updated?: DirectiveBinding;
|
||||
/**
|
||||
* Called before the parent component is unmounted.
|
||||
*/
|
||||
beforeUnmount?: DirectiveBinding;
|
||||
/**
|
||||
* Called when the parent component is unmounted.
|
||||
*/
|
||||
unmounted?: DirectiveBinding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom passthrough(pt) css options.
|
||||
*/
|
||||
export interface FocusTrapPassThroughCSSOptions {
|
||||
/**
|
||||
* Style class of the element.
|
||||
*/
|
||||
class?: any;
|
||||
/**
|
||||
* Inline style of the element.
|
||||
*/
|
||||
style?: any;
|
||||
}
|
||||
|
||||
export interface FocusTrapPassThroughDirectiveOptions {
|
||||
/**
|
||||
* Uses to pass attributes to the life cycle hooks.
|
||||
* @see {@link FocusTrapPassThroughHooksOptions}
|
||||
*/
|
||||
hooks?: FocusTrapPassThroughHooksOptions;
|
||||
/**
|
||||
* Uses to pass attributes to the styles.
|
||||
* @see {@link FocusTrapPassThroughCSSOptions}
|
||||
*/
|
||||
css?: FocusTrapPassThroughCSSOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Custom passthrough(pt) options.
|
||||
* @see {@link FocusTrapOptions.pt}
|
||||
*/
|
||||
export interface FocusTrapPassThroughOptions {
|
||||
/**
|
||||
* Uses to pass attributes to the root's DOM element.
|
||||
* @see {@link FocusTrapPassThroughDirectiveOptions}
|
||||
*/
|
||||
root?: FocusTrapPassThroughDirectiveOptions;
|
||||
/**
|
||||
* Uses to pass attributes to the first focusable element's DOM element.
|
||||
* @see {@link FocusTrapPassThroughDirectiveOptions}
|
||||
*/
|
||||
firstFocusableElement?: FocusTrapPassThroughDirectiveOptions;
|
||||
/**
|
||||
* Uses to pass attributes to the last focusable element's DOM element.
|
||||
* @see {@link FocusTrapPassThroughDirectiveOptions}
|
||||
*/
|
||||
lastFocusableElement?: FocusTrapPassThroughDirectiveOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Defines options of FocusTrap.
|
||||
*/
|
||||
|
@ -17,6 +100,16 @@ export interface FocusTrapOptions {
|
|||
* @defaultValue false
|
||||
*/
|
||||
disabled?: boolean | undefined;
|
||||
/**
|
||||
* When When disabled, focustrap will not focus by default.
|
||||
* @defaultValue true
|
||||
*/
|
||||
autoFocus?: boolean | undefined;
|
||||
/**
|
||||
* Uses to pass attributes to DOM elements inside the component.
|
||||
* @type {FocusTrapPassThroughOptions}
|
||||
*/
|
||||
pt?: FocusTrapPassThroughOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
import { BaseDirective } from 'primevue/basedirective';
|
||||
import { DomHandler, ObjectUtils } from 'primevue/utils';
|
||||
|
||||
function bind(el, binding) {
|
||||
|
@ -37,9 +38,9 @@ function unbind(el) {
|
|||
|
||||
function autoFocus(el, binding) {
|
||||
const { autoFocusSelector = '', firstFocusableSelector = '', autoFocus = false } = binding.value || {};
|
||||
let focusableElement = DomHandler.getFirstFocusableElement(el, `[autofocus]:not(.p-hidden-focusable)${autoFocusSelector}`);
|
||||
let focusableElement = DomHandler.getFirstFocusableElement(el, `[autofocus]:not([data-p-hidden-focusable="true"])${autoFocusSelector}`);
|
||||
|
||||
autoFocus && !focusableElement && (focusableElement = DomHandler.getFirstFocusableElement(el, `:not(.p-hidden-focusable)${firstFocusableSelector}`));
|
||||
autoFocus && !focusableElement && (focusableElement = DomHandler.getFirstFocusableElement(el, `:not([data-p-hidden-focusable="true"])${firstFocusableSelector}`));
|
||||
DomHandler.focus(focusableElement);
|
||||
}
|
||||
|
||||
|
@ -47,7 +48,7 @@ function onFirstHiddenElementFocus(event) {
|
|||
const { currentTarget, relatedTarget } = event;
|
||||
const focusableElement =
|
||||
relatedTarget === currentTarget.$_pfocustrap_lasthiddenfocusableelement
|
||||
? DomHandler.getFirstFocusableElement(currentTarget.parentElement, `:not(.p-hidden-focusable)${currentTarget.$_pfocustrap_focusableselector}`)
|
||||
? DomHandler.getFirstFocusableElement(currentTarget.parentElement, `:not([data-p-hidden-focusable="true"])${currentTarget.$_pfocustrap_focusableselector}`)
|
||||
: currentTarget.$_pfocustrap_lasthiddenfocusableelement;
|
||||
|
||||
DomHandler.focus(focusableElement);
|
||||
|
@ -57,7 +58,7 @@ function onLastHiddenElementFocus(event) {
|
|||
const { currentTarget, relatedTarget } = event;
|
||||
const focusableElement =
|
||||
relatedTarget === currentTarget.$_pfocustrap_firsthiddenfocusableelement
|
||||
? DomHandler.getLastFocusableElement(currentTarget.parentElement, `:not(.p-hidden-focusable)${currentTarget.$_pfocustrap_focusableselector}`)
|
||||
? DomHandler.getLastFocusableElement(currentTarget.parentElement, `:not([data-p-hidden-focusable="true"])${currentTarget.$_pfocustrap_focusableselector}`)
|
||||
: currentTarget.$_pfocustrap_firsthiddenfocusableelement;
|
||||
|
||||
DomHandler.focus(focusableElement);
|
||||
|
@ -69,10 +70,24 @@ function createHiddenFocusableElements(el, binding) {
|
|||
const createFocusableElement = (onFocus) => {
|
||||
const element = document.createElement('span');
|
||||
|
||||
element.classList.value = 'p-hidden-accessible p-hidden-focusable';
|
||||
if (binding.instance.$primevue && binding.instance.$primevue.config && binding.instance.$primevue.config.unstyled) {
|
||||
element.style.border = '0';
|
||||
element.style.clip = 'rect(0 0 0 0)';
|
||||
element.style.height = '1px';
|
||||
element.style.margin = '-1px';
|
||||
element.style.overflow = 'hidden';
|
||||
element.style.padding = '0';
|
||||
element.style.position = 'absolute';
|
||||
element.style.width = '1px';
|
||||
} else {
|
||||
element.classList = 'p-hidden-accessible p-hidden-focusable';
|
||||
}
|
||||
|
||||
element.tabIndex = tabIndex;
|
||||
element.setAttribute('aria-hidden', 'true');
|
||||
element.setAttribute('role', 'presentation');
|
||||
element.setAttribute('data-p-hidden-accessible', true);
|
||||
element.setAttribute('data-p-hidden-focusable', true);
|
||||
element.addEventListener('focus', onFocus);
|
||||
|
||||
return element;
|
||||
|
@ -83,15 +98,17 @@ function createHiddenFocusableElements(el, binding) {
|
|||
|
||||
firstFocusableElement.$_pfocustrap_lasthiddenfocusableelement = lastFocusableElement;
|
||||
firstFocusableElement.$_pfocustrap_focusableselector = firstFocusableSelector;
|
||||
firstFocusableElement.setAttribute('data-pc-section', 'firstfocusableelement');
|
||||
|
||||
lastFocusableElement.$_pfocustrap_firsthiddenfocusableelement = firstFocusableElement;
|
||||
lastFocusableElement.$_pfocustrap_focusableselector = lastFocusableSelector;
|
||||
lastFocusableElement.setAttribute('data-pc-section', 'lastfocusableelement');
|
||||
|
||||
el.prepend(firstFocusableElement);
|
||||
el.append(lastFocusableElement);
|
||||
}
|
||||
|
||||
const FocusTrap = {
|
||||
const FocusTrap = BaseDirective.extend('focustrap', {
|
||||
mounted(el, binding) {
|
||||
const { disabled } = binding.value || {};
|
||||
|
||||
|
@ -100,7 +117,14 @@ const FocusTrap = {
|
|||
bind(el, binding);
|
||||
autoFocus(el, binding);
|
||||
}
|
||||
|
||||
el.setAttribute('data-pc-section', 'root');
|
||||
el.setAttribute('data-pc-name', 'focustrap');
|
||||
|
||||
BaseDirective.directiveElement = el;
|
||||
BaseDirective.handleCSS('focustrap', el, binding);
|
||||
},
|
||||
|
||||
updated(el, binding) {
|
||||
const { disabled } = binding.value || {};
|
||||
|
||||
|
@ -109,6 +133,6 @@ const FocusTrap = {
|
|||
unmounted(el) {
|
||||
unbind(el);
|
||||
}
|
||||
};
|
||||
});
|
||||
|
||||
export default FocusTrap;
|
||||
|
|
Loading…
Reference in New Issue