Skip to content

Commit 1077361

Browse files
committed
move autoshrink element creation from chat into own reusable component
1 parent d434ca4 commit 1077361

5 files changed

Lines changed: 90 additions & 39 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
1414
- let the user input texts, calls `onSubmit` handler on enter key and submit button
1515
- `<ChatArea />`
1616
- combine a list of chat contents and user input box
17+
- `<ContentShrinker />`
18+
- displays all HTML content as only 1 ellipsed text line
1719

1820
## [24.4.1] - 2025-08-25
1921

src/components/Chat/ChatContent.tsx

Lines changed: 3 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,15 @@
11
import React from "react";
2-
import { renderToString } from "react-dom/server";
3-
import * as ReactIs from "react-is";
42

53
import { TestableComponent } from "../../components/interfaces";
64
import { CLASSPREFIX as eccgui } from "../../configuration/constants";
75

86
import { Markdown, MarkdownProps } from "./../../cmem/markdown/Markdown";
7+
import { ContentShrinker } from "./../ContentShrinker/ContentShrinker";
98
import { DepictionProps } from "./../Depiction/Depiction";
109
import { FlexibleLayoutContainer, FlexibleLayoutItem } from "./../FlexibleLayout";
1110
import { IconButton } from "./../Icon/IconButton";
1211
import { Spacing } from "./../Separation/Spacing";
13-
import { HtmlContentBlock, OverflowText, OverflowTextProps } from "./../Typography";
12+
import { HtmlContentBlock, OverflowTextProps } from "./../Typography";
1413

1514
export interface ChatContentProps extends React.HTMLAttributes<HTMLDivElement>, TestableComponent {
1615
/**
@@ -97,35 +96,6 @@ export const ChatContent = ({
9796
const content =
9897
markdownProps && typeof children === "string" ? <Markdown {...markdownProps}>{children}</Markdown> : children;
9998

100-
const onlyText = (children: React.ReactNode | React.ReactNode[]): string => {
101-
if (children instanceof Array) {
102-
return children
103-
.map((child: React.ReactNode) => {
104-
return onlyText(child);
105-
})
106-
.join(" ");
107-
}
108-
109-
return React.Children.toArray(children)
110-
.map((child) => {
111-
if (ReactIs.isFragment(child)) {
112-
return onlyText(child.props?.children);
113-
}
114-
if (typeof child === "string") {
115-
return child;
116-
}
117-
if (typeof child === "number") {
118-
return child.toString();
119-
}
120-
if (ReactIs.isElement(child)) {
121-
// for some reasons `renderToString` returns empty string if not wrappe in a `span`
122-
return renderToString(<span>{child}</span>);
123-
}
124-
return "";
125-
})
126-
.join(" ");
127-
};
128-
12999
const chatitem = (
130100
<div
131101
className={
@@ -143,13 +113,7 @@ export const ChatContent = ({
143113
<Spacing size="tiny" />
144114
</HtmlContentBlock>
145115
)}
146-
{displayShrinked && autoShrink ? (
147-
<OverflowText passDown>
148-
<Markdown removeMarkup>{onlyText(content)}</Markdown>
149-
</OverflowText>
150-
) : (
151-
content
152-
)}
116+
{displayShrinked && autoShrink ? <ContentShrinker>{content}</ContentShrinker> : content}
153117
</div>
154118
);
155119

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
import React from "react";
2+
import { LoremIpsum } from "react-lorem-ipsum";
3+
import { Meta, StoryFn } from "@storybook/react";
4+
5+
import { ContentShrinker, HtmlContentBlock } from "../../../index";
6+
7+
export default {
8+
title: "Components/ContentShrinker",
9+
component: ContentShrinker,
10+
argTypes: {},
11+
} as Meta<typeof ContentShrinker>;
12+
13+
const TemplateFull: StoryFn<typeof ContentShrinker> = (args) => <ContentShrinker {...args} />;
14+
15+
export const Default = TemplateFull.bind({});
16+
Default.args = {
17+
children: (
18+
<>
19+
simple text child
20+
<HtmlContentBlock>
21+
<LoremIpsum p={10} avgSentencesPerParagraph={10} random={false} />
22+
</HtmlContentBlock>
23+
</>
24+
),
25+
};
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import React from "react";
2+
import { renderToString } from "react-dom/server";
3+
import * as ReactIs from "react-is";
4+
5+
import { CLASSPREFIX as eccgui } from "../../configuration/constants";
6+
7+
import { Markdown } from "./../../cmem/markdown/Markdown";
8+
import { OverflowText, OverflowTextProps } from "./../Typography";
9+
10+
export type ContentShrinkerProps = Omit<OverflowTextProps, "passDown" | "useHtmlElement">;
11+
12+
/**
13+
* Component to shrink HTML markup content to 1 single text line.
14+
* Display is based on `OverflowText`.
15+
*/
16+
export const ContentShrinker = ({ className, children, ...otherOverflowProps }: ContentShrinkerProps) => {
17+
const onlyText = (children: React.ReactNode | React.ReactNode[]): string => {
18+
if (children instanceof Array) {
19+
return children
20+
.map((child: React.ReactNode) => {
21+
return onlyText(child);
22+
})
23+
.join(" ");
24+
}
25+
26+
return React.Children.toArray(children)
27+
.map((child) => {
28+
if (ReactIs.isFragment(child)) {
29+
return onlyText(child.props?.children);
30+
}
31+
if (typeof child === "string") {
32+
return child;
33+
}
34+
if (typeof child === "number") {
35+
return child.toString();
36+
}
37+
if (ReactIs.isElement(child)) {
38+
// for some reasons `renderToString` returns empty string if not wrappe in a `span`
39+
return renderToString(<span>{child}</span>);
40+
}
41+
return "";
42+
})
43+
.join(" ");
44+
};
45+
46+
return (
47+
<OverflowText
48+
className={`${eccgui}-contentshrinker` + (className ? ` ${className}` : "")}
49+
passDown
50+
{...otherOverflowProps}
51+
>
52+
<Markdown removeMarkup inheritBlock>
53+
{onlyText(children)}
54+
</Markdown>
55+
</OverflowText>
56+
);
57+
};
58+
59+
export default ContentShrinker;

src/components/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ export * from "./Button/Button";
1010
export * from "./Card";
1111
export * from "./Chat";
1212
export * from "./Checkbox/Checkbox";
13+
export * from "./ContentShrinker/ContentShrinker";
1314
export * from "./ContextOverlay";
1415
export * from "./Depiction/Depiction";
1516
export * from "./Dialog";

0 commit comments

Comments
 (0)