Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
464a674
feat: add new conversational-ai pattern
TarunAdobe Mar 18, 2026
1627a02
chore: add all conversation-ai components
TarunAdobe Mar 23, 2026
aa9de43
chore: update conversation ui component
TarunAdobe Apr 1, 2026
7aece43
chore: update conversation-turn component
TarunAdobe Apr 2, 2026
e220a48
feat(css): updating css for css and lint fixes
aramos-adobe Apr 5, 2026
a2bc379
Merge branch 'conversation-ai-pattern' of github.com:adobe/spectrum-w…
aramos-adobe Apr 5, 2026
8cff96c
feat(sources): add proper styling to links
aramos-adobe Apr 5, 2026
06cb9f1
chore: update api for conversation ai
TarunAdobe Apr 6, 2026
631c11b
chore: fix artifact media type
TarunAdobe Apr 6, 2026
d57b02c
chore: trigger preview deploy
TarunAdobe Apr 10, 2026
4ad12d1
chore: update demo
TarunAdobe Apr 13, 2026
4a301e4
chore: update conversation ai
TarunAdobe Apr 13, 2026
0774ea8
chore: trigger preview-docs workflow
TarunAdobe Apr 13, 2026
6b56487
chore: dummy commit
rubencarvalho Apr 13, 2026
b7b7747
feat(convoai): aligning with design annotations
aramos-adobe Apr 14, 2026
1f4e54c
Merge branch 'main' into ttomar/conversation-ai
TarunAdobe Apr 14, 2026
38ba0ce
chore: update conversation ai component
TarunAdobe Apr 14, 2026
73530b0
fix(css): adjusting user message corners and some focus states
aramos-adobe Apr 14, 2026
d5d3926
fix(css): suggestion item focus
aramos-adobe Apr 15, 2026
b6e4a62
chore: add mode to prompt field
TarunAdobe Apr 15, 2026
61b87b5
chore: fix upload artifact
TarunAdobe Apr 15, 2026
6bf33c3
fix(sources): adjust inline size
aramos-adobe Apr 15, 2026
f07bd52
fix(convoAi): running through tests via playwright and vite
aramos-adobe Apr 15, 2026
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
5 changes: 4 additions & 1 deletion 2nd-gen/packages/swc/.storybook/DocumentTemplate.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,10 @@ import {
useOf,
} from '@storybook/addon-docs/blocks';
import {
DocsAfterApiMarkdown,
GettingStarted,
SpectrumStories,
OverviewStory,
SpectrumStories,
StatusBadge,
} from './blocks';

Expand Down Expand Up @@ -82,11 +83,13 @@ export const ConditionalGettingStarted = () => {
<ConditionalSection tag="states" title="States" />
<ConditionalSection tag="behaviors" title="Behaviors" />
<ConditionalSection tag="a11y" title="Accessibility" hideTitle={true} />
<ConditionalSection tag="full-pattern" title="Full pattern" />

## API

<Primary />
<Controls />
<DocsAfterApiMarkdown />
<AdvancedExamplesStories />

## Feedback
Expand Down
28 changes: 28 additions & 0 deletions 2nd-gen/packages/swc/.storybook/blocks/DocsAfterApiMarkdown.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Copyright 2026 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/

import { Markdown, useOf } from '@storybook/addon-docs/blocks';
import React from 'react';

/**
* Renders `parameters.docs.afterApi` (markdown) immediately after the API / Controls table.
*/
export const DocsAfterApiMarkdown = () => {
const resolvedOf = useOf('meta', ['meta']);
const md = resolvedOf.preparedMeta?.parameters?.docs?.afterApi;

if (!md || typeof md !== 'string') {
return null;
}

return <Markdown>{md}</Markdown>;
};
1 change: 1 addition & 0 deletions 2nd-gen/packages/swc/.storybook/blocks/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
export * from './DocsAfterApiMarkdown';
export * from './GettingStarted';
export * from './OverviewStory';
export * from './SpectrumDocs';
Expand Down
15 changes: 15 additions & 0 deletions 2nd-gen/packages/swc/.storybook/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,16 @@ const stories: StorybookConfig['stories'] = [
: '**/*.stories.ts',
titlePrefix: 'Components',
},
{
directory: '../patterns',
files: '**/*.stories.ts',
titlePrefix: 'Patterns',
},
{
directory: '../patterns',
files: '**/*.mdx',
titlePrefix: 'Patterns',
},
];

/**
Expand Down Expand Up @@ -83,6 +93,11 @@ if (storybookMode === 'dev') {
files: '**/*.test.ts',
titlePrefix: 'Components',
});
stories.push({
directory: '../patterns',
files: '**/*.test.ts',
titlePrefix: 'Patterns',
});
}

/**
Expand Down
30 changes: 4 additions & 26 deletions 2nd-gen/packages/swc/.storybook/preview.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ import { withLanguageWrapper } from './decorators/language.js';
import { withStaticColorPlayground } from './decorators/static-color-playground.js';
import DocumentTemplate from './DocumentTemplate.mdx';
import { FontLoader } from './loaders/font-loader.js';
import { transformDocsSource } from './utils/docs-source-transform.js';

import '../stylesheets/swc.css';
import '../stylesheets/typography.css';
Expand Down Expand Up @@ -181,32 +182,7 @@ const preview = {
excludeDecorators: true,
type: 'auto',
language: 'html',
transform: async (source: string) => {
try {
const prettier = await import('prettier/standalone');
const prettierPluginHtml = await import('prettier/plugins/html');
const prettierPluginBabel = await import('prettier/plugins/babel');
const prettierPluginEstree =
await import('prettier/plugins/estree');

return prettier.format(source, {
parser: 'html',
plugins: [
prettierPluginHtml.default,
prettierPluginBabel.default,
prettierPluginEstree.default,
],
tabWidth: 2,
useTabs: false,
singleQuote: true,
printWidth: 80,
});
} catch (error) {
// If formatting fails, return the original source
console.error('Failed to format source code:', error);
return source;
}
},
transform: transformDocsSource,
},
},
options: {
Expand All @@ -216,6 +192,8 @@ const preview = {
'Learn about SWC',
['Overview', 'When to use SWC', '1st-gen vs 2nd-gen'],
'Components',
'Patterns',
['Conversational AI', ['README', 'Prompt field', 'User message']],
'Guides',
[
'Accessibility guides',
Expand Down
74 changes: 74 additions & 0 deletions 2nd-gen/packages/swc/.storybook/utils/docs-source-transform.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
/**
* Copyright 2026 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/
import type { StoryContext } from '@storybook/web-components';

const PATTERN_TITLE_PREFIX = 'Patterns/Conversational AI/';

/**
* Format source snippets for Storybook code panel.
* For conversational AI pattern stories, this removes CSF wrapper noise and
* keeps only the `html\`...\`` content when possible.
*/
export async function transformDocsSource(
source: string,
storyContext?: StoryContext
): Promise<string> {
const normalizedSource = shouldNormalizePatternSource(storyContext)
? extractHtmlTemplate(source)
: source;

return formatHtml(normalizedSource);
}

function shouldNormalizePatternSource(storyContext?: StoryContext): boolean {
return storyContext?.title?.startsWith(PATTERN_TITLE_PREFIX) ?? false;
}

function extractHtmlTemplate(source: string): string {
const primaryMatch = source.match(
/\brender\s*:\s*\([^)]*\)\s*=>\s*html`([\s\S]*?)`\s*[},]/m
);
if (primaryMatch?.[1]) {
return primaryMatch[1].trim();
}

const fallbackMatch = source.match(/\bhtml`([\s\S]*?)`/m);
if (fallbackMatch?.[1]) {
return fallbackMatch[1].trim();
}

return source;
}

async function formatHtml(source: string): Promise<string> {
try {
const prettier = await import('prettier/standalone');
const prettierPluginHtml = await import('prettier/plugins/html');
const prettierPluginBabel = await import('prettier/plugins/babel');
const prettierPluginEstree = await import('prettier/plugins/estree');

return prettier.format(source, {
parser: 'html',
plugins: [
prettierPluginHtml.default,
prettierPluginBabel.default,
prettierPluginEstree.default,
],
tabWidth: 2,
useTabs: false,
singleQuote: true,
printWidth: 80,
});
} catch {
return source;
}
}
1 change: 1 addition & 0 deletions 2nd-gen/packages/swc/cem.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ function statusPlugin() {
export default {
globs: [
'components/**/*.ts',
'patterns/**/*.ts',
'../core/components/**/*.ts',
'../core/controllers/**/*.ts',
'../core/element/**/*.ts',
Expand Down
25 changes: 25 additions & 0 deletions 2nd-gen/packages/swc/debug-storybook.log
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
[11:45:52.845] [INFO] storybook v10.2.8
[11:45:54.394] [DEBUG] Getting package.json info for /Users/ttomar/Documents/work/ai-component/spectrum-web-components/2nd-gen/packages/swc/package.json...
[11:45:54.535] [DEBUG] Serving static files from 2nd-gen/packages/swc/public at /
[11:45:54.536] [INFO] Starting...
[11:45:55.838] [ERROR] SB_CORE-SERVER_0004 (NoMatchingExportError): There was an exports mismatch error when trying to build Storybook.
Please check whether the versions of your Storybook packages match whenever possible, as this might be the cause.

Problematic example:
{ "@storybook/react": "7.5.3", "@storybook/react-vite": "7.4.5", "storybook": "7.3.0" }

Correct example:
{ "@storybook/react": "7.5.3", "@storybook/react-vite": "7.5.3", "storybook": "7.5.3" }

Please run `npx storybook doctor` for guidance on how to fix this issue.

More info:

at buildOrThrow (file:///Users/ttomar/Documents/work/ai-component/spectrum-web-components/2nd-gen/node_modules/storybook/dist/core-server/index.js:4509:9)
at process.processTicksAndRejections (node:internal/process/task_queues:103:5)
at async buildDevStandalone (file:///Users/ttomar/Documents/work/ai-component/spectrum-web-components/2nd-gen/node_modules/storybook/dist/core-server/index.js:7577:66)
at async withTelemetry (file:///Users/ttomar/Documents/work/ai-component/spectrum-web-components/2nd-gen/node_modules/storybook/dist/_node-chunks/chunk-KIOKJLL5.js:218:12)
at async dev (file:///Users/ttomar/Documents/work/ai-component/spectrum-web-components/2nd-gen/node_modules/storybook/dist/bin/core.js:2734:3)
at async _Command.<anonymous> (file:///Users/ttomar/Documents/work/ai-component/spectrum-web-components/2nd-gen/node_modules/storybook/dist/bin/core.js:2803:92)
[11:45:55.841] [WARN] Broken build, fix the error above.
You may need to refresh the browser.
4 changes: 4 additions & 0 deletions 2nd-gen/packages/swc/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
"./global-elements.css": {
"default": "./dist/global-elements.css"
},
"./patterns/*/*": {
"types": "./dist/patterns/*/*/index.d.ts",
"import": "./dist/patterns/*/*/index.js"
},
"./utils/*": {
"types": "./dist/utils/*.d.ts",
"import": "./dist/utils/*.js"
Expand Down
60 changes: 60 additions & 0 deletions 2nd-gen/packages/swc/patterns/conversational-ai/README.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
import { Meta, Canvas } from '@storybook/addon-docs/blocks';
import * as ConversationTurnStories from './conversation-turn/stories/conversation-turn.stories';

<Meta title="Conversational AI/README" />

# Conversational AI

A complete set of building blocks for composing AI chat interfaces in 2nd-gen Spectrum Web Components. The pattern covers the full response lifecycle — from user input through AI generation, output, feedback, source attribution, and follow-up suggestions.

---

## Full example

<Canvas of={ConversationTurnStories.FullPattern} sourceState="none" />

---

## Components

| Element | Description |
| ----------------------- | -------------------------------------------------------------------------------------------------------------- |
| `swc-prompt-field` | Text input surface for entering or refining a prompt |
| `swc-upload-artifact` | Shared upload artifact primitive with `card` and `media` types, used in prompt-field and user-message surfaces |
| `swc-conversation-turn` | Column alignment for one participant turn; stack consecutive messages in one turn for grouped spacing |
| `swc-user-message` | User message bubble with slot-inferred copy/card/media layout |
| `swc-system-message` | System reply stack; **default slot** guidance is after the API table on the System message docs page |
| `swc-response-status` | Loading / generation-complete status indicator |
| `swc-message-feedback` | Positive / negative feedback control |
| `swc-message-sources` | Collapsible numbered list of response sources |
| `swc-suggestion` | Follow-up suggestion group with optional title and slotted suggestion items |
| `swc-suggestion-item` | Interactive chip action used inside `swc-suggestion`; emits bubbled selection event |

---

## Pattern structure

```text
patterns/
conversational-ai/
README.mdx
system-prose-demo.css
upload-artifact/
prompt-field/
user-message/
response-status/
message-feedback/
message-sources/
suggestion/
suggestion-item/
conversation-turn/
system-message/
utils/
icons/
```

---

## Tokens

All components resolve styles through `token()` calls that map to `var(--swc-*)` custom properties. No hard-coded colours or sizes — set the standard Spectrum token layer to theme the pattern globally.
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
/**
* Copyright 2026 Adobe. All rights reserved.
* This file is licensed to you under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. You may obtain a copy
* of the License at http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software distributed under
* the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR REPRESENTATIONS
* OF ANY KIND, either express or implied. See the License for the specific language
* governing permissions and limitations under the License.
*/

import { CSSResultArray, html, TemplateResult } from 'lit';
import { property } from 'lit/decorators.js';

import { SpectrumElement } from '@spectrum-web-components/core/element/index.js';

import styles from './conversation-turn.css';

/**
* Aligns one turn in a chat column: user content toward the end (right in LTR)
* and system content toward the start at full width.
*
* Slot **`swc-user-message`**, **`swc-system-message`**, or custom markup inside each turn
* Multiple slotted messages are stacked automatically with
* `--swc-conversation-turn-group-gap` spacing.
* User-message widths are applied by layout context (full screen, split rail,
* panel) while system content remains full width.
*
* @element swc-conversation-turn
* @slot - Turn body (message stack or bubble)
*/
export class ConversationTurn extends SpectrumElement {
/** `user` — end-aligned; `system` — start-aligned, full width of the column. */
@property({ type: String, reflect: true })
public type: 'system' | 'user' = 'user';

public static override get styles(): CSSResultArray {
return [styles];
}

protected override render(): TemplateResult {
return html`
<div class="swc-ConversationTurn">
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Sighted users can tell which turn is from the user and which one is from the AI. We need a way to communicate this to screenreaders as well.

<slot></slot>
</div>
`;
}
}
Loading