semantic-ui-react
Version:
The official Semantic-UI-React integration.
164 lines (127 loc) • 4.56 kB
JavaScript
var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
exports.__esModule = true;
exports.computeClassNames = computeClassNames;
exports.computeClassNamesDifference = computeClassNamesDifference;
exports.default = useClassNamesOnNode;
exports.NodeRegistry = exports.handleClassNamesChange = void 0;
var _reactComponentRef = require("@fluentui/react-component-ref");
var _react = _interopRequireDefault(require("react"));
var _useIsomorphicLayoutEffect = _interopRequireDefault(require("./useIsomorphicLayoutEffect"));
var CLASS_NAME_DELITIMITER = /\s+/;
/**
* Accepts a set of ref objects that contain classnames as a string and returns an array of unique
* classNames.
*
* @param {Set<React.RefObject>|undefined} classNameRefs
* @returns String[]
*/
function computeClassNames(classNameRefs) {
var classNames = [];
if (classNameRefs) {
classNameRefs.forEach(function (classNameRef) {
if (typeof classNameRef.current === 'string') {
var classNamesForRef = classNameRef.current.split(CLASS_NAME_DELITIMITER);
classNamesForRef.forEach(function (className) {
classNames.push(className);
});
}
});
return classNames.filter(function (className, i, array) {
return className.length > 0 && array.indexOf(className) === i;
});
}
return [];
}
/**
* Computes classnames that should be removed and added to a node based on input differences.
*
* @param {String[]} prevClassNames
* @param {String[]} currentClassNames
*/
function computeClassNamesDifference(prevClassNames, currentClassNames) {
return [currentClassNames.filter(function (className) {
return prevClassNames.indexOf(className) === -1;
}), prevClassNames.filter(function (className) {
return currentClassNames.indexOf(className) === -1;
})];
}
var prevClassNames = new Map();
/**
* @param {HTMLElement} node
* @param {Set<React.RefObject>|undefined} classNameRefs
*/
var handleClassNamesChange = function handleClassNamesChange(node, classNameRefs) {
var currentClassNames = computeClassNames(classNameRefs);
var _computeClassNamesDif = computeClassNamesDifference(prevClassNames.get(node) || [], currentClassNames),
forAdd = _computeClassNamesDif[0],
forRemoval = _computeClassNamesDif[1];
if (node) {
forAdd.forEach(function (className) {
return node.classList.add(className);
});
forRemoval.forEach(function (className) {
return node.classList.remove(className);
});
}
prevClassNames.set(node, currentClassNames);
};
exports.handleClassNamesChange = handleClassNamesChange;
var NodeRegistry = function NodeRegistry() {
var _this = this;
this.add = function (node, classNameRef) {
if (_this.nodes.has(node)) {
var _set = _this.nodes.get(node);
_set.add(classNameRef);
return;
} // IE11 does not support constructor params
var set = new Set();
set.add(classNameRef);
_this.nodes.set(node, set);
};
this.del = function (node, classNameRef) {
if (!_this.nodes.has(node)) {
return;
}
var set = _this.nodes.get(node);
if (set.size === 1) {
_this.nodes.delete(node);
return;
}
set.delete(classNameRef);
};
this.emit = function (node, callback) {
callback(node, _this.nodes.get(node));
};
this.nodes = new Map();
};
exports.NodeRegistry = NodeRegistry;
var nodeRegistry = new NodeRegistry();
/**
* A React hooks that allows to manage classNames on a DOM node in declarative manner. Accepts
* a HTML element or React ref objects with it.
*
* @param {HTMLElement|React.RefObject} node
* @param {String} className
*/
function useClassNamesOnNode(node, className) {
var classNameRef = _react.default.useRef();
var isMounted = _react.default.useRef(false);
(0, _useIsomorphicLayoutEffect.default)(function () {
classNameRef.current = className;
if (isMounted.current) {
var element = (0, _reactComponentRef.isRefObject)(node) ? node.current : node;
nodeRegistry.emit(element, handleClassNamesChange);
}
isMounted.current = true;
}, [className]);
(0, _useIsomorphicLayoutEffect.default)(function () {
var element = (0, _reactComponentRef.isRefObject)(node) ? node.current : node;
nodeRegistry.add(element, classNameRef);
nodeRegistry.emit(element, handleClassNamesChange);
return function () {
nodeRegistry.del(element, classNameRef);
nodeRegistry.emit(element, handleClassNamesChange);
};
}, [node]);
}
;