@neo4j-ndl/react
Version:
React implementation of Neo4j Design System
167 lines • 6.77 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.truncateReactNodeByCharacters = exports.getTextContent = void 0;
/**
*
* Copyright (c) "Neo4j"
* Neo4j Sweden AB [http://neo4j.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
const react_1 = __importDefault(require("react"));
const constants_1 = require("./constants");
/**
* Recursively extracts plain text from React nodes
*/
const getTextContent = (node) => {
if (typeof node === 'string') {
return node;
}
if (typeof node === 'number') {
return node.toString();
}
if (react_1.default.isValidElement(node)) {
// Type assertion to access props safely
const element = node;
return (0, exports.getTextContent)(element.props.children);
}
if (Array.isArray(node)) {
return node.map(exports.getTextContent).join('');
}
return '';
};
exports.getTextContent = getTextContent;
/**
* Truncates React node content by character count while preserving element structure.
*/
const truncateReactNodeByCharacters = (node, maxCharacters, shouldAddEllipsis = true) => {
// Handle the case where node is an array (React children)
const normalizedNode = Array.isArray(node)
? react_1.default.createElement(react_1.default.Fragment, null, ...node)
: node;
// Get the total character count first to determine if truncation is needed
const totalLength = (0, exports.getTextContent)(normalizedNode).length;
if (totalLength <= maxCharacters) {
return { needsTruncation: false, truncatedContent: null };
}
let charCount = 0;
let hasReachedLimit = false;
const truncateNode = (currentNode) => {
// Stop processing if character limit is reached
if (hasReachedLimit || charCount >= maxCharacters) {
hasReachedLimit = true;
return null;
}
// Handle arrays of children (mixed content case)
if (Array.isArray(currentNode)) {
const truncatedChildren = [];
for (const child of currentNode) {
if (hasReachedLimit || charCount >= maxCharacters) {
break;
}
const truncatedChild = truncateNode(child);
if (truncatedChild !== null) {
truncatedChildren.push(truncatedChild);
}
}
return truncatedChildren.length > 0 ? truncatedChildren : null;
}
if (typeof currentNode === 'string') {
const availableChars = maxCharacters - charCount;
if (currentNode.length <= availableChars) {
charCount += currentNode.length;
return currentNode;
}
// Truncate at character limit, preferring word boundaries
let truncated = currentNode.substring(0, availableChars);
const lastSpaceIndex = truncated.lastIndexOf(' ');
if (lastSpaceIndex > availableChars * constants_1.ESTIMATION_FACTORS.WORD_BOUNDARY) {
truncated = truncated.substring(0, lastSpaceIndex);
}
truncated = truncated.trim();
charCount += truncated.length;
hasReachedLimit = true;
return truncated;
}
if (typeof currentNode === 'number') {
const str = currentNode.toString();
const availableChars = maxCharacters - charCount;
if (str.length <= availableChars) {
charCount += str.length;
return currentNode;
}
const truncated = str.substring(0, availableChars);
charCount += truncated.length;
hasReachedLimit = true;
return truncated;
}
if (!react_1.default.isValidElement(currentNode)) {
return currentNode;
}
const { children } = currentNode.props;
if (children === null || children === undefined) {
return currentNode;
}
if (typeof children === 'string') {
const truncatedChild = truncateNode(children);
if (truncatedChild === null) {
return null;
}
return react_1.default.cloneElement(currentNode, {}, truncatedChild);
}
if (Array.isArray(children)) {
const truncatedChildren = [];
for (const child of children) {
if (hasReachedLimit || charCount >= maxCharacters) {
break;
}
const truncatedChild = truncateNode(child);
if (truncatedChild !== null) {
truncatedChildren.push(truncatedChild);
}
}
if (truncatedChildren.length === 0) {
return null;
}
return react_1.default.cloneElement(currentNode, {}, ...truncatedChildren);
}
// Single React element child
const truncatedChild = truncateNode(children);
if (truncatedChild === null) {
return null;
}
return react_1.default.cloneElement(currentNode, {}, truncatedChild);
};
const truncatedResult = truncateNode(normalizedNode);
// Convert array results to proper React elements
const finalResult = Array.isArray(truncatedResult)
? react_1.default.createElement(react_1.default.Fragment, null, ...truncatedResult)
: truncatedResult;
// Add ellipsis if needed
if (shouldAddEllipsis && finalResult !== null) {
const withEllipsis = react_1.default.createElement(react_1.default.Fragment, null, finalResult, constants_1.ELLIPSIS_CHAR);
return { needsTruncation: true, truncatedContent: withEllipsis };
}
return {
needsTruncation: true,
truncatedContent: finalResult,
};
};
exports.truncateReactNodeByCharacters = truncateReactNodeByCharacters;
//# sourceMappingURL=text-overflow-utils.js.map