diff --git a/packages/apollo-react/src/material/components/ap-chat/components/input/tiptap/resource-chip-node-view.tsx b/packages/apollo-react/src/material/components/ap-chat/components/input/tiptap/resource-chip-node-view.tsx
index 9ca64bffdd..b71a400b48 100644
--- a/packages/apollo-react/src/material/components/ap-chat/components/input/tiptap/resource-chip-node-view.tsx
+++ b/packages/apollo-react/src/material/components/ap-chat/components/input/tiptap/resource-chip-node-view.tsx
@@ -5,17 +5,21 @@ import { type NodeViewProps, NodeViewWrapper } from '@tiptap/react';
import token, { Typography } from '@uipath/apollo-core';
import { useChatState } from '@uipath/apollo-react/chat/headless/providers/chat-state-provider';
import { CHAT_RESOURCE_CHIP_MAX_WIDTH } from '@uipath/apollo-react/chat/service';
+import { getReferenceChipColors } from '@uipath/apollo-wind/components/ui/reference-chip-colors';
import React from 'react';
import { fontByVariant } from '../../../utils/font-by-variant';
import { AutopilotChatActionButton } from '../../common/action-button';
import { AutopilotChatTooltip } from '../../common/tooltip';
+// Shared with apollo-wind's ReferenceChip so every reference chip uses the same token pair.
+const chipColors = getReferenceChipColors().valid;
+
const ChipContent = styled('span')<{ readonly?: boolean }>(({ readonly }) => ({
display: 'inline-flex',
alignItems: 'center',
padding: `0 ${token.Padding.PadS}`,
- backgroundColor: 'var(--color-info-background)',
- color: 'var(--color-info-text)',
+ backgroundColor: chipColors.background,
+ color: chipColors.text,
borderRadius: `calc(${token.Border.BorderRadiusL} * 2)`,
verticalAlign: 'middle',
...(!readonly && {
@@ -27,6 +31,7 @@ const ChipContent = styled('span')<{ readonly?: boolean }>(({ readonly }) => ({
const ChipIcon = styled('span')(() => ({
fontFamily: '"Material Icons Outlined"',
+ color: chipColors.icon,
fontSize: token.Icon.IconXs,
flexShrink: 0,
userSelect: 'none',
@@ -49,7 +54,7 @@ const ChipDeleteContainer = styled('span')<{ visible: boolean; compactMode: bool
transform: 'translateY(-50%)',
display: 'flex',
alignItems: 'center',
- backgroundColor: 'var(--color-info-background)',
+ backgroundColor: chipColors.background,
borderRadius: `calc(${token.Border.BorderRadiusL} * 2)`,
transition: 'opacity 0.15s ease-in-out',
diff --git a/packages/apollo-wind/README.md b/packages/apollo-wind/README.md
index 408e0e2b67..a404a11743 100644
--- a/packages/apollo-wind/README.md
+++ b/packages/apollo-wind/README.md
@@ -213,3 +213,28 @@ MIT - see [LICENSE](./LICENSE)
**Peer Dependencies:** React ≥18.0.0
Built with ❤️ by UiPath | Inspired by [shadcn/ui](https://ui.shadcn.com)
+
+## Reference Chip
+
+`ReferenceChip` displays selected variables, resources and connections with paired
+semantic background, text and icon colors. Find its API and state examples in
+Storybook under **Apollo Wind → Components → Data Display → Reference Chip**.
+The **Patterns → Code Editors → Editor Variables** example uses it through
+`PromptEditor`; existing editor consumers need no API changes.
+
+```tsx
+import { ReferenceChip } from '@uipath/apollo-wind';
+
+}
+ onRemove={clearConnection}
+ removeLabel="Remove Outlook connection"
+/>
+```
+
+The host supplies the icon, selection behavior and localized removal label.
+`readOnly` hides removal, `disabled` disables removal, `invalid` uses the paired
+error palette, and `selected` adds a visual outline. Keep removable chips outside
+other buttons. Inside a picker trigger, omit `onRemove` and use a separate clear
+button. Product connection fields must adopt this primitive to receive its styles.
diff --git a/packages/apollo-wind/src/components/ui/code-editors.stories.tsx b/packages/apollo-wind/src/components/ui/code-editors.stories.tsx
index 1d95172b43..ec109c1904 100644
--- a/packages/apollo-wind/src/components/ui/code-editors.stories.tsx
+++ b/packages/apollo-wind/src/components/ui/code-editors.stories.tsx
@@ -1205,7 +1205,7 @@ function EditorVariablesUsagePage() {
ariaLabel="Prompt"
/>
- Try both: choose{' '}
+ PromptEditor uses the shared ReferenceChip for inserted variables. Try both: choose{' '}
Insert → $vars → firstName above, or
type $ in the editor and pick from the
menu that appears.
diff --git a/packages/apollo-wind/src/components/ui/index.ts b/packages/apollo-wind/src/components/ui/index.ts
index 77ab25aa62..bb179a6529 100644
--- a/packages/apollo-wind/src/components/ui/index.ts
+++ b/packages/apollo-wind/src/components/ui/index.ts
@@ -54,6 +54,7 @@ export * from './message-scroller';
export * from './model-picker';
export * from './multi-select';
export * from './pagination';
+export * from './panel-tabs';
export * from './popover';
export * from './portal-container';
export * from './progress';
@@ -62,13 +63,15 @@ export * from './prompt-suggestions';
export * from './prompt-value-control';
export * from './quick-form-field';
export * from './radio-group';
+export { ReferenceChip, type ReferenceChipProps } from './reference-chip';
+export { getReferenceChipColors } from './reference-chip-colors';
export * from './resizable';
export * from './scroll-area';
export * from './search';
export * from './select';
export * from './separator';
-export * from './sidebar';
export * from './sheet';
+export * from './sidebar';
export * from './skeleton';
export * from './slider';
export * from './sonner';
@@ -78,7 +81,6 @@ export * from './stats-card';
export * from './stepper';
export * from './switch';
export * from './table';
-export * from './panel-tabs';
export * from './tabs';
export * from './textarea';
export * from './thinking-indicator';
diff --git a/packages/apollo-wind/src/components/ui/prompt-editor/components/MarkdownPreview.tsx b/packages/apollo-wind/src/components/ui/prompt-editor/components/MarkdownPreview.tsx
index ea187234c2..a248ff9664 100644
--- a/packages/apollo-wind/src/components/ui/prompt-editor/components/MarkdownPreview.tsx
+++ b/packages/apollo-wind/src/components/ui/prompt-editor/components/MarkdownPreview.tsx
@@ -1,6 +1,7 @@
import DOMPurify from 'dompurify';
import { Marked } from 'marked';
import { useMemo } from 'react';
+import { getReferenceChipColors } from '../../reference-chip-colors';
import { usePromptEditorConfig } from '../prompt-editor-config';
import { type PromptEditorToken } from '../types';
import { buildTokenIconSvgMarkup } from './token-icon-markup';
@@ -13,6 +14,7 @@ const marked = new Marked({ async: false, gfm: true, breaks: true });
* do), and without a per-component JS `.css` import (which doesn't resolve in the bundleless build).
* Scoped under `.prompt-editor-preview`; colors use design tokens.
*/
+const referenceColors = getReferenceChipColors().valid;
const MARKDOWN_PREVIEW_STYLES = `
.prompt-editor-preview { color: var(--color-foreground); }
.prompt-editor-preview-empty { color: var(--color-muted-foreground); }
@@ -39,8 +41,8 @@ const MARKDOWN_PREVIEW_STYLES = `
.prompt-editor-preview th { font-weight: 600; background-color: var(--color-muted); }
.prompt-editor-preview strong { font-weight: 700; }
.prompt-editor-preview em { font-style: italic; }
-.prompt-editor-preview .token-pill { display: inline-flex; align-items: center; gap: 3px; height: 20px; padding: 0 4px; border-radius: 4px; font-size: 13px; line-height: 20px; vertical-align: middle; background: var(--color-info-background); color: var(--color-info-text); }
-.prompt-editor-preview .token-pill svg { display: block; flex-shrink: 0; color: var(--color-info-icon); width: 14px; height: 14px; }
+.prompt-editor-preview .token-pill { display: inline-flex; align-items: center; gap: 3px; height: 20px; padding: 0 4px; border-radius: 4px; font-size: 13px; line-height: 20px; vertical-align: middle; background: ${referenceColors.background}; color: ${referenceColors.text}; }
+.prompt-editor-preview .token-pill svg { display: block; flex-shrink: 0; color: ${referenceColors.icon}; width: 14px; height: 14px; }
`;
/** Host override for a variable pill's preview rendering (icon markup and/or label). */
diff --git a/packages/apollo-wind/src/components/ui/prompt-editor/components/TokenPill.tsx b/packages/apollo-wind/src/components/ui/prompt-editor/components/TokenPill.tsx
index 2211ac4a25..86c3858539 100644
--- a/packages/apollo-wind/src/components/ui/prompt-editor/components/TokenPill.tsx
+++ b/packages/apollo-wind/src/components/ui/prompt-editor/components/TokenPill.tsx
@@ -1,8 +1,8 @@
import { Database, Paperclip, SquareFunction, Variable } from 'lucide-react';
import { memo } from 'react';
+import { ReferenceChip } from '../../reference-chip';
import { usePromptEditorConfig } from '../prompt-editor-config';
import type { PromptEditorDiffType, PromptEditorTokenType } from '../types';
-import { getPromptEditorTokenColors } from '../types';
/** Leading icon per token type — mirrors the SVG markup `MarkdownPreview` inlines for preview mode. */
const TOKEN_TYPE_ICON: Record<
@@ -41,83 +41,27 @@ const TokenPillBase = ({
onMouseDown,
}: TokenPillProps) => {
const { strings } = usePromptEditorConfig();
- const PROMPT_EDITOR_TOKEN_COLORS = getPromptEditorTokenColors();
- const colors =
- isInvalid && !diffType ? PROMPT_EDITOR_TOKEN_COLORS.invalid : PROMPT_EDITOR_TOKEN_COLORS.valid;
const Icon = TOKEN_TYPE_ICON[tokenType];
-
- const handleRemoveMouseDown = (e: React.MouseEvent) => {
- e.preventDefault();
- e.stopPropagation();
- };
-
- const handleRemoveClick = (e: React.MouseEvent) => {
- e.preventDefault();
- e.stopPropagation();
- onRemove?.();
- };
-
- const bgColor = diffType
- ? diffType === 'added'
- ? 'rgba(76, 175, 80, 0.15)'
- : 'rgba(244, 67, 54, 0.15)'
- : colors.background;
-
- const outerClassName = [
- 'relative inline-flex items-center align-middle gap-[3px] h-5 rounded px-1 text-[13px] leading-5 outline-offset-1',
- readonly ? 'cursor-default' : 'cursor-pointer',
- diffType === 'removed' ? 'line-through opacity-60' : '',
- isSelected ? 'z-10' : '',
- ]
- .filter(Boolean)
- .join(' ');
-
return (
- // biome-ignore lint/a11y/noStaticElementInteractions: the pill is a Lexical decorator chip; mousedown sets node selection. Keyboard selection is handled by Lexical at the editor root, and the chip exposes a focusable Remove button.
- }
+ onRemove={onRemove}
+ removeLabel={strings.removeToken}
+ readOnly={readonly}
+ invalid={isInvalid && !diffType}
+ selected={isSelected}
onMouseDown={onMouseDown}
- className={outerClassName}
- style={{
- backgroundColor: bgColor,
- outline: isSelected ? `2px solid ${colors.border}` : 'none',
- }}
- >
-
-
-
-
- {value}
-
- {!readonly && (
-
- )}
-
+ className={`${readonly ? 'cursor-default' : 'cursor-pointer'} ${diffType === 'removed' ? 'line-through opacity-60' : ''}`}
+ style={
+ diffType
+ ? {
+ backgroundColor:
+ diffType === 'added' ? 'rgba(76, 175, 80, 0.15)' : 'rgba(244, 67, 54, 0.15)',
+ }
+ : undefined
+ }
+ />
);
};
diff --git a/packages/apollo-wind/src/components/ui/prompt-editor/types.ts b/packages/apollo-wind/src/components/ui/prompt-editor/types.ts
index 2815c9e8a4..2fcf39d15b 100644
--- a/packages/apollo-wind/src/components/ui/prompt-editor/types.ts
+++ b/packages/apollo-wind/src/components/ui/prompt-editor/types.ts
@@ -1,3 +1,5 @@
+import { getReferenceChipColors } from '../reference-chip-colors';
+
export type PromptEditorTokenType = 'input' | 'output' | 'state' | 'resource' | 'text';
interface BaseToken {
@@ -89,23 +91,7 @@ export interface PromptEditorTokenColorConfig {
* Two-state palette: invalid = red, valid = blue. Backed by apollo-wind's semantic design tokens,
* which already resolve per light/dark theme via CSS — no JS theme detection needed.
*/
-export const getPromptEditorTokenColors = (): Record<
- 'valid' | 'invalid',
- PromptEditorTokenColorConfig
-> => ({
- valid: {
- background: 'var(--color-info-background)',
- border: 'var(--color-info-icon)',
- text: 'var(--color-info-text)',
- icon: 'var(--color-info-icon)',
- },
- invalid: {
- background: 'var(--color-error-background)',
- border: 'var(--color-error-icon)',
- text: 'var(--color-error-text)',
- icon: 'var(--color-error-icon)',
- },
-});
+export const getPromptEditorTokenColors = getReferenceChipColors;
/** The token-type label subset of `PromptEditorStrings` (structural, to avoid a config↔types cycle). */
export interface PromptEditorTokenTypeLabels {
diff --git a/packages/apollo-wind/src/components/ui/reference-chip-colors.ts b/packages/apollo-wind/src/components/ui/reference-chip-colors.ts
new file mode 100644
index 0000000000..27b29ea773
--- /dev/null
+++ b/packages/apollo-wind/src/components/ui/reference-chip-colors.ts
@@ -0,0 +1,15 @@
+/** Paired reference colors. Keep labels, icons and backgrounds on the same semantic palette. */
+export const getReferenceChipColors = () => ({
+ valid: {
+ background: 'var(--color-info-background)',
+ border: 'var(--color-info-icon)',
+ text: 'var(--color-info-text)',
+ icon: 'var(--color-info-icon)',
+ },
+ invalid: {
+ background: 'var(--color-error-background)',
+ border: 'var(--color-error-icon)',
+ text: 'var(--color-error-text)',
+ icon: 'var(--color-error-icon)',
+ },
+});
diff --git a/packages/apollo-wind/src/components/ui/reference-chip.stories.tsx b/packages/apollo-wind/src/components/ui/reference-chip.stories.tsx
new file mode 100644
index 0000000000..3717b7f1a9
--- /dev/null
+++ b/packages/apollo-wind/src/components/ui/reference-chip.stories.tsx
@@ -0,0 +1,219 @@
+import type { Meta, StoryObj } from '@storybook/react-vite';
+import { Check, Database, Mail, Variable, X } from 'lucide-react';
+import { type ReactNode, useState } from 'react';
+import { Button } from './button';
+import { ReferenceChip } from './reference-chip';
+import { getReferenceChipColors } from './reference-chip-colors';
+
+const meta = {
+ title: 'Components/Data Display/Reference Chip',
+ component: ReferenceChip,
+ tags: ['autodocs'],
+ decorators: [
+ (Story) => (
+
+
+
+ ),
+ ],
+ args: { label: 'vars.firstName', icon: },
+ parameters: {
+ docs: {
+ description: {
+ component: `A compact reference to a variable, resource or connection. PromptEditor uses this primitive through TokenPill. The connection picker owns its popup and selection behavior; ReferenceChip owns the selected value's appearance.
+
+Colors come from existing semantic tokens, always as a pair from one family. Valid references use --color-info-background with --color-info-text and --color-info-icon. Invalid references use --color-error-background with --color-error-text and --color-error-icon. The selected outline uses the icon token of the same family. getReferenceChipColors() returns these values for hosts that cannot render the component. Do not fill a chip with a primary or accent color and pick a foreground separately: that is how low-contrast chips happen. Branded icons may retain their colors. The Themes story shows every theme side by side.
+
+Pass onRemove to expose a keyboard-accessible remove button and removeLabel for localization. readOnly hides removal; disabled disables it. selected is visual only: the host owns selection semantics. Keep a removable chip outside other buttons. Inside a picker trigger, omit onRemove and provide a separate clear button.
+
+Import { ReferenceChip } from '@uipath/apollo-wind'. Existing PromptEditor consumers inherit this treatment without changing their API. Product connection fields must adopt the component; this does not update external product repositories.`,
+ },
+ },
+ },
+} satisfies Meta;
+export default meta;
+type Story = StoryObj;
+
+export const Default: Story = {};
+
+export const States: Story = {
+ render: () => (
+