@gechiui/components
Version:
UI components for GeChiUI.
149 lines (118 loc) • 3.84 kB
JavaScript
;
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _element = require("@gechiui/element");
var _extends2 = _interopRequireDefault(require("@babel/runtime/helpers/extends"));
var _lodash = require("lodash");
var _classnames = _interopRequireDefault(require("classnames"));
var _dom = require("@gechiui/dom");
var _disabledStyles = require("./styles/disabled-styles");
/**
* External dependencies
*/
/**
* GeChiUI dependencies
*/
/**
* Internal dependencies
*/
const Context = (0, _element.createContext)(false);
const {
Consumer,
Provider
} = Context;
/**
* 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'];
/**
* @typedef OwnProps
* @property {string} [className] Classname for the disabled element.
* @property {import('react').ReactNode} children Children to disable.
* @property {boolean} [isDisabled=true] Whether to disable the children.
*/
/**
* @param {OwnProps & import('react').HTMLAttributes<HTMLDivElement>} props
* @return {JSX.Element} Element wrapping the children to disable them when isDisabled is true.
*/
function Disabled(_ref) {
let {
className,
children,
isDisabled = true,
...props
} = _ref;
/** @type {import('react').RefObject<HTMLDivElement>} */
const node = (0, _element.useRef)(null);
const disable = () => {
if (!node.current) {
return;
}
_dom.focus.focusable.find(node.current).forEach(focusable => {
if ((0, _lodash.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 = (0, _element.useCallback)((0, _lodash.debounce)(disable, undefined, {
leading: true
}), []);
(0, _element.useLayoutEffect)(() => {
if (!isDisabled) {
return;
}
disable();
/** @type {MutationObserver | undefined} */
let observer;
if (node.current) {
observer = new window.MutationObserver(debouncedDisable);
observer.observe(node.current, {
childList: true,
attributes: true,
subtree: true
});
}
return () => {
if (observer) {
observer.disconnect();
}
debouncedDisable.cancel();
};
}, []);
if (!isDisabled) {
return (0, _element.createElement)(Provider, {
value: false
}, children);
}
return (0, _element.createElement)(Provider, {
value: true
}, (0, _element.createElement)(_disabledStyles.StyledWrapper, (0, _extends2.default)({
ref: node,
className: (0, _classnames.default)(className, 'components-disabled')
}, props), children));
}
Disabled.Context = Context;
Disabled.Consumer = Consumer;
var _default = Disabled;
exports.default = _default;
//# sourceMappingURL=index.js.map