@engie-group/fluid-design-system-react
Version:
Fluid Design System React
153 lines (134 loc) • 4.57 kB
text/typescript
import React from 'react';
const isUndefinedOrNull = (value: unknown): value is null | undefined => {
return typeof value === 'undefined' || value === null;
};
/**
* Generates a string from arguments that can be a string, number, array or objects with {key: value} where key is a class and value is a boolean
*/
const classNames = (...args: unknown[]): string => {
const classes = [];
for (const arg of args) {
if (!arg) {
continue;
}
const argType = typeof arg;
if (argType === 'string' || argType === 'number') {
classes.push(arg);
} else if (Array.isArray(arg)) {
if (arg.length) {
const inner = Utils.classNames.apply(null, arg);
if (inner) {
classes.push(inner);
}
}
} else if (argType === 'object') {
if (arg.toString === Object.prototype.toString) {
for (const key in arg) {
// @ts-expect-error arg is of type unknown
if (Object.prototype.hasOwnProperty.call(arg, key) && arg[key]) {
classes.push(key);
}
}
} else {
classes.push(arg.toString());
}
}
}
return classes.join(' ');
};
const coerceFunction = (func: (...args: unknown[]) => unknown) => {
if (!isUndefinedOrNull(func) && typeof func === 'function') {
return func;
} else {
return null;
}
};
const mergeRefs = <T = unknown>(
refs: Array<React.MutableRefObject<T> | React.LegacyRef<T>>
): React.RefCallback<T> => {
return (value) => {
refs.forEach((ref) => {
if (typeof ref === 'function') {
ref(value);
} else if (ref != null) {
(ref as React.MutableRefObject<T | null>).current = value;
}
});
};
};
const normalizeString = (text: string) => {
return text.normalize('NFD').replace(/[\u0300-\u036f]/g, '');
};
const normalizeAndSearchInText = (text: string, search: string): boolean => {
if (Utils.isUndefinedOrNull(text) || Utils.isUndefinedOrNull(search)) {
return false;
}
const normalizedText = Utils.normalizeString(text);
// removed in 2.13.0: `normalizedSearch` used to filter out (, ) and \ through `.replace(/\(|\)|\\/gi, '');`
const normalizedSearch = Utils.normalizeString(search);
const regExp = new RegExp(Utils.escapeRegExp(normalizedSearch), 'gi');
return normalizedText.search(regExp) !== -1;
};
// Escape special characters in a string (so regex behave properly)
const escapeRegExp = (string: string): string => {
return string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&');
};
const highlightTextAsHtml = (
content: string,
textToHighlight: string,
caseSensitive = false,
escapeAccents = true,
openingTag = '<mark class="nj-highlight">',
closingTag = '</mark>'
): string => {
const regexFlags = caseSensitive ? 'g' : 'gi';
// Escape the textToHighlight to handle special characters
const escapedTextToHighlight = Utils.escapeRegExp(textToHighlight);
let innerHtml: string;
if (Utils.isUndefinedOrNull(textToHighlight)) {
innerHtml = content;
} else {
if (escapeAccents) {
const regExp = new RegExp(Utils.normalizeString(escapedTextToHighlight), regexFlags);
const matches = Utils.normalizeString(content).matchAll(regExp);
let finalText = content;
let buffer = 0;
if (!Utils.isUndefinedOrNull(matches)) {
for (const match of matches) {
const updatedIndex = buffer + match.index;
const textBeforeOccurrence = finalText.slice(0, updatedIndex);
const occurrence = finalText.slice(updatedIndex, updatedIndex + textToHighlight.length);
const textAfterOccurrence = finalText.slice(
updatedIndex + textToHighlight.length,
finalText.length
);
finalText = `${textBeforeOccurrence}${openingTag}${occurrence}${closingTag}${textAfterOccurrence}`;
buffer = buffer + openingTag.length + closingTag.length;
}
}
innerHtml = finalText;
} else {
const regExp = new RegExp(escapedTextToHighlight, regexFlags);
innerHtml = content.replace(regExp, `${openingTag}$&${closingTag}`);
}
}
return innerHtml;
};
const omit = <T extends NonNullable<unknown>, K extends keyof T>(obj: T, ...keys: K[]) => {
return Object.fromEntries(
Object.entries(obj).filter(([key]) => {
return !keys.includes(key as K);
})
) as Omit<T, K>;
};
export const Utils = {
isUndefinedOrNull,
classNames,
coerceFunction,
mergeRefs,
normalizeString,
normalizeAndSearchInText,
escapeRegExp,
highlightTextAsHtml,
omit
};