@wordpress/components
Version:
UI components for WordPress.
105 lines (89 loc) • 2.69 kB
JavaScript
import _extends from "@babel/runtime/helpers/esm/extends";
import { createElement } from "@wordpress/element";
/**
* External dependencies
*/
import { includes, debounce } from 'lodash';
import classnames from 'classnames';
/**
* WordPress dependencies
*/
import { createContext, useCallback, useLayoutEffect, useRef } from '@wordpress/element';
import { focus } from '@wordpress/dom';
/**
* Internal dependencies
*/
import { StyledWrapper } from './styles/disabled-styles';
const {
Consumer,
Provider
} = createContext(false);
/**
* Names of control nodes which qualify for disabled behavior.
*
* See WHATWG HTML Standard: 4.10.18.5: "Enabling and disabling form controls: the disabled attribute".
*
* @see https://html.spec.whatwg.org/multipage/form-control-infrastructure.html#enabling-and-disabling-form-controls:-the-disabled-attribute
*
* @type {string[]}
*/
const DISABLED_ELIGIBLE_NODE_NAMES = ['BUTTON', 'FIELDSET', 'INPUT', 'OPTGROUP', 'OPTION', 'SELECT', 'TEXTAREA'];
function Disabled({
className,
children,
isDisabled = true,
...props
}) {
const node = useRef();
const disable = () => {
focus.focusable.find(node.current).forEach(focusable => {
if (includes(DISABLED_ELIGIBLE_NODE_NAMES, focusable.nodeName)) {
focusable.setAttribute('disabled', '');
}
if (focusable.nodeName === 'A') {
focusable.setAttribute('tabindex', -1);
}
const tabIndex = focusable.getAttribute('tabindex');
if (tabIndex !== null && tabIndex !== '-1') {
focusable.removeAttribute('tabindex');
}
if (focusable.hasAttribute('contenteditable')) {
focusable.setAttribute('contenteditable', 'false');
}
});
}; // Debounce re-disable since disabling process itself will incur
// additional mutations which should be ignored.
const debouncedDisable = useCallback(debounce(disable, {
leading: true
}), []);
useLayoutEffect(() => {
if (!isDisabled) {
return;
}
disable();
const observer = new window.MutationObserver(debouncedDisable);
observer.observe(node.current, {
childList: true,
attributes: true,
subtree: true
});
return () => {
observer.disconnect();
debouncedDisable.cancel();
};
}, []);
if (!isDisabled) {
return createElement(Provider, {
value: false
}, children);
}
return createElement(Provider, {
value: true
}, createElement(StyledWrapper, _extends({
ref: node,
className: classnames(className, 'components-disabled')
}, props), children));
}
Disabled.Consumer = Consumer;
export default Disabled;
//# sourceMappingURL=index.js.map