diff --git a/.stylelintrc.json b/.stylelintrc.json
index 370aefe972..fd24feef96 100644
--- a/.stylelintrc.json
+++ b/.stylelintrc.json
@@ -11,7 +11,7 @@
"ignoreProperties": ["animation", "filter"]
}],
"value-no-vendor-prefix": [true, {
- "ignoreValues": ["fill-available"]
+ "ignoreValues": ["fill-available", "box"]
}],
"function-no-unknown": null,
"number-leading-zero": "never",
diff --git a/src/Truncate/README.md b/src/Truncate/README.md
index fd847ddd84..3e2c5147f4 100644
--- a/src/Truncate/README.md
+++ b/src/Truncate/README.md
@@ -5,11 +5,9 @@ components:
- Truncate
categories:
- Content
-status: 'Deprecate Soon'
+status: 'New'
designStatus: 'Done'
devStatus: 'Done'
-notes: |
- Plan to replace with native css implementation as per https://github.com/openedx/paragon/issues/3311
---
A Truncate component can help you crop multiline text. There will be three dots at the end of the text.
@@ -17,34 +15,34 @@ A Truncate component can help you crop multiline text. There will be three dots
## Basic Usage
```jsx live
-
+
Learners, course teams, researchers, developers: the edX community includes groups with a range of reasons
for using the platform and objectives to accomplish. To help members of each group learn about what edX
offers, reach goals, and solve problems, edX provides a variety of information resources.
Learners, course teams, researchers, developers: the edX community includes groups with a range of reasons
for using the platform and objectives to accomplish. To help members of each group learn about what edX
offers, reach goals, and solve problems, edX provides a variety of information resources.
-
+
```
### With the custom ellipsis
```jsx live
-
+
Learners, course teams, researchers, developers: the edX community includes groups with a range of reasons
for using the platform and objectives to accomplish. To help members of each group learn about what edX
offers, reach goals, and solve problems, edX provides a variety of information resources.
-
+
```
### With the onTruncate
```jsx live
- console.log('onTruncate')}>
+
Learners, course teams, researchers, developers: the edX community includes groups with a range of reasons
for using the platform and objectives to accomplish. To help members of each group learn about what edX
offers, reach goals, and solve problems, edX provides a variety of information resources.
-
+
```
### Example usage in Card
@@ -61,22 +59,22 @@ A Truncate component can help you crop multiline text. There will be three dots
/>
+
Using Enhanced Capabilities In Your Course
- }
+ }
/>
-
+
Learners, course teams, researchers, developers: the edX community includes groups with a range of reasons
for using the platform and objectives to accomplish. To help members of each group learn about what edX
offers, reach goals, and solve problems, edX provides a variety of information resources.
-
+
+
Using Enhanced Capabilities In Your Course
- }
+ }
>
@@ -87,10 +85,12 @@ A Truncate component can help you crop multiline text. There will be three dots
### HTML markdown support
-**Note**: `Truncate` supports only plain `HTML` children and not `jsx`.
+**Note**: `Truncate` supports only plain `HTML` children and not `jsx`.
+
+QUESTION FOR KEVIN: Would this fail screen readers anyway?
```jsx live
-
+Learners, course teams, researchers, developers: the edX community includes groups with a range of reasons for using the platform and objectives to accomplish.
-
+
```
diff --git a/src/Truncate/Truncate.test.jsx b/src/Truncate/Truncate.test.jsx
index d1cc120c85..372b6a9ef4 100644
--- a/src/Truncate/Truncate.test.jsx
+++ b/src/Truncate/Truncate.test.jsx
@@ -1,27 +1,65 @@
import React from 'react';
+import '@testing-library/jest-dom';
import { render, screen } from '@testing-library/react';
-import Truncate from '.';
-
-describe('', () => {
- render(
-
- Learners, course teams, researchers, developers.
- ,
- );
- it('render with className', () => {
- const element = screen.getByText(/Learners, course teams, researchers, developers./i);
- expect(element).toBeTruthy();
- expect(element.className).toContain('pgn__truncate');
- expect(element.getAttribute('aria-label')).toBe('Learners, course teams, researchers, developers.');
- expect(element.getAttribute('title')).toBe('Learners, course teams, researchers, developers.');
+import Truncate from './Truncate';
+import { assembleStringFromChildrenArray } from './utils';
+
+jest.mock('./utils', () => ({
+ assembleStringFromChildrenArray: jest.fn(
+ (children) => `Assembled text from ${children.length} elements`,
+ ),
+}));
+
+describe('Truncate Component', () => {
+ beforeEach(() => {
+ jest.clearAllMocks();
+ });
+
+ it('should render with default line clamp of 1', () => {
+ const testContent = 'This is a test string.';
+ render({testContent});
+
+ const element = screen.getByTestId('truncate-element');
+ expect(element.style.getPropertyValue('--truncate-prop-lines')).toBe('1');
+
+ expect(element).toHaveAttribute('title', testContent);
+ expect(element).toHaveAttribute('aria-label', testContent);
});
- it('render with onTruncate', () => {
- const mockFn = jest.fn();
- render(
-
- Learners, course teams, researchers, developers.
- ,
- );
- expect(mockFn).toHaveBeenCalledTimes(2);
+
+ it('should render with custom line clamp value', () => {
+ const testContent = 'Another long string here.';
+ const customLines = 5;
+ render({testContent});
+
+ const element = screen.getByTestId('truncate-element');
+
+ expect(element.style.getPropertyValue('--truncate-prop-lines')).toBe(String(customLines));
+
+ expect(element).toHaveAttribute('title', testContent);
+ expect(element).toHaveAttribute('aria-label', testContent);
+ });
+
+ it('should not call assembleStringFromChildrenArray if children is a string', () => {
+ const testContent = 'Simple string content.';
+ render({testContent});
+
+ expect(assembleStringFromChildrenArray).not.toHaveBeenCalled();
+ });
+
+ it('should call assembleStringFromChildrenArray if children is complex', () => {
+ // Complex children structure (an array of elements)
+ const complexChildren = [
+ Part A,
+ Part B,
+ 'Part C',
+ ];
+
+ (assembleStringFromChildrenArray).mockReturnValue('This is the mocked full string.');
+
+ render({complexChildren});
+
+ expect(assembleStringFromChildrenArray).toHaveBeenCalledTimes(1);
+
+ expect(assembleStringFromChildrenArray).toHaveBeenCalledWith(complexChildren);
});
});
diff --git a/src/Truncate/Truncate.tsx b/src/Truncate/Truncate.tsx
new file mode 100644
index 0000000000..fac0155dc0
--- /dev/null
+++ b/src/Truncate/Truncate.tsx
@@ -0,0 +1,33 @@
+import React from 'react';
+import { assembleStringFromChildrenArray } from './utils';
+
+interface TruncateProps {
+ /** The expected text to which the ellipsis would be applied. */
+ children: React.ReactNode;
+ /** The number of lines the text to be truncated to. */
+ lines?: number;
+}
+
+function Truncate({ children, lines = 1 }: TruncateProps) {
+ let initialText: string = '';
+ if (Array.isArray(children)) {
+ const { result } = assembleStringFromChildrenArray(children);
+ initialText = result;
+ } else {
+ initialText = String(children);
+ }
+
+ return (
+