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 { .wire-next--chat-bubble { --wire-chat-color: var(--wire-component-color, var(--wire-color-primary)); --wire-chat-padding: 1rem; display: grid; width: 100%; min-width: 0; gap: 1rem; color: var(--wire-color-text); } .wire-next__chat-header h3, .wire-next__chat-header p, .wire-next__chat-content h4, .wire-next__chat-content p { margin: 0; } .wire-next__chat-header p { margin-top: 0.35rem; color: var(--wire-color-text-muted); } .wire-next__chat-thread { display: grid; min-width: 0; gap: 1.25rem; } .wire-next__chat-message { display: grid; width: min(78%, 34rem); min-width: 0; justify-self: start; gap: 0.4rem; } .wire-next__chat-message[data-direction="outgoing"] { justify-self: end; } .wire-next--chat-bubble[data-one-sided="true"] .wire-next__chat-message { justify-self: start; } .wire-next__chat-row { display: flex; min-width: 0; align-items: flex-start; gap: 0.75rem; } .wire-next__chat-message[data-direction="outgoing"] .wire-next__chat-row { flex-direction: row-reverse; } .wire-next--chat-bubble[data-one-sided="true"] .wire-next__chat-message[data-direction="outgoing"] .wire-next__chat-row { flex-direction: row; } .wire-next__chat-content { min-width: 0; padding: var(--wire-chat-padding); border: 1px solid var(--wire-color-border); border-radius: 1rem; background: var(--wire-color-surface-raised, var(--wire-color-surface)); color: var(--wire-color-text); cursor: pointer; } .wire-next__chat-content:focus-visible { outline: 2px solid var(--wire-chat-color); outline-offset: 2px; } .wire-next__chat-message[data-direction="outgoing"] .wire-next__chat-content { border-color: var(--wire-chat-color); background: var(--wire-chat-color); color: var(--wire-color-primary-contrast, #fff); } .wire-next__chat-message[data-direction="outgoing"] .wire-next__chat-content :is(h4, p, li, span) { color: inherit; } .wire-next__chat-content h4 { margin-bottom: 0.65rem; font-size: 1em; } .wire-next__chat-content p + p, .wire-next__chat-content p + nav { margin-top: 0.75rem; } .wire-next__chat-content ul { display: grid; margin: 0.55rem 0 0; padding-inline-start: 1.25rem; gap: 0.35rem; } .wire-next__chat-content nav { display: grid; margin-top: 0.75rem; gap: 0.3rem; } .wire-next__chat-content a { color: var(--wire-chat-color); font-weight: 650; text-decoration: none; } .wire-next__chat-message[data-direction="outgoing"] .wire-next__chat-content a { color: inherit; text-decoration: underline; } .wire-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(--wire-color-border); border-radius: 999px; background: var(--wire-color-surface-raised, var(--wire-color-surface)); color: var(--wire-color-text); cursor: pointer; place-items: center; } .wire-next__chat-avatar img { width: 100%; height: 100%; object-fit: cover; } .wire-next__chat-avatar:focus-visible { outline: 2px solid var(--wire-chat-color); outline-offset: 2px; } .wire-next__chat-meta { display: flex; align-items: center; gap: 0.3rem; padding-inline: calc(2.5rem + 0.75rem); color: var(--wire-color-text-muted); font-size: 0.78em; } .wire-next__chat-message[data-direction="outgoing"] .wire-next__chat-meta { justify-content: flex-end; } .wire-next__chat-meta[data-tone="danger"] { color: var(--wire-color-danger); } .wire-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) { .wire-next__chat-message { width: min(92%, 34rem); } .wire-next__chat-avatar { flex-basis: 2rem; width: 2rem; min-height: 2rem; } .wire-next__chat-meta { padding-inline: 0; } } } }