component ChatBubble { outputs { action(payload: { action: boolean; item: string | number | boolean | null | object; index: number }) messageClick(payload: { item: string | number | boolean | null | object; index: number; direction: string }) avatarClick(payload: { item: string | number | boolean | null | object; index: number; direction: string }) linkClick(payload: { link: string | number | boolean | null | object; item: string | number | boolean | null | object; index: number }) } props { size: string = "default" color: string = "primary" title: string = "" description: string = "" items: unknown[] = [] oneSided: boolean = false showAvatars: boolean = false showMetadata: boolean = false ariaLabel: string = "Conversation" variant: string = "default" class: string = "" } functions { shared function messageDirection(item) { return item.direction === "outgoing" ? "outgoing" : "incoming" } client function selectMessage(item, index) { output.messageClick({ item: item, index: index, direction: messageDirection(item) }) } client function selectAvatar(sourceEvent, item, index) { sourceEvent.stopPropagation() output.avatarClick({ item: item, index: index, direction: messageDirection(item) }) } client function selectLink(sourceEvent, link, item, index) { sourceEvent.stopPropagation() output.linkClick({ link: link, item: item, index: index }) } client function selectAction(sourceEvent, item, index) { sourceEvent.stopPropagation() output.action({ action: item.action || "retry", item: item, index: index }) } } view {
{#if title || description}
{#if title}

{title}

{/if} {#if description}

{description}

{/if}
{/if} {#if items.length}
{#each items as item, index}
{#if showAvatars && (item.avatarSrc || item.avatarFallback)} {/if}
{#if item.title}

{item.title}

{/if} {#if item.text}

{item.text}

{/if} {#if item.bullets && item.bullets.length}
    {#each item.bullets as bullet}
  • {bullet}
  • {/each}
{/if} {#if item.links && item.links.length} {/if}
{#if showMetadata && (item.timestamp || item.status || item.actionLabel)}
{#if item.statusIcon}{/if} {#if item.status}{item.status}{/if} {#if item.timestamp}{/if} {#if item.actionLabel} {/if}
{/if}
{/each}
{/if}
} style { .wrn-next--chat-bubble.wrn-component--size-sm { --wrn-chat-padding: 0.75rem; font-size: 0.875rem; } .wrn-next--chat-bubble.wrn-component--size-lg { --wrn-chat-padding: 1.25rem; font-size: 1.0625rem; } .wrn-next--chat-bubble { --wrn-chat-color: var(--wrn-component-color, var(--wrn-color-primary)); --wrn-chat-padding: 1rem; display: grid; width: 100%; min-width: 0; gap: 1rem; color: var(--wrn-color-text); } .wrn-next__chat-header h3, .wrn-next__chat-header p, .wrn-next__chat-content h4, .wrn-next__chat-content p { margin: 0; } .wrn-next__chat-header p { margin-top: 0.35rem; color: var(--wrn-color-text-muted); } .wrn-next__chat-thread { display: grid; min-width: 0; gap: 1.25rem; } .wrn-next__chat-message { display: grid; width: min(78%, 34rem); min-width: 0; justify-self: start; gap: 0.4rem; } .wrn-next__chat-message[data-direction="outgoing"] { justify-self: end; } .wrn-next--chat-bubble[data-one-sided="true"] .wrn-next__chat-message { justify-self: start; } .wrn-next__chat-row { display: flex; min-width: 0; align-items: flex-start; gap: 0.75rem; } .wrn-next__chat-message[data-direction="outgoing"] .wrn-next__chat-row { flex-direction: row-reverse; } .wrn-next--chat-bubble[data-one-sided="true"] .wrn-next__chat-message[data-direction="outgoing"] .wrn-next__chat-row { flex-direction: row; } .wrn-next__chat-content { min-width: 0; padding: var(--wrn-chat-padding); border: 1px solid var(--wrn-color-border); border-radius: 1rem; background: var(--wrn-color-surface-raised, var(--wrn-color-surface)); color: var(--wrn-color-text); cursor: pointer; } .wrn-next__chat-content:focus-visible { outline: 2px solid var(--wrn-chat-color); outline-offset: 2px; } .wrn-next__chat-message[data-direction="outgoing"] .wrn-next__chat-content { border-color: var(--wrn-chat-color); background: var(--wrn-chat-color); color: var(--wrn-color-primary-contrast, #fff); } .wrn-next__chat-message[data-direction="outgoing"] .wrn-next__chat-content :is(h4, p, li, span) { color: inherit; } .wrn-next__chat-content h4 { margin-bottom: 0.65rem; font-size: 1em; } .wrn-next__chat-content p + p, .wrn-next__chat-content p + nav { margin-top: 0.75rem; } .wrn-next__chat-content ul { display: grid; margin: 0.55rem 0 0; padding-inline-start: 1.25rem; gap: 0.35rem; } .wrn-next__chat-content nav { display: grid; margin-top: 0.75rem; gap: 0.3rem; } .wrn-next__chat-content a { color: var(--wrn-chat-color); font-weight: 650; text-decoration: none; } .wrn-next__chat-message[data-direction="outgoing"] .wrn-next__chat-content a { color: inherit; text-decoration: underline; } .wrn-next__chat-avatar { display: grid; flex: 0 0 2.5rem; width: 2.5rem; min-height: 2.5rem; overflow: hidden; padding: 0; border: 1px solid var(--wrn-color-border); border-radius: 999px; background: var(--wrn-color-surface-raised, var(--wrn-color-surface)); color: var(--wrn-color-text); cursor: pointer; place-items: center; } .wrn-next__chat-avatar img { width: 100%; height: 100%; object-fit: cover; } .wrn-next__chat-avatar:focus-visible { outline: 2px solid var(--wrn-chat-color); outline-offset: 2px; } .wrn-next__chat-meta { display: flex; align-items: center; gap: 0.3rem; padding-inline: calc(2.5rem + 0.75rem); color: var(--wrn-color-text-muted); font-size: 0.78em; } .wrn-next__chat-message[data-direction="outgoing"] .wrn-next__chat-meta { justify-content: flex-end; } .wrn-next__chat-meta[data-tone="danger"] { color: var(--wrn-color-danger); } .wrn-next__chat-meta button { padding: 0; border: 0; background: transparent; color: inherit; font: inherit; font-weight: 700; cursor: pointer; text-decoration: underline; } @media (max-width: 640px) { .wrn-next__chat-message { width: min(92%, 34rem); } .wrn-next__chat-avatar { flex-basis: 2rem; width: 2rem; min-height: 2rem; } .wrn-next__chat-meta { padding-inline: 0; } } /* Shared component foundation. */ .wrn-component { --wrn-component-color: var(--wrn-color-primary); --wrn-component-scale: 1; margin: 0; color: var(--wrn-color-text); font-family: var(--wrn-font-sans, inherit); } .wrn-component--color-primary { --wrn-component-color: var(--wrn-color-primary); } .wrn-component--color-secondary { --wrn-component-color: var(--wrn-color-secondary); } .wrn-component--color-success { --wrn-component-color: var(--wrn-color-success); } .wrn-component--color-warning { --wrn-component-color: var(--wrn-color-warning); } .wrn-component--color-danger { --wrn-component-color: var(--wrn-color-danger); } .wrn-component--color-info { --wrn-component-color: var(--wrn-color-info); } .wrn-component--size-xs { --wrn-component-scale: 0.78; } .wrn-component--size-sm { --wrn-component-scale: 0.88; } .wrn-component--size-default, .wrn-component--size-md { --wrn-component-scale: 1; } .wrn-component--size-lg { --wrn-component-scale: 1.14; } .wrn-component--size-xl { --wrn-component-scale: 1.28; } .wrn-component:not(.wrn-btn) { font-size: calc(1em * var(--wrn-component-scale)); } .wrn-component :is(a, button, input, select, textarea):focus-visible { outline-color: var(--wrn-component-color); } .wrn-component p { margin: 0; color: var(--wrn-color-muted); line-height: 1.6; } } }