Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 129 additions & 0 deletions pages/chat-bubble/style-permutations.page.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
// SPDX-License-Identifier: Apache-2.0
import Box from "@cloudscape-design/components/box";

import { ChatBubble } from "../../lib/components";
import { Page } from "../app/templates";
import { TestBed } from "../app/test-bed";
import { Actions, ChatBubbleAvatarGenAI, ChatBubbleAvatarUser, ChatContainer } from "./util-components";

export default function ChatBubblePage() {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[non-blocking]: I'd suggest to implement it using the same abstraction as in the components repo: https://github.com/cloudscape-design/components/blob/main/pages/alert/permutations.page.tsx#L10 as it's more scalable and easier to modify / test new properties

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, we don't have PermutationsView util in this package. We can make it reusable and use it here as well in the future. For this PR, I will not be adding it so that I can get unblocked.

return (
<Page title="Chat bubble">
<TestBed>
<ChatContainer>
{/* Background Color with Dark Mode */}
<ChatBubble
style={{ bubble: { background: "light-dark(#f0f8ff, #1a1a2e)", color: "light-dark(#333, #eee)" } }}
type="incoming"
avatar={<ChatBubbleAvatarGenAI />}
ariaLabel="Background test"
>
Light blue/dark purple background with adaptive text color
</ChatBubble>

{/* Border Styles with Dark Mode */}
<ChatBubble
style={{
bubble: { borderColor: "light-dark(#e74c3c, #ff6b6b)", borderWidth: "2px", borderRadius: "20px" },
}}
type="outgoing"
avatar={<ChatBubbleAvatarUser />}
ariaLabel="Border test"
>
Adaptive red border with rounded corners
</ChatBubble>

{/* Typography with Dark Mode */}
<ChatBubble
style={{ bubble: { fontSize: "18px", fontWeight: "bold", color: "light-dark(#8e44ad, #bb86fc)" } }}
type="incoming"
avatar={<ChatBubbleAvatarGenAI />}
ariaLabel="Typography test"
>
Large bold adaptive purple text
</ChatBubble>

{/* Shadow Effect with Dark Mode */}
<ChatBubble
style={{
bubble: { boxShadow: "10px 5px 5px red" },
}}
type="outgoing"
avatar={<ChatBubbleAvatarUser />}
ariaLabel="Shadow test"
>
Adaptive shadow for elevation
</ChatBubble>

{/* Spacing */}
<ChatBubble
style={{ root: { columnGap: "32px" }, bubble: { paddingBlock: "20px", paddingInline: "24px" } }}
type="incoming"
avatar={<ChatBubbleAvatarGenAI />}
ariaLabel="Spacing test"
>
Wide avatar spacing with generous padding
</ChatBubble>

{/* Loading State with Dark Mode */}
<ChatBubble
style={{
bubble: {
background: "light-dark(#fff3cd, #3d3d00)",
borderColor: "light-dark(#ffc107, #ffeb3b)",
borderWidth: "1px",
},
}}
avatar={<ChatBubbleAvatarGenAI loading={true} />}
type="incoming"
showLoadingBar={true}
ariaLabel="Loading test"
>
<Box color="text-body-secondary">Generating response...</Box>
</ChatBubble>

{/* With Actions and Dark Mode */}
<ChatBubble
style={{ bubble: { background: "light-dark(#e8f5e8, #1b2e1b)", borderRadius: "18px", rowGap: "25px" } }}
avatar={<ChatBubbleAvatarGenAI />}
type="incoming"
actions={<Actions />}
ariaLabel="Actions test"
>
Message with action buttons
</ChatBubble>

{/* All Properties Combined with Dark Mode */}
<ChatBubble
style={{
root: {
columnGap: "25px",
},
bubble: {
background: "light-dark(#ffffff, #2d2d2d)",
color: "light-dark(#1b5e20, #81c784)",
borderColor: "light-dark(#4caf50, #66bb6a)",
borderWidth: "2px",
borderRadius: "24px",
boxShadow: "0 4px 12px rgb(29, 130, 118)",
fontSize: "16px",
fontWeight: "bold",
paddingBlock: "20px",
paddingInline: "30px",
rowGap: "20px",
},
}}
type="outgoing"
avatar={<ChatBubbleAvatarUser />}
actions={<Actions />}
ariaLabel="All properties test"
showLoadingBar={true}
>
All style properties combined
</ChatBubble>
</ChatContainer>
</TestBed>
</Page>
);
}
18 changes: 11 additions & 7 deletions scripts/environment.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,13 +10,17 @@ const pkg = JSON.parse(fs.readFileSync("package.json", "utf-8"));
const packageVersion = `${pkg.version} (${gitCommitVersion})`;

const basePath = "lib/components/internal/environment";
const values = {
PACKAGE_SOURCE: "chat-components",
PACKAGE_VERSION: packageVersion,
THEME: "open-source-visual-refresh",
SYSTEM: "core",
ALWAYS_VISUAL_REFRESH: true,
};
export function getBuildTimeEnvironmentConstants() {
return {
PACKAGE_SOURCE: "chat-components",
PACKAGE_VERSION: packageVersion,
THEME: "open-source-visual-refresh",
SYSTEM: "core",
ALWAYS_VISUAL_REFRESH: true,
};
}

const values = getBuildTimeEnvironmentConstants();
writeFile(`${basePath}.json`, JSON.stringify(values, null, 2));
writeFile(
`${basePath}.js`,
Expand Down
96 changes: 96 additions & 0 deletions src/__tests__/__snapshots__/documenter.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,102 @@ If avatar is being used, set its \`loading\` state to true.",
"optional": true,
"type": "boolean",
},
{
"inlineType": {
"name": "ChatBubbleProps.Style",
"properties": [
{
"inlineType": {
"name": "object",
"properties": [
{
"name": "background",
"optional": true,
"type": "string",
},
{
"name": "borderColor",
"optional": true,
"type": "string",
},
{
"name": "borderRadius",
"optional": true,
"type": "string",
},
{
"name": "borderWidth",
"optional": true,
"type": "string",
},
{
"name": "boxShadow",
"optional": true,
"type": "string",
},
{
"name": "color",
"optional": true,
"type": "string",
},
{
"name": "fontSize",
"optional": true,
"type": "string",
},
{
"name": "fontWeight",
"optional": true,
"type": "string",
},
{
"name": "paddingBlock",
"optional": true,
"type": "string",
},
{
"name": "paddingInline",
"optional": true,
"type": "string",
},
{
"name": "rowGap",
"optional": true,
"type": "string",
},
],
"type": "object",
},
"name": "bubble",
"optional": true,
"type": "{ background?: string | undefined; borderColor?: string | undefined; borderRadius?: string | undefined; borderWidth?: string | undefined; boxShadow?: string | undefined; color?: string | undefined; ... 4 more ...; paddingInline?: string | undefined; }",
},
{
"inlineType": {
"name": "{ columnGap?: string | undefined; }",
"properties": [
{
"name": "columnGap",
"optional": true,
"type": "string",
},
],
"type": "object",
},
"name": "root",
"optional": true,
"type": "{ columnGap?: string | undefined; }",
},
],
"type": "object",
},
"name": "style",
"optional": true,
"systemTags": [
"core",
],
"type": "ChatBubbleProps.Style",
},
{
"description": "Defines the type of the chat bubble and sets its color accordingly.",
"inlineType": {
Expand Down
3 changes: 3 additions & 0 deletions src/avatar/__tests__/avatar.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,9 @@ describe("Avatar", () => {
});

test("style api", () => {
vi.mock("../internal/environment", () => ({
SYSTEM: "core",
}));
const ariaLabel = "User avatar JD Jane Doe";
const wrapper = renderAvatar({
ariaLabel,
Expand Down
70 changes: 70 additions & 0 deletions src/chat-bubble/__tests__/__snapshots__/style.test.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html

exports[`getBubbleStyle > handles all possible style configurations 1`] = `
{
"background": undefined,
"borderColor": undefined,
"borderRadius": undefined,
"borderStyle": undefined,
"borderWidth": undefined,
"boxShadow": undefined,
"color": undefined,
"fontSize": undefined,
"fontWeight": undefined,
"paddingBlock": undefined,
"paddingInline": undefined,
"rowGap": undefined,
}
`;

exports[`getBubbleStyle > handles all possible style configurations 2`] = `
{
"background": undefined,
"borderColor": undefined,
"borderRadius": undefined,
"borderStyle": undefined,
"borderWidth": undefined,
"boxShadow": undefined,
"color": undefined,
"fontSize": undefined,
"fontWeight": undefined,
"paddingBlock": undefined,
"paddingInline": undefined,
"rowGap": undefined,
}
`;

exports[`getBubbleStyle > handles all possible style configurations 3`] = `
{
"background": "#f0f0f0",
"borderColor": "#ccc",
"borderRadius": "8px",
"borderStyle": "solid",
"borderWidth": "2px",
"boxShadow": "0 4px 8px rgba(0,0,0,0.2)",
"color": "#333",
"fontSize": "16px",
"fontWeight": "500",
"paddingBlock": "20px",
"paddingInline": "24px",
"rowGap": "12px",
}
`;

exports[`getChatBubbleRootStyle > handles all possible style configurations 1`] = `
{
"columnGap": undefined,
}
`;

exports[`getChatBubbleRootStyle > handles all possible style configurations 2`] = `
{
"columnGap": undefined,
}
`;

exports[`getChatBubbleRootStyle > handles all possible style configurations 3`] = `
{
"columnGap": "10px",
}
`;
Loading
Loading