diff --git a/.changeset/pretty-items-lick.md b/.changeset/pretty-items-lick.md new file mode 100644 index 00000000000..bfadb87ffd2 --- /dev/null +++ b/.changeset/pretty-items-lick.md @@ -0,0 +1,30 @@ +--- +"@aws-amplify/ui": patch +--- + +chore(ai): add theming for AIConversation + +```ts +const theme = createTheme({ + tokens: { + components: { + aiConversation: {} + } + } +}) +``` + +```ts +const aiConversationTheme = defineComponentTheme({ + name: 'ai-conversation', + theme(tokens) { + return { + _element: { + message: { + color: tokens.colors.font.tertiary + } + } + } + } +}); +``` diff --git a/docs/__tests__/__snapshots__/cssvars-table.test.ts.snap b/docs/__tests__/__snapshots__/cssvars-table.test.ts.snap index f96d36e9ddc..69baeff0c0f 100644 --- a/docs/__tests__/__snapshots__/cssvars-table.test.ts.snap +++ b/docs/__tests__/__snapshots__/cssvars-table.test.ts.snap @@ -606,6 +606,146 @@ exports[`CSS Variables Table 1`] = ` "variable": "--amplify-components-accordion-item-trigger-padding-inline", "value": "var(--amplify-space-small)" }, + { + "variable": "--amplify-components-ai-conversation-attachment-border-color", + "value": "var(--amplify-colors-border-secondary)" + }, + { + "variable": "--amplify-components-ai-conversation-attachment-border-radius", + "value": "var(--amplify-radii-small)" + }, + { + "variable": "--amplify-components-ai-conversation-attachment-border-width", + "value": "var(--amplify-border-widths-small)" + }, + { + "variable": "--amplify-components-ai-conversation-attachment-font-size", + "value": "var(--amplify-font-sizes-small)" + }, + { + "variable": "--amplify-components-ai-conversation-attachment-gap", + "value": "var(--amplify-space-xs)" + }, + { + "variable": "--amplify-components-ai-conversation-attachment-image-height", + "value": "var(--amplify-font-sizes-medium)" + }, + { + "variable": "--amplify-components-ai-conversation-attachment-image-width", + "value": "var(--amplify-font-sizes-medium)" + }, + { + "variable": "--amplify-components-ai-conversation-attachment-list-gap", + "value": "var(--amplify-space-xxs)" + }, + { + "variable": "--amplify-components-ai-conversation-attachment-list-padding-block-start", + "value": "var(--amplify-space-xs)" + }, + { + "variable": "--amplify-components-ai-conversation-attachment-name-color", + "value": "var(--amplify-colors-font-primary)" + }, + { + "variable": "--amplify-components-ai-conversation-attachment-name-font-size", + "value": "var(--amplify-font-sizes-small)" + }, + { + "variable": "--amplify-components-ai-conversation-attachment-name-font-weight", + "value": "var(--amplify-font-weights-normal)" + }, + { + "variable": "--amplify-components-ai-conversation-attachment-padding-block", + "value": "var(--amplify-space-xxxs)" + }, + { + "variable": "--amplify-components-ai-conversation-attachment-padding-inline", + "value": "var(--amplify-space-xs)" + }, + { + "variable": "--amplify-components-ai-conversation-attachment-remove-padding", + "value": "var(--amplify-space-xxs)" + }, + { + "variable": "--amplify-components-ai-conversation-attachment-size-color", + "value": "var(--amplify-colors-font-tertiary)" + }, + { + "variable": "--amplify-components-ai-conversation-attachment-size-font-size", + "value": "var(--amplify-font-sizes-small)" + }, + { + "variable": "--amplify-components-ai-conversation-attachment-size-font-weight", + "value": "var(--amplify-font-weights-normal)" + }, + { + "variable": "--amplify-components-ai-conversation-form-gap", + "value": "var(--amplify-space-small)" + }, + { + "variable": "--amplify-components-ai-conversation-form-padding", + "value": "var(--amplify-space-small)" + }, + { + "variable": "--amplify-components-ai-conversation-message-assistant-background-color", + "value": "var(--amplify-colors-primary-10)" + }, + { + "variable": "--amplify-components-ai-conversation-message-background-color", + "value": "var(--amplify-colors-background-secondary)" + }, + { + "variable": "--amplify-components-ai-conversation-message-body-gap", + "value": "var(--amplify-space-xs)" + }, + { + "variable": "--amplify-components-ai-conversation-message-border-radius", + "value": "var(--amplify-radii-large)" + }, + { + "variable": "--amplify-components-ai-conversation-message-gap", + "value": "var(--amplify-space-small)" + }, + { + "variable": "--amplify-components-ai-conversation-message-padding-block", + "value": "var(--amplify-space-small)" + }, + { + "variable": "--amplify-components-ai-conversation-message-padding-inline", + "value": "var(--amplify-space-small)" + }, + { + "variable": "--amplify-components-ai-conversation-message-sender-gap", + "value": "var(--amplify-space-small)" + }, + { + "variable": "--amplify-components-ai-conversation-message-sender-timestamp-color", + "value": "var(--amplify-colors-font-tertiary)" + }, + { + "variable": "--amplify-components-ai-conversation-message-sender-timestamp-font-size", + "value": "inherit" + }, + { + "variable": "--amplify-components-ai-conversation-message-sender-timestamp-font-weight", + "value": "inherit" + }, + { + "variable": "--amplify-components-ai-conversation-message-sender-username-color", + "value": "var(--amplify-colors-font-primary)" + }, + { + "variable": "--amplify-components-ai-conversation-message-sender-username-font-size", + "value": "inherit" + }, + { + "variable": "--amplify-components-ai-conversation-message-sender-username-font-weight", + "value": "var(--amplify-font-weights-bold)" + }, + { + "variable": "--amplify-components-ai-conversation-message-user-background-color", + "value": "var(--amplify-colors-background-secondary)" + }, { "variable": "--amplify-components-alert-align-items", "value": "center" diff --git a/examples/next/pages/ui/components/ai/ai-conversation-theming-v2/amplify_outputs.js b/examples/next/pages/ui/components/ai/ai-conversation-theming-v2/amplify_outputs.js new file mode 100644 index 00000000000..2f1016412fd --- /dev/null +++ b/examples/next/pages/ui/components/ai/ai-conversation-theming-v2/amplify_outputs.js @@ -0,0 +1,2 @@ +import amplifyOutputs from '@environments/ai/gen2/amplify_outputs'; +export default amplifyOutputs; diff --git a/examples/next/pages/ui/components/ai/ai-conversation-theming-v2/index.page.tsx b/examples/next/pages/ui/components/ai/ai-conversation-theming-v2/index.page.tsx new file mode 100644 index 00000000000..5ca1cb2e059 --- /dev/null +++ b/examples/next/pages/ui/components/ai/ai-conversation-theming-v2/index.page.tsx @@ -0,0 +1,124 @@ +import * as React from 'react'; + +import { Amplify } from 'aws-amplify'; +import { generateClient } from 'aws-amplify/api'; +import { + View, + createTheme, + defaultDarkModeOverride, + withAuthenticator, + ColorMode, + Button, +} from '@aws-amplify/ui-react'; +import { createAIHooks, AIConversation } from '@aws-amplify/ui-react-ai'; +import { ThemeStyle, defineComponentTheme } from '@aws-amplify/ui-react/server'; +import '@aws-amplify/ui-react/styles.css'; + +import outputs from './amplify_outputs'; +import type { Schema } from '@environments/ai/gen2/amplify/data/resource'; + +const client = generateClient({ authMode: 'userPool' }); +const { useAIConversation } = createAIHooks(client); + +Amplify.configure(outputs); + +const conversationTheme = defineComponentTheme({ + name: 'ai-conversation', + theme(tokens) { + return { + _element: { + message: { + borderRadius: tokens.radii.large, + padding: tokens.space.small, + borderWidth: tokens.borderWidths.small, + borderStyle: 'solid', + borderColor: tokens.colors.border.primary, + boxShadow: `${tokens.shadows.medium}`, + }, + message__list: { + gap: tokens.space.large, + }, + form: { + borderRadius: tokens.radii.large, + padding: tokens.space.small, + borderWidth: tokens.borderWidths.small, + borderStyle: 'solid', + borderColor: tokens.colors.border.primary, + boxShadow: `${tokens.shadows.medium}`, + }, + }, + }; + }, + overrides: [ + { + colorMode: 'dark', + theme(tokens) { + return { + _element: { + form: { + backgroundColor: tokens.colors.background.secondary, + }, + }, + }; + }, + }, + ], +}); + +const theme = createTheme({ + name: 'ai-conversation-theme', + components: [conversationTheme], + overrides: [defaultDarkModeOverride], +}); + +function Chat() { + const [ + { + data: { messages }, + isLoading, + }, + sendMessage, + ] = useAIConversation('pirateChat'); + return ( + <> + + + + ); +} + +function AIConversationThemePage() { + const [colorMode, setColorMode] = React.useState('light'); + + return ( + <> + + + + + + + ); +} + +export default withAuthenticator(AIConversationThemePage); diff --git a/examples/next/pages/ui/components/ai/ai-conversation-theming/amplify_outputs.js b/examples/next/pages/ui/components/ai/ai-conversation-theming/amplify_outputs.js new file mode 100644 index 00000000000..2f1016412fd --- /dev/null +++ b/examples/next/pages/ui/components/ai/ai-conversation-theming/amplify_outputs.js @@ -0,0 +1,2 @@ +import amplifyOutputs from '@environments/ai/gen2/amplify_outputs'; +export default amplifyOutputs; diff --git a/examples/next/pages/ui/components/ai/ai-conversation-theming/index.page.tsx b/examples/next/pages/ui/components/ai/ai-conversation-theming/index.page.tsx new file mode 100644 index 00000000000..2b26d0a4c82 --- /dev/null +++ b/examples/next/pages/ui/components/ai/ai-conversation-theming/index.page.tsx @@ -0,0 +1,81 @@ +import * as React from 'react'; +import { Amplify } from 'aws-amplify'; +import { createAIHooks, AIConversation } from '@aws-amplify/ui-react-ai'; +import { ThemeStyle } from '@aws-amplify/ui-react/server'; +import { generateClient } from 'aws-amplify/api'; +import '@aws-amplify/ui-react/styles.css'; +import outputs from './amplify_outputs'; +import type { Schema } from '@environments/ai/gen2/amplify/data/resource'; +import { + View, + createTheme, + defaultDarkModeOverride, + withAuthenticator, +} from '@aws-amplify/ui-react'; +import { ColorMode } from '@aws-amplify/ui-react'; +import { Button } from '@aws-amplify/ui-react'; + +const client = generateClient({ authMode: 'userPool' }); +const { useAIConversation } = createAIHooks(client); + +Amplify.configure(outputs); + +const theme = createTheme({ + name: 'ai-conversation-theme', + tokens: { + components: { + aiConversation: { + message: { + backgroundColor: { value: '#f5f5f5' }, + gap: '{space.small}', + }, + }, + }, + }, + overrides: [defaultDarkModeOverride], +}); + +function AIConversationThemePage() { + const [colorMode, setColorMode] = React.useState('light'); + const [ + { + data: { messages }, + isLoading, + }, + sendMessage, + ] = useAIConversation('pirateChat'); + + return ( + <> + + + + + + + + ); +} + +export default withAuthenticator(AIConversationThemePage); diff --git a/packages/ui/src/theme/__tests__/__snapshots__/defaultTheme.test.ts.snap b/packages/ui/src/theme/__tests__/__snapshots__/defaultTheme.test.ts.snap index 27b7132a0cd..4bcbd85efee 100644 --- a/packages/ui/src/theme/__tests__/__snapshots__/defaultTheme.test.ts.snap +++ b/packages/ui/src/theme/__tests__/__snapshots__/defaultTheme.test.ts.snap @@ -25,6 +25,41 @@ exports[`@aws-amplify/ui defaultTheme should match snapshot 1`] = ` --amplify-components-accordion-item-icon-color: var(--amplify-colors-font-tertiary); --amplify-components-accordion-item-icon-transition-duration: var(--amplify-time-medium); --amplify-components-accordion-item-icon-transition-timing-function: cubic-bezier(0.87, 0, 0.13, 1); +--amplify-components-ai-conversation-message-background-color: var(--amplify-colors-background-secondary); +--amplify-components-ai-conversation-message-border-radius: var(--amplify-radii-large); +--amplify-components-ai-conversation-message-gap: var(--amplify-space-small); +--amplify-components-ai-conversation-message-padding-block: var(--amplify-space-small); +--amplify-components-ai-conversation-message-padding-inline: var(--amplify-space-small); +--amplify-components-ai-conversation-message-user-background-color: var(--amplify-colors-background-secondary); +--amplify-components-ai-conversation-message-assistant-background-color: var(--amplify-colors-primary-10); +--amplify-components-ai-conversation-message-sender-gap: var(--amplify-space-small); +--amplify-components-ai-conversation-message-sender-username-color: var(--amplify-colors-font-primary); +--amplify-components-ai-conversation-message-sender-username-font-size: inherit; +--amplify-components-ai-conversation-message-sender-username-font-weight: var(--amplify-font-weights-bold); +--amplify-components-ai-conversation-message-sender-timestamp-color: var(--amplify-colors-font-tertiary); +--amplify-components-ai-conversation-message-sender-timestamp-font-size: inherit; +--amplify-components-ai-conversation-message-sender-timestamp-font-weight: inherit; +--amplify-components-ai-conversation-message-body-gap: var(--amplify-space-xs); +--amplify-components-ai-conversation-form-gap: var(--amplify-space-small); +--amplify-components-ai-conversation-form-padding: var(--amplify-space-small); +--amplify-components-ai-conversation-attachment-border-color: var(--amplify-colors-border-secondary); +--amplify-components-ai-conversation-attachment-border-width: var(--amplify-border-widths-small); +--amplify-components-ai-conversation-attachment-border-radius: var(--amplify-radii-small); +--amplify-components-ai-conversation-attachment-font-size: var(--amplify-font-sizes-small); +--amplify-components-ai-conversation-attachment-padding-block: var(--amplify-space-xxxs); +--amplify-components-ai-conversation-attachment-padding-inline: var(--amplify-space-xs); +--amplify-components-ai-conversation-attachment-gap: var(--amplify-space-xs); +--amplify-components-ai-conversation-attachment-list-padding-block-start: var(--amplify-space-xs); +--amplify-components-ai-conversation-attachment-list-gap: var(--amplify-space-xxs); +--amplify-components-ai-conversation-attachment-name-color: var(--amplify-colors-font-primary); +--amplify-components-ai-conversation-attachment-name-font-size: var(--amplify-font-sizes-small); +--amplify-components-ai-conversation-attachment-name-font-weight: var(--amplify-font-weights-normal); +--amplify-components-ai-conversation-attachment-size-color: var(--amplify-colors-font-tertiary); +--amplify-components-ai-conversation-attachment-size-font-size: var(--amplify-font-sizes-small); +--amplify-components-ai-conversation-attachment-size-font-weight: var(--amplify-font-weights-normal); +--amplify-components-ai-conversation-attachment-remove-padding: var(--amplify-space-xxs); +--amplify-components-ai-conversation-attachment-image-width: var(--amplify-font-sizes-medium); +--amplify-components-ai-conversation-attachment-image-height: var(--amplify-font-sizes-medium); --amplify-components-alert-align-items: center; --amplify-components-alert-justify-content: space-between; --amplify-components-alert-color: var(--amplify-colors-font-primary); diff --git a/packages/ui/src/theme/__tests__/__snapshots__/overrides.test.ts.snap b/packages/ui/src/theme/__tests__/__snapshots__/overrides.test.ts.snap index a4b700e4656..55d0c70ec60 100644 --- a/packages/ui/src/theme/__tests__/__snapshots__/overrides.test.ts.snap +++ b/packages/ui/src/theme/__tests__/__snapshots__/overrides.test.ts.snap @@ -25,6 +25,41 @@ exports[`@aws-amplify/ui overrides should match snapshot 1`] = ` --amplify-components-accordion-item-icon-color: var(--amplify-colors-font-tertiary); --amplify-components-accordion-item-icon-transition-duration: var(--amplify-time-medium); --amplify-components-accordion-item-icon-transition-timing-function: cubic-bezier(0.87, 0, 0.13, 1); +--amplify-components-ai-conversation-message-background-color: var(--amplify-colors-background-secondary); +--amplify-components-ai-conversation-message-border-radius: var(--amplify-radii-large); +--amplify-components-ai-conversation-message-gap: var(--amplify-space-small); +--amplify-components-ai-conversation-message-padding-block: var(--amplify-space-small); +--amplify-components-ai-conversation-message-padding-inline: var(--amplify-space-small); +--amplify-components-ai-conversation-message-user-background-color: var(--amplify-colors-background-secondary); +--amplify-components-ai-conversation-message-assistant-background-color: var(--amplify-colors-primary-10); +--amplify-components-ai-conversation-message-sender-gap: var(--amplify-space-small); +--amplify-components-ai-conversation-message-sender-username-color: var(--amplify-colors-font-primary); +--amplify-components-ai-conversation-message-sender-username-font-size: inherit; +--amplify-components-ai-conversation-message-sender-username-font-weight: var(--amplify-font-weights-bold); +--amplify-components-ai-conversation-message-sender-timestamp-color: var(--amplify-colors-font-tertiary); +--amplify-components-ai-conversation-message-sender-timestamp-font-size: inherit; +--amplify-components-ai-conversation-message-sender-timestamp-font-weight: inherit; +--amplify-components-ai-conversation-message-body-gap: var(--amplify-space-xs); +--amplify-components-ai-conversation-form-gap: var(--amplify-space-small); +--amplify-components-ai-conversation-form-padding: var(--amplify-space-small); +--amplify-components-ai-conversation-attachment-border-color: var(--amplify-colors-border-secondary); +--amplify-components-ai-conversation-attachment-border-width: var(--amplify-border-widths-small); +--amplify-components-ai-conversation-attachment-border-radius: var(--amplify-radii-small); +--amplify-components-ai-conversation-attachment-font-size: var(--amplify-font-sizes-small); +--amplify-components-ai-conversation-attachment-padding-block: var(--amplify-space-xxxs); +--amplify-components-ai-conversation-attachment-padding-inline: var(--amplify-space-xs); +--amplify-components-ai-conversation-attachment-gap: var(--amplify-space-xs); +--amplify-components-ai-conversation-attachment-list-padding-block-start: var(--amplify-space-xs); +--amplify-components-ai-conversation-attachment-list-gap: var(--amplify-space-xxs); +--amplify-components-ai-conversation-attachment-name-color: var(--amplify-colors-font-primary); +--amplify-components-ai-conversation-attachment-name-font-size: var(--amplify-font-sizes-small); +--amplify-components-ai-conversation-attachment-name-font-weight: var(--amplify-font-weights-normal); +--amplify-components-ai-conversation-attachment-size-color: var(--amplify-colors-font-tertiary); +--amplify-components-ai-conversation-attachment-size-font-size: var(--amplify-font-sizes-small); +--amplify-components-ai-conversation-attachment-size-font-weight: var(--amplify-font-weights-normal); +--amplify-components-ai-conversation-attachment-remove-padding: var(--amplify-space-xxs); +--amplify-components-ai-conversation-attachment-image-width: var(--amplify-font-sizes-medium); +--amplify-components-ai-conversation-attachment-image-height: var(--amplify-font-sizes-medium); --amplify-components-alert-align-items: center; --amplify-components-alert-justify-content: space-between; --amplify-components-alert-color: var(--amplify-colors-font-primary); diff --git a/packages/ui/src/theme/components/aiConverstion.ts b/packages/ui/src/theme/components/aiConverstion.ts new file mode 100644 index 00000000000..1bd747c910c --- /dev/null +++ b/packages/ui/src/theme/components/aiConverstion.ts @@ -0,0 +1,31 @@ +import { Modifiers, ComponentStyles, Elements } from './utils'; + +export type AIConversationTheme = + ComponentStyles & + Elements< + { + message?: ComponentStyles & + Modifiers<'user' | 'assistant' | 'bubble', Required>; + message__list?: ComponentStyles; + message__avatar?: ComponentStyles; + message__sender?: ComponentStyles; + message__sender__username?: ComponentStyles; + message__sender__timestamp?: ComponentStyles; + message__body?: ComponentStyles; + message__actions?: ComponentStyles; + + form?: ComponentStyles; + form__dropzone?: ComponentStyles; + form__attatch?: ComponentStyles; + form__send?: ComponentStyles; + form_field?: ComponentStyles; + + attachment?: ComponentStyles; + attachment__list?: ComponentStyles; + attachment__image?: ComponentStyles; + attachment__size?: ComponentStyles; + attachment__name?: ComponentStyles; + attachment__remove?: ComponentStyles; + }, + Required + >; diff --git a/packages/ui/src/theme/components/index.ts b/packages/ui/src/theme/components/index.ts index eb8c5c69d2d..01d21a02d6a 100644 --- a/packages/ui/src/theme/components/index.ts +++ b/packages/ui/src/theme/components/index.ts @@ -1,4 +1,5 @@ import { WebTokens } from '../tokens'; +import { AIConversationTheme } from './aiConverstion'; import { AccordionTheme } from './accordion'; import { AlertTheme } from './alert'; import { AutoCompleteTheme } from './autocomplete'; @@ -51,6 +52,7 @@ export type { ComponentTheme, BaseComponentTheme, BaseTheme }; export type ComponentsTheme = | BaseComponentTheme | BaseComponentTheme + | BaseComponentTheme | BaseComponentTheme | BaseComponentTheme | BaseComponentTheme @@ -100,6 +102,7 @@ export type ComponentsTheme = // if the name extends from a known name, like 'alert' this should return the specific shape export type AllComponentThemes = { accordion: AccordionTheme; + 'ai-conversation': AIConversationTheme; alert: AlertTheme; autocomplete: AutoCompleteTheme; avatar: AvatarTheme; diff --git a/packages/ui/src/theme/css/component/AIConversation/aiConversation.scss b/packages/ui/src/theme/css/component/AIConversation/aiConversation.scss index ee24a98256d..b2db174cc9c 100644 --- a/packages/ui/src/theme/css/component/AIConversation/aiConversation.scss +++ b/packages/ui/src/theme/css/component/AIConversation/aiConversation.scss @@ -2,17 +2,27 @@ display: flex; flex-direction: column; height: 100%; + flex: 1; &__suggestion { } &__message { - --content-bg: transparent; + // internal CSS vars to handle combination of variation and sender (user, ai) + --internal-content-bg: ; + --internal-flex-direction: ; + --internal-content-padding: ; + --internal-body-align-items: ; display: flex; - flex-direction: var(--flex-direction); - gap: var(--amplify-space-small); - padding: var(--amplify-space-small); + flex-direction: var(--internal-flex-direction); + gap: var(--amplify-components-ai-conversation-message-gap); + padding-inline: var( + --amplify-components-ai-conversation-message-padding-inline + ); + padding-block: var( + --amplify-components-ai-conversation-message-padding-block + ); &__list { display: flex; @@ -25,32 +35,47 @@ &__sender { display: flex; - flex-direction: var(--flex-direction); + flex-direction: var(--internal-flex-direction); align-items: center; - height: var(--amplify-components-avatar-height); - gap: var(--amplify-space-small); + min-height: var(--amplify-components-avatar-height); + gap: var(--amplify-components-ai-conversation-message-sender-gap); &__username { - font-weight: bold; + color: var( + --amplify-components-ai-conversation-message-sender-username-color + ); + font-size: var( + --amplify-components-ai-conversation-message-sender-username-font-size + ); + font-weight: var( + --amplify-components-ai-conversation-message-sender-username-font-weight + ); } &__timestamp { - color: var(--amplify-colors-font-tertiary); - font-size: var(--amplify-font-sizes-small); + color: var( + --amplify-components-ai-conversation-message-sender-timestamp-color + ); + font-size: var( + --amplify-components-ai-conversation-message-sender-timestamp-font-size + ); + font-weight: var( + --amplify-components-ai-conversation-message-sender-timestamp-font-weight + ); } } &__body { display: flex; flex-direction: column; - align-items: var(--body-align-items); - gap: var(--amplify-space-xs); + align-items: var(--internal-body-align-items); + gap: var(--amplify-components-ai-conversation-message-body-gap); } &__content { - background-color: var(--content-bg); + background-color: var(--internal-content-bg); border-radius: var(--amplify-radii-medium); - padding: var(--content-padding); + padding: var(--internal-content-padding); } &__actions { @@ -59,23 +84,28 @@ } &--bubble { - --content-bg: var(--bg-color); - --content-padding: var(--amplify-space-xxs) var(--amplify-space-xs); - --flex-direction: row-reverse; - --body-align-items: flex-end; + --internal-content-bg: var(--internal-bg-color); + --internal-content-padding: var(--amplify-space-xxs) + var(--amplify-space-xs); + --internal-flex-direction: row-reverse; + --internal-body-align-items: flex-end; } &--filled { } &--user { - --bg-color: var(--amplify-colors-background-secondary); + --internal-bg-color: var( + --amplify-components-ai-conversation-message-user-background-color + ); } &--assistant { - --bg-color: var(--amplify-colors-primary-10); - --flex-direction: row; - --body-align-items: flex-start; + --internal-bg-color: var( + --amplify-components-ai-conversation-message-assistant-background-color + ); + --internal-flex-direction: row; + --internal-body-align-items: flex-start; } } @@ -83,12 +113,13 @@ display: flex; flex-direction: row; align-items: flex-start; - gap: var(--amplify-space-small); + gap: var(--amplify-components-ai-conversation-form-gap); + padding: var(--amplify-components-ai-conversation-form-padding); &__dropzone { text-align: initial; border: none; - padding: var(--amplify-space-xs); + padding: 0; } &__attach { @@ -102,39 +133,66 @@ &__attachment { display: flex; flex-direction: row; - padding-block: var(--amplify-space-xxxs); - padding-inline: var(--amplify-space-xs); - border-width: var(--amplify-border-widths-small); - border-style: solid; - border-color: var(--amplify-colors-border-secondary); - border-radius: var(--amplify-radii-small); align-items: center; - gap: var(--amplify-space-xs); - font-size: var(--amplify-font-sizes-small); + padding-block: var( + --amplify-components-ai-conversation-attachment-padding-block + ); + padding-inline: var( + --amplify-components-ai-conversation-attachment-padding-inline + ); + border-width: var( + --amplify-components-ai-conversation-attachment-border-width + ); + border-style: solid; + border-color: var( + --amplify-components-ai-conversation-attachment-border-color + ); + border-radius: var( + --amplify-components-ai-conversation-attachment-border-radius + ); + gap: var(--amplify-components-ai-conversation-attachment-gap); + font-size: var(--amplify-components-ai-conversation-attachment-font-size); &__list { display: flex; flex-direction: row; flex-wrap: wrap; - gap: var(--amplify-space-small); - padding-block-start: var(--amplify-space-small); + gap: var(--amplify-components-ai-conversation-attachment-list-gap); + padding-block-start: var( + --amplify-components-ai-conversation-attachment-padding-block-start + ); } &__image { - width: 1rem; - height: 1rem; + width: var(--amplify-components-ai-conversation-attachment-image-width); + height: var(--amplify-components-ai-conversation-attachment-image-height); object-fit: cover; } &__name { + color: var(--amplify-components-ai-conversation-attachment-name-color); + font-size: var( + --amplify-components-ai-conversation-attachment-name-font-size + ); + font-weight: var( + --amplify-components-ai-conversation-attachment-name-font-weight + ); } &__size { - color: var(--amplify-colors-font-tertiary); + color: var(--amplify-components-ai-conversation-attachment-size-color); + font-size: var( + --amplify-components-ai-conversation-attachment-size-font-size + ); + font-weight: var( + --amplify-components-ai-conversation-attachment-size-font-weight + ); } &__remove { - padding: var(--amplify-space-xxs); + padding: var( + --amplify-components-ai-conversation-attachment-remove-padding + ); } } diff --git a/packages/ui/src/theme/tokens/components/aiConversation.ts b/packages/ui/src/theme/tokens/components/aiConversation.ts new file mode 100644 index 00000000000..52c0ae4513b --- /dev/null +++ b/packages/ui/src/theme/tokens/components/aiConversation.ts @@ -0,0 +1,120 @@ +import { DesignTokenProperties, OutputVariantKey } from '../types/designToken'; + +export interface AIConversationTokens { + message?: DesignTokenProperties< + | 'backgroundColor' + | 'borderRadius' + | 'paddingBlock' + | 'paddingInline' + | 'gap', + OutputType + > & { + sender?: DesignTokenProperties<'gap', OutputType> & { + username?: DesignTokenProperties< + 'color' | 'fontSize' | 'fontWeight', + OutputType + >; + timestamp?: DesignTokenProperties< + 'color' | 'fontSize' | 'fontWeight', + OutputType + >; + }; + body?: DesignTokenProperties<'gap', OutputType>; + user?: DesignTokenProperties<'backgroundColor', OutputType>; + assistant?: DesignTokenProperties<'backgroundColor', OutputType>; + }; + form?: DesignTokenProperties<'gap' | 'padding', OutputType>; + attachment?: DesignTokenProperties< + | 'borderColor' + | 'borderWidth' + | 'borderRadius' + | 'fontSize' + | 'paddingBlock' + | 'paddingInline' + | 'gap', + OutputType + > & { + list?: DesignTokenProperties<'paddingBlockStart' | 'gap', OutputType>; + image?: DesignTokenProperties<'width' | 'height', OutputType>; + size?: DesignTokenProperties< + 'color' | 'fontSize' | 'fontWeight', + OutputType + >; + name?: DesignTokenProperties< + 'color' | 'fontSize' | 'fontWeight', + OutputType + >; + remove?: DesignTokenProperties<'padding', OutputType>; + }; +} + +export const aiConversation: Required> = { + message: { + backgroundColor: { value: '{colors.background.secondary.value}' }, + borderRadius: { value: '{radii.large.value}' }, + gap: { value: '{space.small.value}' }, + paddingBlock: { value: '{space.small.value}' }, + paddingInline: { value: '{space.small.value}' }, + user: { + backgroundColor: { value: '{colors.background.secondary.value}' }, + }, + assistant: { + backgroundColor: { value: '{colors.primary.10.value}' }, + }, + sender: { + gap: { value: '{space.small.value}' }, + username: { + color: { value: '{colors.font.primary.value}' }, + fontSize: { value: 'inherit' }, + fontWeight: { value: '{fontWeights.bold.value}' }, + }, + timestamp: { + color: { value: '{colors.font.tertiary.value}' }, + fontSize: { value: 'inherit' }, + fontWeight: { value: 'inherit' }, + }, + }, + body: { gap: { value: '{space.xs.value}' } }, + }, + + form: { + gap: { value: '{space.small.value}' }, + padding: { value: '{space.small.value}' }, + }, + + attachment: { + borderColor: { value: '{colors.border.secondary.value}' }, + borderWidth: { value: '{borderWidths.small.value}' }, + borderRadius: { value: '{radii.small.value}' }, + fontSize: { value: '{fontSizes.small.value}' }, + paddingBlock: { value: '{space.xxxs.value}' }, + paddingInline: { value: '{space.xs.value}' }, + gap: { value: '{space.xs.value}' }, + + list: { + paddingBlockStart: { value: '{space.xs.value}' }, + gap: { value: '{space.xxs.value}' }, + }, + + name: { + color: { value: '{colors.font.primary.value}' }, + fontSize: { value: '{fontSizes.small.value}' }, + fontWeight: { value: '{fontWeights.normal.value}' }, + }, + + size: { + color: { value: '{colors.font.tertiary.value}' }, + fontSize: { value: '{fontSizes.small.value}' }, + fontWeight: { value: '{fontWeights.normal.value}' }, + }, + + remove: { + padding: { value: '{space.xxs.value}' }, + }, + + image: { + width: { value: '{fontSizes.medium.value}' }, + height: { value: '{fontSizes.medium.value}' }, + }, + }, +}; diff --git a/packages/ui/src/theme/tokens/components/index.ts b/packages/ui/src/theme/tokens/components/index.ts index 650cda3042d..4c10dd92866 100644 --- a/packages/ui/src/theme/tokens/components/index.ts +++ b/packages/ui/src/theme/tokens/components/index.ts @@ -1,4 +1,5 @@ import { AlertTokens, alert } from './alert'; +import { AIConversationTokens, aiConversation } from './aiConversation'; import { AutocompleteTokens, autocomplete } from './autocomplete'; import { AuthenticatorTokens, authenticator } from './authenticator'; import { AvatarTokens, avatar } from './avatar'; @@ -61,6 +62,7 @@ import { OutputVariantKey } from '../types/designToken'; type BaseComponentTokens = { accordion?: AccordionTokens; + aiConversation?: AIConversationTokens; alert?: AlertTokens; authenticator?: AuthenticatorTokens; autocomplete?: AutocompleteTokens; @@ -131,6 +133,7 @@ export type WebComponentTokens = Required<{ export const components: DefaultComponentTokens = { accordion, + aiConversation, alert, authenticator, autocomplete,