New Case Study:See how Anthropic automated 95% of dependency reviews with Socket.Learn More
Socket
Sign inDemoInstall
Socket

use-clamp-text

Package Overview
Dependencies
Maintainers
1
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

use-clamp-text - npm Package Compare versions

Comparing version 1.0.1 to 1.1.0

5

CHANGELOG.md

@@ -0,1 +1,6 @@

# 1.1.0
- Support for custom ellipsis
- Allow more flexible usage through `charWidth`
# 1.0.1

@@ -2,0 +7,0 @@

12

esm/index.d.ts
/// <reference types="react" />
export declare function useClampText({ text, ellipsis, lines, expanded, debounceTime, }: {
text: any;
ellipsis?: string;
interface ClampTextConfig {
text: string;
ellipsis: string | number;
lines?: number;
expanded?: boolean;
debounceTime?: number;
}): readonly [import("react").MutableRefObject<HTMLElement>, {
charWidth?: number;
}
export declare function useClampText({ text, ellipsis, lines, expanded, debounceTime, charWidth, }: ClampTextConfig): readonly [import("react").MutableRefObject<HTMLElement>, {
readonly noClamp: boolean;
readonly clampedText: string;
readonly key: string;
}];
export {};
import { useRef, useState, useCallback } from 'react';
import { useDebounce, useOnWindowResize, useDidMount, useDidUpdate, } from 'rooks';
var defaultEllipsis = '...';
var key = 0;
var getNewKey = function () { return "__clamp_text_key__".concat(key++); };
export function useClampText(_a) {
var text = _a.text, _b = _a.ellipsis, ellipsis = _b === void 0 ? defaultEllipsis : _b, _c = _a.lines, lines = _c === void 0 ? 3 : _c, _d = _a.expanded, expanded = _d === void 0 ? false : _d, _e = _a.debounceTime, debounceTime = _e === void 0 ? 300 : _e;
var _f = useState(function () { return ({
var text = _a.text, _b = _a.ellipsis, ellipsis = _b === void 0 ? defaultEllipsis : _b, _c = _a.lines, lines = _c === void 0 ? 3 : _c, _d = _a.expanded, expanded = _d === void 0 ? false : _d, _e = _a.debounceTime, debounceTime = _e === void 0 ? 300 : _e, _f = _a.charWidth, charWidth = _f === void 0 ? 1.2 : _f;
var _g = useState(function () { return ({
noClamp: false,
clampedText: '.',
}); }), _g = _f[0], noClamp = _g.noClamp, clampedText = _g.clampedText, setState = _f[1];
key: getNewKey(),
}); }), _h = _g[0], noClamp = _h.noClamp, clampedText = _h.clampedText, key = _h.key, setState = _g[1];
var nodeRef = useRef();
var lineHeightRef = useRef(0);
var clampLines = useCallback(function (_a) {
var lineHeight = _a.lineHeight, originalText = _a.originalText, expanded = _a.expanded, ellipsis = _a.ellipsis, lines = _a.lines;
var lineHeight = _a.lineHeight, originalText = _a.originalText, expanded = _a.expanded, ellipsis = _a.ellipsis, lines = _a.lines, charWidth = _a.charWidth;
var node = nodeRef.current;

@@ -22,2 +25,3 @@ if (!node) {

clampedText: originalText,
key: getNewKey(),
});

@@ -27,5 +31,12 @@ return;

var maxHeight = lineHeight * lines + 1;
var ellipsisLength = defaultEllipsis
? 5
: Math.ceil(ellipsis.length * 1.2);
var ellipsisLength = 0;
if (typeof ellipsis === 'string') {
ellipsisLength =
ellipsis === defaultEllipsis
? 5
: Math.ceil(ellipsis.length * charWidth);
}
else if (typeof ellipsis === 'number') {
ellipsisLength = Math.ceil(ellipsis * charWidth);
}
var start = 0;

@@ -38,3 +49,4 @@ var middle = 0;

function moveMarkers() {
var clientHeight = node.clientHeight;
var _a;
var clientHeight = (_a = node === null || node === void 0 ? void 0 : node.clientHeight) !== null && _a !== void 0 ? _a : 1;
if (clientHeight <= maxHeight) {

@@ -51,3 +63,7 @@ start = middle + 1;

if (middle === originalText.length) {
setState({ clampedText: originalText, noClamp: true });
setState({
clampedText: originalText,
noClamp: true,
key: getNewKey(),
});
return;

@@ -58,3 +74,3 @@ }

var clampedText = originalText.slice(0, Math.max(middle - ellipsisLength, 0)).trim() +
ellipsis;
(typeof ellipsis === 'string' ? ellipsis : '');
node.innerText = clampedText;

@@ -64,2 +80,3 @@ setState({

clampedText: clampedText,
key: getNewKey(),
});

@@ -75,8 +92,9 @@ }, []);

lines: lines,
charWidth: charWidth,
});
});
useDidMount(function () {
var _a;
var _a, _b;
if (text && !lineHeightRef.current) {
var lineHeight = ((_a = nodeRef.current) === null || _a === void 0 ? void 0 : _a.clientHeight) + 1;
var lineHeight = ((_b = (_a = nodeRef.current) === null || _a === void 0 ? void 0 : _a.clientHeight) !== null && _b !== void 0 ? _b : 1) + 1;
lineHeightRef.current = lineHeight;

@@ -89,2 +107,3 @@ clampLines({

lines: lines,
charWidth: charWidth,
});

@@ -100,4 +119,5 @@ }

lines: lines,
charWidth: charWidth,
});
}, [expanded, text]);
}, [expanded, text, charWidth]);
return [

@@ -108,4 +128,5 @@ nodeRef,

clampedText: clampedText,
key: key,
},
];
}
/// <reference types="react" />
export declare function useClampText({ text, ellipsis, lines, expanded, debounceTime, }: {
text: any;
ellipsis?: string;
interface ClampTextConfig {
text: string;
ellipsis: string | number;
lines?: number;
expanded?: boolean;
debounceTime?: number;
}): readonly [import("react").MutableRefObject<HTMLElement>, {
charWidth?: number;
}
export declare function useClampText({ text, ellipsis, lines, expanded, debounceTime, charWidth, }: ClampTextConfig): readonly [import("react").MutableRefObject<HTMLElement>, {
readonly noClamp: boolean;
readonly clampedText: string;
readonly key: string;
}];
export {};

@@ -7,12 +7,15 @@ "use strict";

var defaultEllipsis = '...';
var key = 0;
var getNewKey = function () { return "__clamp_text_key__".concat(key++); };
function useClampText(_a) {
var text = _a.text, _b = _a.ellipsis, ellipsis = _b === void 0 ? defaultEllipsis : _b, _c = _a.lines, lines = _c === void 0 ? 3 : _c, _d = _a.expanded, expanded = _d === void 0 ? false : _d, _e = _a.debounceTime, debounceTime = _e === void 0 ? 300 : _e;
var _f = (0, react_1.useState)(function () { return ({
var text = _a.text, _b = _a.ellipsis, ellipsis = _b === void 0 ? defaultEllipsis : _b, _c = _a.lines, lines = _c === void 0 ? 3 : _c, _d = _a.expanded, expanded = _d === void 0 ? false : _d, _e = _a.debounceTime, debounceTime = _e === void 0 ? 300 : _e, _f = _a.charWidth, charWidth = _f === void 0 ? 1.2 : _f;
var _g = (0, react_1.useState)(function () { return ({
noClamp: false,
clampedText: '.',
}); }), _g = _f[0], noClamp = _g.noClamp, clampedText = _g.clampedText, setState = _f[1];
key: getNewKey(),
}); }), _h = _g[0], noClamp = _h.noClamp, clampedText = _h.clampedText, key = _h.key, setState = _g[1];
var nodeRef = (0, react_1.useRef)();
var lineHeightRef = (0, react_1.useRef)(0);
var clampLines = (0, react_1.useCallback)(function (_a) {
var lineHeight = _a.lineHeight, originalText = _a.originalText, expanded = _a.expanded, ellipsis = _a.ellipsis, lines = _a.lines;
var lineHeight = _a.lineHeight, originalText = _a.originalText, expanded = _a.expanded, ellipsis = _a.ellipsis, lines = _a.lines, charWidth = _a.charWidth;
var node = nodeRef.current;

@@ -26,2 +29,3 @@ if (!node) {

clampedText: originalText,
key: getNewKey(),
});

@@ -31,5 +35,12 @@ return;

var maxHeight = lineHeight * lines + 1;
var ellipsisLength = defaultEllipsis
? 5
: Math.ceil(ellipsis.length * 1.2);
var ellipsisLength = 0;
if (typeof ellipsis === 'string') {
ellipsisLength =
ellipsis === defaultEllipsis
? 5
: Math.ceil(ellipsis.length * charWidth);
}
else if (typeof ellipsis === 'number') {
ellipsisLength = Math.ceil(ellipsis * charWidth);
}
var start = 0;

@@ -42,3 +53,4 @@ var middle = 0;

function moveMarkers() {
var clientHeight = node.clientHeight;
var _a;
var clientHeight = (_a = node === null || node === void 0 ? void 0 : node.clientHeight) !== null && _a !== void 0 ? _a : 1;
if (clientHeight <= maxHeight) {

@@ -55,3 +67,7 @@ start = middle + 1;

if (middle === originalText.length) {
setState({ clampedText: originalText, noClamp: true });
setState({
clampedText: originalText,
noClamp: true,
key: getNewKey(),
});
return;

@@ -62,3 +78,3 @@ }

var clampedText = originalText.slice(0, Math.max(middle - ellipsisLength, 0)).trim() +
ellipsis;
(typeof ellipsis === 'string' ? ellipsis : '');
node.innerText = clampedText;

@@ -68,2 +84,3 @@ setState({

clampedText: clampedText,
key: getNewKey(),
});

@@ -79,8 +96,9 @@ }, []);

lines: lines,
charWidth: charWidth,
});
});
(0, rooks_1.useDidMount)(function () {
var _a;
var _a, _b;
if (text && !lineHeightRef.current) {
var lineHeight = ((_a = nodeRef.current) === null || _a === void 0 ? void 0 : _a.clientHeight) + 1;
var lineHeight = ((_b = (_a = nodeRef.current) === null || _a === void 0 ? void 0 : _a.clientHeight) !== null && _b !== void 0 ? _b : 1) + 1;
lineHeightRef.current = lineHeight;

@@ -93,2 +111,3 @@ clampLines({

lines: lines,
charWidth: charWidth,
});

@@ -104,4 +123,5 @@ }

lines: lines,
charWidth: charWidth,
});
}, [expanded, text]);
}, [expanded, text, charWidth]);
return [

@@ -112,2 +132,3 @@ nodeRef,

clampedText: clampedText,
key: key,
},

@@ -114,0 +135,0 @@ ];

{
"name": "use-clamp-text",
"description": "react hook to clamp multiline text to a given height in a responsive way (in < 2.5kb)",
"version": "1.0.1",
"version": "1.1.0",
"main": "lib/index.js",

@@ -70,5 +70,5 @@ "module": "esm/index.js",

"path": "esm/index.js",
"limit": "2.5 KB"
"limit": "3 KB"
}
]
}

@@ -48,10 +48,28 @@ # use-clamp-text

| prop | type | required | default | description |
| -------- | --------- | -------- | ------- | -------------------------------------------------------- |
| text | `string` | `true` | | Text you wish to clamp |
| ellipsis | `string` | `false` | `'…'` | String displayed after the clamped `text` |
| expanded | `boolean` | `false` | `false` | To control whether the string should be truncated or not |
| lines | `number` | `false` | `3` | Number of visible lines |
| debounce | `number` | `false` | `300` | Time in milliseconds used for debounce |
### Arguments
The hook accepts only a single object argument is accepted with the following properties:
| property | type | required | default | description |
| --------- | ------------------ | -------- | ------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| text | `string` | `true` | | Text you wish to clamp |
| ellipsis | `string \| number` | `false` | `'…'` | String displayed after the clamped text or number of characters to be trimmed off the string (useful for adding inline custom ellipsis like a `<a>` or `<button>`) |
| expanded | `boolean` | `false` | `false` | To control whether the string should be truncated or not |
| lines | `number` | `false` | `3` | Number of visible lines |
| debounce | `number` | `false` | `300` | Time in milliseconds used for debounce |
| charWidth | `number` | `false` | `1.2` | Character width to be assumed for calculating clamped string length (an average depending on your font size should work well enough) |
### Return
The hook returns a tuple -
- [0] (first element) - `React.MutableRefObject<HTMLElement | null>` - a ref to attach to the element where the clamped text will be rendered
- [1] (second element) - `Object` - The properties of the object are documented in the table below
| property | type | description |
| ----------- | --------- | ---------------------------------------------------------------------------------------------------------------------- |
| noClamp | `boolean` | Whether the text is clamped or not. Will return true if not clamped |
| clampedText | `string` | The string to be rendered |
| key | `string` | A key to attach to the element that contains the string to be rendered (only needed when using custom inline ellipsis) |
## Prior Art (packages I ~~copied~~ adapted code from)

@@ -58,0 +76,0 @@

@@ -11,2 +11,23 @@ import { useRef, useState, useCallback } from 'react';

let key = 0;
const getNewKey = () => `__clamp_text_key__${key++}`;
interface ClampTextConfig {
text: string;
ellipsis: string | number;
lines?: number;
expanded?: boolean;
debounceTime?: number;
charWidth?: number;
}
interface ClampLineParams {
lineHeight: number;
originalText: string;
expanded: boolean;
ellipsis?: string | number;
lines: number;
charWidth: number;
}
export function useClampText({

@@ -18,6 +39,8 @@ text,

debounceTime = 300,
}) {
const [{ noClamp, clampedText }, setState] = useState(() => ({
charWidth = 1.2,
}: ClampTextConfig) {
const [{ noClamp, clampedText, key }, setState] = useState(() => ({
noClamp: false,
clampedText: '.',
key: getNewKey(),
}));

@@ -29,3 +52,10 @@

const clampLines = useCallback(
({ lineHeight, originalText, expanded, ellipsis, lines }) => {
({
lineHeight,
originalText,
expanded,
ellipsis,
lines,
charWidth,
}: ClampLineParams) => {
const node = nodeRef.current;

@@ -39,2 +69,3 @@ if (!node) {

clampedText: originalText,
key: getNewKey(),
});

@@ -45,5 +76,11 @@ return;

const maxHeight = lineHeight * lines + 1;
const ellipsisLength = defaultEllipsis
? 5
: Math.ceil(ellipsis.length * 1.2);
let ellipsisLength = 0;
if (typeof ellipsis === 'string') {
ellipsisLength =
ellipsis === defaultEllipsis
? 5
: Math.ceil(ellipsis.length * charWidth);
} else if (typeof ellipsis === 'number') {
ellipsisLength = Math.ceil(ellipsis * charWidth);
}

@@ -59,3 +96,3 @@ let start = 0;

function moveMarkers() {
const clientHeight = node.clientHeight;
const clientHeight = node?.clientHeight ?? 1;
if (clientHeight <= maxHeight) {

@@ -73,3 +110,7 @@ start = middle + 1;

if (middle === originalText.length) {
setState({ clampedText: originalText, noClamp: true });
setState({
clampedText: originalText,
noClamp: true,
key: getNewKey(),
});
return;

@@ -83,3 +124,3 @@ }

originalText.slice(0, Math.max(middle - ellipsisLength, 0)).trim() +
ellipsis;
(typeof ellipsis === 'string' ? ellipsis : '');

@@ -90,2 +131,3 @@ node.innerText = clampedText;

clampedText,
key: getNewKey(),
});

@@ -103,2 +145,3 @@ },

lines,
charWidth,
})

@@ -109,3 +152,3 @@ );

if (text && !lineHeightRef.current) {
const lineHeight = nodeRef.current?.clientHeight + 1;
const lineHeight = (nodeRef.current?.clientHeight ?? 1) + 1;
lineHeightRef.current = lineHeight;

@@ -118,2 +161,3 @@ clampLines({

lines,
charWidth,
});

@@ -129,4 +173,5 @@ }

lines,
charWidth,
});
}, [expanded, text]);
}, [expanded, text, charWidth]);

@@ -138,4 +183,5 @@ return [

clampedText,
key,
},
] as const;
}
SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc