Skip to content

Commit 4450973

Browse files
committed
move shrinking functionality to own component
1 parent b98a6cb commit 4450973

7 files changed

Lines changed: 106 additions & 43 deletions

File tree

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/) and this p
1010

1111
- `<ChatContent />`
1212
- displays single chat contents in a bubble, including options to add status line and avatar
13+
- `<ChatContentCollapsed />`
14+
- can collapse (and expand) `<ChatContent />` automatically for convenience
1315
- `<ChatField />`
1416
- let the user input texts, calls `onSubmit` handler on enter key and submit button
1517
- `<ChatArea />`

src/components/Chat/ChatContent.tsx

Lines changed: 9 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@ import { TestableComponent } from "../../components/interfaces";
44
import { CLASSPREFIX as eccgui } from "../../configuration/constants";
55

66
import { Markdown, MarkdownProps } from "./../../cmem/markdown/Markdown";
7+
import { ContextMenuProps } from "./../ContextOverlay/ContextMenu";
78
import { DepictionProps } from "./../Depiction/Depiction";
89
import { FlexibleLayoutContainer, FlexibleLayoutItem } from "./../FlexibleLayout";
9-
import { IconButton } from "./../Icon/IconButton";
10+
import { IconButtonProps } from "./../Icon/IconButton";
1011
import { Spacing } from "./../Separation/Spacing";
11-
import { TextReducer } from "./../TextReducer/TextReducer";
1212
import { HtmlContentBlock, OverflowTextProps } from "./../Typography";
1313

1414
export interface ChatContentProps extends React.HTMLAttributes<HTMLDivElement>, TestableComponent {
@@ -44,27 +44,13 @@ export interface ChatContentProps extends React.HTMLAttributes<HTMLDivElement>,
4444
*/
4545
markdownProps?: Omit<MarkdownProps, "children">;
4646
/**
47-
* Callback handler if content should be expanded.
48-
* Button to shrink/expand is displayed, depending on `shrinked` value.
49-
* If this handler is given then the component never will change the `shrinked` state automatically.
47+
* Could be used to add some type of toggle button or to include a context menu.
5048
*/
51-
onToggleSize?: () => void;
52-
/**
53-
* Content should dislayed shrinked.
54-
* Button to expand content is displayed.
55-
* Component can reduce content automatically to one line if `autoShrink` is set to `true`.
56-
* If `onToggleSize` handler is not given then `autoShrink=true` is inferred and size toggling is automatically provided.
57-
*/
58-
shrinked?: boolean;
59-
/**
60-
* Children elements are automatically shrinked to one line.
61-
* If `shrinked` are not given then `shrinked=true` is infered.
62-
*/
63-
autoShrink?: boolean;
49+
actionButton?: React.ReactElement<IconButtonProps> | React.ReactElement<ContextMenuProps>;
6450
}
6551

6652
/**
67-
* Component to display singe chat contents, including avatar and status line.
53+
* Component to display single chat contents, including avatar and status line.
6854
*/
6955
export const ChatContent = ({
7056
className,
@@ -76,23 +62,9 @@ export const ChatContent = ({
7662
alignment = "left",
7763
limitHeight,
7864
markdownProps,
79-
shrinked,
80-
autoShrink,
81-
onToggleSize,
65+
actionButton,
8266
...otherDivProps
8367
}: ChatContentProps) => {
84-
const [displayShrinked, setDispayShrinked] = React.useState<boolean>(
85-
shrinked === true || (autoShrink === true && typeof shrinked === "undefined")
86-
);
87-
88-
const toggleSize = () => {
89-
if (onToggleSize) {
90-
onToggleSize();
91-
} else {
92-
setDispayShrinked(!displayShrinked);
93-
}
94-
};
95-
9668
const content =
9769
markdownProps && typeof children === "string" ? <Markdown {...markdownProps}>{children}</Markdown> : children;
9870

@@ -113,7 +85,7 @@ export const ChatContent = ({
11385
<Spacing size="tiny" />
11486
</HtmlContentBlock>
11587
)}
116-
{displayShrinked && autoShrink ? <TextReducer useOverflowTextWrapper>{content}</TextReducer> : content}
88+
{content}
11789
</div>
11890
);
11991

@@ -142,17 +114,14 @@ export const ChatContent = ({
142114
</FlexibleLayoutItem>
143115
)}
144116
<FlexibleLayoutItem className={`${eccgui}-chat__content-wrapper`}>{chatitem}</FlexibleLayoutItem>
145-
{(displayShrinked || onToggleSize || autoShrink) && (
117+
{actionButton && (
146118
<FlexibleLayoutItem
147119
className={`${eccgui}-chat__content-sizetoggle`}
148120
growFactor={0}
149121
shrinkFactor={0}
150122
style={alignment === "right" ? { order: -1 } : undefined}
151123
>
152-
<IconButton
153-
name={displayShrinked ? "toggler-showmore" : "toggler-showless"}
154-
onClick={() => toggleSize()}
155-
/>
124+
{actionButton}
156125
</FlexibleLayoutItem>
157126
)}
158127
</FlexibleLayoutContainer>
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
import React from "react";
2+
3+
import { Markdown } from "../../cmem/markdown/Markdown";
4+
import { IconButton } from "../Icon/IconButton";
5+
import { TextReducer, TextReducerProps } from "../TextReducer/TextReducer";
6+
7+
import { ChatContentProps } from "./ChatContent";
8+
9+
export interface ChatContentCollapsedProps {
10+
children: React.ReactElement<ChatContentProps>;
11+
/**
12+
* Set this to `false` if the compoment should initally start in an expanded state.
13+
*/
14+
collapsed?: boolean;
15+
/**
16+
* Use this to set extra `TextReducer` properties.
17+
* This is used to create the collapsed variant of the given content.
18+
*/
19+
textReducerProps?: Omit<TextReducerProps, "children">;
20+
/**
21+
* Text for collapse button.
22+
*/
23+
textCollapse?: string;
24+
/**
25+
* Text for expand button.
26+
*/
27+
textExpand?: string;
28+
}
29+
30+
/**
31+
* Adds an auto collapsing feature for convenience to `ChatContent`.
32+
*/
33+
export const ChatContentCollapsed = ({
34+
children,
35+
collapsed = true,
36+
textReducerProps = {},
37+
textCollapse = "Collapse",
38+
textExpand = "Expand",
39+
}: ChatContentCollapsedProps) => {
40+
const [displayCollapsed, setDispayCollapsed] = React.useState<boolean>(collapsed);
41+
42+
const childrenAsTextline = (
43+
<TextReducer useOverflowTextWrapper {...textReducerProps}>
44+
{typeof children.props.children === "string" ? (
45+
<Markdown>{children.props.children}</Markdown>
46+
) : (
47+
children.props.children
48+
)}
49+
</TextReducer>
50+
);
51+
52+
return React.cloneElement(children, {
53+
children: displayCollapsed ? childrenAsTextline : children.props.children,
54+
actionButton: (
55+
<IconButton
56+
text={displayCollapsed ? textExpand : textCollapse}
57+
name={displayCollapsed ? "toggler-showmore" : "toggler-showless"}
58+
onClick={() => setDispayCollapsed(!displayCollapsed)}
59+
/>
60+
),
61+
});
62+
};
63+
64+
export default ChatContentCollapsed;

src/components/Chat/index.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
11
export * from "./ChatArea";
22
export * from "./ChatContent";
3+
export * from "./ChatContentCollapsed";
34
export * from "./ChatField";

src/components/Chat/stories/ChatArea.stories.tsx

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import React from "react";
22
import { Meta, StoryFn } from "@storybook/react";
33

4-
import { ChatArea, ChatContent, ChatField } from "../../../index";
4+
import { ChatArea, ChatContent, ChatContentCollapsed, ChatField } from "../../../index";
55

66
import { Default as ShortChatBubble, LongChatBubble } from "./ChatContent.stories";
77
import { Default as ChatFieldExample } from "./ChatField.stories";
@@ -26,7 +26,9 @@ Default.args = {
2626
<ChatContent {...ShortChatBubble.args} alignment="right" indentationSize="medium" />,
2727
<ChatContent {...ShortChatBubble.args} avatar={undefined} displayType="free" />,
2828
<ChatContent {...ShortChatBubble.args} alignment="right" indentationSize="medium" />,
29-
<ChatContent {...LongChatBubble.args} autoShrink />,
29+
<ChatContentCollapsed>
30+
<ChatContent {...LongChatBubble.args} />
31+
</ChatContentCollapsed>,
3032
<ChatContent {...ShortChatBubble.args} alignment="right" indentationSize="medium" />,
3133
<ChatContent {...ShortChatBubble.args} />,
3234
],

src/components/Chat/stories/ChatContent.stories.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,12 +45,13 @@ Default.args = {
4545
<strong>Username</strong> 25 minutes ago
4646
</OverflowText>
4747
),
48-
onToggleSize: undefined,
4948
};
5049

5150
export const LongChatBubble = TemplateFull.bind({});
5251
LongChatBubble.args = {
5352
...Default.args,
53+
avatar: undefined,
54+
displayType: "simple",
5455
children: (
5556
<HtmlContentBlock>
5657
<LoremIpsum p={10} avgSentencesPerParagraph={10} random={false} />
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
import React from "react";
2+
import { Meta, StoryFn } from "@storybook/react";
3+
4+
import { ChatContent, ChatContentCollapsed } from "../../../index";
5+
6+
import { LongChatBubble } from "./ChatContent.stories";
7+
8+
export default {
9+
title: "Components/Chat/ChatContentCollapsed",
10+
component: ChatContentCollapsed,
11+
argTypes: {},
12+
} as Meta<typeof ChatContentCollapsed>;
13+
14+
let update = 0;
15+
const TemplateFull: StoryFn<typeof ChatContentCollapsed> = (args) => (
16+
<div key={update++}>
17+
<ChatContentCollapsed {...args} />
18+
</div>
19+
);
20+
21+
export const Default = TemplateFull.bind({});
22+
Default.args = {
23+
children: <ChatContent {...LongChatBubble.args} />,
24+
};

0 commit comments

Comments
 (0)