Skip to content

Commit

Permalink
feat(Message): add message component (#1004)
Browse files Browse the repository at this point in the history
  • Loading branch information
Lisa18289 authored Nov 28, 2024
1 parent 3b4d762 commit dcecea5
Show file tree
Hide file tree
Showing 14 changed files with 384 additions and 4 deletions.
5 changes: 5 additions & 0 deletions packages/components/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -242,6 +242,11 @@
"types": "./dist/js/types/components/MenuItem/index.d.ts",
"import": "./dist/js/MenuItem.js"
},
"./Message/styles.css": "./dist/css/Message.css",
"./Message": {
"types": "./dist/js/types/components/Message/index.d.ts",
"import": "./dist/js/Message.js"
},
"./Modal/styles.css": "./dist/css/Modal.css",
"./Modal": {
"types": "./dist/js/types/components/Modal/index.d.ts",
Expand Down
13 changes: 9 additions & 4 deletions packages/components/src/components/Align/Align.tsx
Original file line number Diff line number Diff line change
@@ -1,14 +1,19 @@
import type { FC, PropsWithChildren } from "react";
import type { PropsWithChildren } from "react";
import React from "react";
import styles from "./Align.module.scss";
import clsx from "clsx";
import type { PropsContext } from "@/lib/propsContext";
import PropsContextProvider from "@/lib/propsContext/PropsContextProvider";
import type { PropsWithClassName } from "@/lib/types/props";
import type { FlowComponentProps } from "@/lib/componentFactory/flowComponent";
import { flowComponent } from "@/lib/componentFactory/flowComponent";

export interface AlignProps extends PropsWithChildren, PropsWithClassName {}
export interface AlignProps
extends PropsWithChildren,
PropsWithClassName,
FlowComponentProps {}

export const Align: FC<AlignProps> = (props) => {
export const Align = flowComponent("Align", (props) => {
const { children, className } = props;

const rootClassName = clsx(styles.align, className);
Expand All @@ -23,6 +28,6 @@ export const Align: FC<AlignProps> = (props) => {
<div className={rootClassName}>{children}</div>
</PropsContextProvider>
);
};
});

export default Align;
56 changes: 56 additions & 0 deletions packages/components/src/components/Message/Message.module.scss
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
.message {
display: flex;
flex-direction: column;
row-gap: var(--message--spacing-y);
width: max-content;
max-width: 100%;

.content {
grid-area: content;
border-radius: var(--message--corner-radius);
padding-inline: var(--message--padding-x);
padding-block: var(--message--padding-y);
background-color: var(--message--background-color-sender);
}

&.responder .content {
background-color: var(--message--background-color-responder);
}

.header {
display: flex;
column-gap: var(--message--spacing-x);
row-gap: var(--message--spacing-y);
align-items: center;
flex-wrap: wrap;
font-size: var(--font-size-text--s);

.user {
order: 1;
flex-grow: 1;
}

.date {
font-size: var(--font-size-text--s);
order: 2;
}

.action {
order: 3;
}
}

&.right {
.header {
flex-direction: row-reverse;

.user {
flex-direction: row-reverse;

:global(.flow--text) {
text-align: end;
}
}
}
}
}
59 changes: 59 additions & 0 deletions packages/components/src/components/Message/Message.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import type { FC, PropsWithChildren } from "react";
import React from "react";
import clsx from "clsx";
import styles from "./Message.module.scss";
import type { PropsWithClassName } from "@/lib/types/props";
import type { PropsContext } from "@/lib/propsContext";
import { IconContextMenu } from "@/components/Icon/components/icons";
import PropsContextProvider from "@/lib/propsContext/PropsContextProvider";

export interface MessageProps extends PropsWithChildren, PropsWithClassName {
/** @default "sender" */
type?: "responder" | "sender";
orientation?: "left" | "right";
}

export const Message: FC<MessageProps> = (props) => {
const { type = "sender", children, className, orientation = "left" } = props;

const rootClassName = clsx(
styles.message,
styles[type],
styles[orientation],
className,
);

const propsContext: PropsContext = {
Content: { className: styles.content },
Header: {
className: styles.header,
Button: {
className: styles.action,
size: "s",
variant: "plain",
color: "secondary",
},
ContextMenuTrigger: {
Button: {
className: styles.action,
size: "s",
variant: "plain",
color: "secondary",
children: <IconContextMenu />,
},
},
Text: { className: styles.date },
Align: {
className: styles.user,
},
},
};

return (
<PropsContextProvider props={propsContext}>
<article className={rootClassName}>{children}</article>
</PropsContextProvider>
);
};

export default Message;
4 changes: 4 additions & 0 deletions packages/components/src/components/Message/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
import { Message } from "./Message";

export { type MessageProps, Message } from "./Message";
export default Message;
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
import type { Meta, StoryObj } from "@storybook/react";
import React from "react";
import { Message } from "@/components/Message";
import { Header } from "@/components/Header";
import { ContextMenu, ContextMenuTrigger } from "@/components/ContextMenu";
import { Button } from "@/components/Button";
import MenuItem from "@/components/MenuItem";
import { Align } from "@/components/Align";
import { Avatar } from "@/components/Avatar";
import { Initials } from "@/components/Initials";
import { Content } from "@/components/Content";
import { Text } from "@/components/Text";

const meta: Meta<typeof Message> = {
title: "Content/Message",
component: Message,
parameters: {
controls: { exclude: ["className"] },
},
render: (props) => (
<Message {...props}>
<Header>
<ContextMenuTrigger>
<Button />
<ContextMenu>
<MenuItem>Bearbeiten</MenuItem>
<MenuItem>Löschen</MenuItem>
</ContextMenu>
</ContextMenuTrigger>
<Align>
<Avatar>
<Initials>Max Mustermann</Initials>
</Avatar>
<Text>
<b>Max Mustermann</b>
Organisationsinhaber
</Text>
</Align>
<Text>01.09.2024, 12:45</Text>
</Header>

<Content>
<Text>Das ist eine Nachricht</Text>
</Content>
</Message>
),
};
export default meta;

type Story = StoryObj<typeof Message>;

export const Default: Story = {};

export const Responder: Story = { args: { type: "responder" } };

export const MessageOnly: Story = {
render: (props) => (
<Message {...props}>
<Content>
<Text>Das ist eine Nachricht</Text>
</Content>
</Message>
),
};

export const OrientationRight: Story = { args: { orientation: "right" } };
3 changes: 3 additions & 0 deletions packages/components/src/components/propTypes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ import type { SegmentedControlProps } from "@/components/SegmentedControl";
import type { SegmentProps } from "@/components/SegmentedControl/components/Segment";
import type { FileCardProps } from "@/components/FileCard";
import type { FileFieldProps } from "@/components/FileField";
import type { AlignProps } from "@/components/Align";

export * from "./types";

Expand All @@ -64,6 +65,7 @@ export interface FlowComponentPropsTypes {
Alert: AlertProps;
AlertBadge: AlertBadgeProps;
AlertIcon: AlertIconProps;
Align: AlignProps;
Avatar: AvatarProps;
Badge: BadgeProps;
Button: ButtonProps;
Expand Down Expand Up @@ -130,6 +132,7 @@ const propsContextSupportingComponentsMap: Record<
Alert: true,
AlertBadge: true,
AlertIcon: true,
Align: true,
Badge: true,
Button: true,
Checkbox: true,
Expand Down
1 change: 1 addition & 0 deletions packages/components/vite.build.config.base.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ export const buildConfig = (opts: Options) => {
LoadingSpinner: "./src/components/LoadingSpinner/index.ts",
Markdown: "./src/components/Markdown/index.ts",
MenuItem: "./src/components/MenuItem/index.ts",
Message: "./src/components/Message/index.ts",
Modal: "./src/components/Modal/index.ts",
Navigation: "./src/components/Navigation/index.ts",
Notification: "./src/components/Notification/index.ts",
Expand Down
15 changes: 15 additions & 0 deletions packages/design-tokens/src/content/message.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
message:
corner-radius:
value: "{corner-radius.default}"
padding-y:
value: "{size-px.s}"
padding-x:
value: "{size-px.m}"
spacing-y:
value: "{size-rem.s}"
spacing-x:
value: "{size-rem.m}"
background-color-responder:
value: "{color.gray.400}"
background-color-sender:
value: "{color.hosting-blue.200}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Message } from "@mittwald/flow-react-components/Message";
import { Header } from "@mittwald/flow-react-components/Header";
import {
ContextMenu,
ContextMenuTrigger,
} from "@mittwald/flow-react-components/ContextMenu";
import { Button } from "@mittwald/flow-react-components/Button";
import MenuItem from "@mittwald/flow-react-components/MenuItem";
import { Align } from "@mittwald/flow-react-components/Align";
import { Avatar } from "@mittwald/flow-react-components/Avatar";
import { Initials } from "@mittwald/flow-react-components/Initials";
import { Text } from "@mittwald/flow-react-components/Text";
import { Content } from "@mittwald/flow-react-components/Content";

<Message>
<Header>
<ContextMenuTrigger>
<Button />
<ContextMenu>
<MenuItem>Bearbeiten</MenuItem>
<MenuItem>Löschen</MenuItem>
</ContextMenu>
</ContextMenuTrigger>
<Align>
<Avatar>
<Initials>Max Mustermann</Initials>
</Avatar>
<Text>
<b>Max Mustermann</b>
Organisationsinhaber
</Text>
</Align>
<Text>01.09.2024, 12:45</Text>
</Header>

<Content>
<Text>
Lorem ipsum dolor sit amet, consetetur sadipscing
elitr, sed diam nonumy eirmod tempor invidunt ut
labore et dolore magna aliquyam erat, sed diam
voluptua. At vero eos et accusam et justo duo dolores
et ea rebum. Stet clita kasd gubergren, no sea
takimata sanctus est Lorem ipsum dolor sit amet.
</Text>
</Content>
</Message>;
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
import { Message } from "@mittwald/flow-react-components/Message";
import { Header } from "@mittwald/flow-react-components/Header";
import {
ContextMenu,
ContextMenuTrigger,
} from "@mittwald/flow-react-components/ContextMenu";
import { Button } from "@mittwald/flow-react-components/Button";
import MenuItem from "@mittwald/flow-react-components/MenuItem";
import { Align } from "@mittwald/flow-react-components/Align";
import { Avatar } from "@mittwald/flow-react-components/Avatar";
import { Initials } from "@mittwald/flow-react-components/Initials";
import { Text } from "@mittwald/flow-react-components/Text";
import { Content } from "@mittwald/flow-react-components/Content";

<Message type="responder">
<Header>
<ContextMenuTrigger>
<Button />
<ContextMenu>
<MenuItem>Bearbeiten</MenuItem>
<MenuItem>Löschen</MenuItem>
</ContextMenu>
</ContextMenuTrigger>
<Align>
<Avatar>
<Initials>Max Mustermann</Initials>
</Avatar>
<Text>
<b>Max Mustermann</b>
Organisationsinhaber
</Text>
</Align>
<Text>01.09.2024, 12:45</Text>
</Header>

<Content>
<Text>
Lorem ipsum dolor sit amet, consetetur sadipscing
elitr, sed diam nonumy eirmod tempor invidunt ut
labore et dolore magna aliquyam erat, sed diam
voluptua. At vero eos et accusam et justo duo dolores
et ea rebum. Stet clita kasd gubergren, no sea
takimata sanctus est Lorem ipsum dolor sit amet.
</Text>
</Content>
</Message>;
Loading

0 comments on commit dcecea5

Please sign in to comment.