import { n as __exportAll } from "./chunk-B-1-B7_t.js";
import { n as cn } from "./utils-DXzSsU1e.js";
import { i as Avatar_default, n as AvatarImage_default, r as AvatarFallback_default } from "./avatar-DlTHFl6x.js";
import { n as Badge_default } from "./badge-BbQrSqE-.js";
import { n as Button_default } from "./button-B9CnnuTu.js";
import { Fragment, computed, createBlock, createCommentVNode, createElementBlock, createElementVNode, createTextVNode, createVNode, defineComponent, normalizeClass, openBlock, ref, renderList, resolveDynamicComponent, toDisplayString, unref, watch, withCtx } from "vue";
import { cva } from "class-variance-authority";
//#region src/components/compositions/elements/code/ChatMessage.vue?vue&type=script&setup=true&lang.ts
var _hoisted_1 = [
	"data-role",
	"data-align",
	"data-variant"
];
var _hoisted_2 = {
	key: 0,
	class: "font-medium",
	"data-testid": "chat-message-author"
};
var _hoisted_3 = {
	key: 1,
	class: "flex items-center gap-1 py-1",
	"data-testid": "chat-message-pending",
	"aria-label": "Typing"
};
var _hoisted_4 = ["innerHTML"];
var _hoisted_5 = {
	key: 3,
	class: "whitespace-pre-wrap leading-snug",
	"data-testid": "chat-message-body"
};
var _hoisted_6 = {
	key: 0,
	class: "text-xs text-destructive",
	"data-testid": "chat-message-error"
};
var ChatMessage_vue_vue_type_script_setup_true_lang_default = /* @__PURE__ */ defineComponent({
	__name: "ChatMessage",
	props: {
		message: {},
		role: { default: "user" },
		authorName: {},
		authorAvatarUrl: {},
		authorAvatarFallback: {},
		timestamp: {},
		pending: {
			type: Boolean,
			default: false
		},
		error: {},
		actions: { default: () => [] },
		align: { default: "auto" },
		variant: {},
		allowHtml: {
			type: Boolean,
			default: false
		},
		classList: {}
	},
	emits: ["action"],
	setup(__props, { emit: __emit }) {
		/**
		* Generic chat-message bubble composition.
		*
		* Display-only — renders a single chat bubble in the style of Slack /
		* Discord / iMessage. Side-aligned by role, color-tinted by variant,
		* optional avatar, role badge, timestamp, typing indicator, inline
		* error, and a row of ghost-button actions.
		*
		* No platform-specific integration. Form-data store is not touched.
		*
		*   <ChatMessage
		*     role="assistant"
		*     authorName="Assistant"
		*     message="Hello, how can I help?"
		*     :timestamp="new Date()"
		*   />
		*/
		const props = __props;
		const emit = __emit;
		const resolvedAlign = computed(() => {
			if (props.align === "start" || props.align === "end") return props.align;
			return props.role === "user" ? "end" : "start";
		});
		const isEnd = computed(() => resolvedAlign.value === "end");
		const ROLE_VARIANT = {
			user: "accent",
			assistant: "muted",
			system: "default",
			tool: "muted"
		};
		const resolvedVariant = computed(() => {
			if (props.variant) return props.variant;
			return ROLE_VARIANT[props.role] ?? "default";
		});
		const bubbleVariants = cva("max-w-[36rem] min-w-0 break-words rounded-2xl border px-3 py-2 text-sm shadow-sm", {
			variants: {
				variant: {
					default: "bg-card text-card-foreground border-border",
					muted: "bg-muted text-foreground border-transparent",
					accent: "bg-primary text-primary-foreground border-transparent",
					destructive: "bg-destructive text-destructive-foreground border-transparent"
				},
				align: {
					start: "rounded-tl-sm",
					end: "rounded-tr-sm"
				}
			},
			defaultVariants: {
				variant: "default",
				align: "start"
			}
		});
		const bubbleClass = computed(() => bubbleVariants({
			variant: resolvedVariant.value,
			align: resolvedAlign.value
		}));
		const derivedAvatarFallback = computed(() => {
			if (props.authorAvatarFallback) return props.authorAvatarFallback;
			const source = (props.authorName ?? props.role ?? "?").trim();
			return source ? source.charAt(0).toUpperCase() : "?";
		});
		const formattedTimestamp = computed(() => {
			const ts = props.timestamp;
			if (!ts) return "";
			const date = ts instanceof Date ? ts : new Date(ts);
			if (Number.isNaN(date.getTime())) return "";
			try {
				return new Intl.DateTimeFormat(void 0, {
					hour: "numeric",
					minute: "2-digit"
				}).format(date);
			} catch {
				return date.toISOString();
			}
		});
		const rootClass = computed(() => {
			const cl = props.classList;
			if (!cl) return "";
			return Array.isArray(cl) ? cl.join(" ") : cl;
		});
		const showRoleBadge = computed(() => {
			return Boolean(props.role) && props.role !== "user";
		});
		const ActionIcons = ref({});
		function toPascalCase(input) {
			return input.replace(/[-_\s]+(.)?/g, (_, ch) => ch ? ch.toUpperCase() : "").replace(/^(.)/, (m) => m.toUpperCase());
		}
		async function loadActionIcons(actions) {
			const needed = actions.filter((a) => a.icon).map((a) => a.icon);
			if (needed.length === 0) return;
			const registry = await import("@lucide/vue");
			const next = { ...ActionIcons.value };
			for (const raw of needed) next[raw] = registry[toPascalCase(raw)] ?? null;
			ActionIcons.value = next;
		}
		watch(() => props.actions, (next) => {
			loadActionIcons(next ?? []);
		}, {
			immediate: true,
			deep: true
		});
		function onAction(id) {
			emit("action", { id });
		}
		return (_ctx, _cache) => {
			return openBlock(), createElementBlock("div", {
				class: normalizeClass(unref(cn)("flex w-full items-end gap-2", isEnd.value ? "justify-end" : "justify-start", rootClass.value)),
				"data-role": props.role,
				"data-align": resolvedAlign.value,
				"data-variant": resolvedVariant.value,
				"data-testid": "chat-message"
			}, [
				!isEnd.value ? (openBlock(), createBlock(unref(Avatar_default), {
					key: 0,
					size: "sm",
					class: "mb-1",
					"data-testid": "chat-message-avatar"
				}, {
					default: withCtx(() => [props.authorAvatarUrl ? (openBlock(), createBlock(unref(AvatarImage_default), {
						key: 0,
						src: props.authorAvatarUrl,
						alt: props.authorName ?? props.role
					}, null, 8, ["src", "alt"])) : createCommentVNode("", true), createVNode(unref(AvatarFallback_default), null, {
						default: withCtx(() => [createTextVNode(toDisplayString(derivedAvatarFallback.value), 1)]),
						_: 1
					})]),
					_: 1
				})) : createCommentVNode("", true),
				createElementVNode("div", { class: normalizeClass(unref(cn)("flex min-w-0 flex-col gap-1", isEnd.value ? "items-end" : "items-start")) }, [
					createElementVNode("div", {
						class: normalizeClass(bubbleClass.value),
						"data-testid": "chat-message-bubble"
					}, [props.authorName || showRoleBadge.value || formattedTimestamp.value ? (openBlock(), createElementBlock("div", {
						key: 0,
						class: normalizeClass(unref(cn)("mb-1 flex w-full items-center gap-2 text-xs", isEnd.value ? "flex-row-reverse" : "flex-row"))
					}, [
						props.authorName ? (openBlock(), createElementBlock("span", _hoisted_2, toDisplayString(props.authorName), 1)) : createCommentVNode("", true),
						showRoleBadge.value ? (openBlock(), createBlock(unref(Badge_default), {
							key: 1,
							variant: "outline",
							size: "sm",
							"data-testid": "chat-message-role-badge"
						}, {
							default: withCtx(() => [createTextVNode(toDisplayString(props.role), 1)]),
							_: 1
						})) : createCommentVNode("", true),
						formattedTimestamp.value ? (openBlock(), createElementBlock("span", {
							key: 2,
							class: normalizeClass(unref(cn)("text-[11px] opacity-70", resolvedVariant.value === "accent" || resolvedVariant.value === "destructive" ? "" : "text-muted-foreground", isEnd.value ? "mr-auto" : "ml-auto")),
							"data-testid": "chat-message-timestamp"
						}, toDisplayString(formattedTimestamp.value), 3)) : createCommentVNode("", true)
					], 2)) : createCommentVNode("", true), props.pending ? (openBlock(), createElementBlock("div", _hoisted_3, [..._cache[0] || (_cache[0] = [
						createElementVNode("span", { class: "size-1.5 animate-bounce rounded-full bg-current opacity-60" }, null, -1),
						createElementVNode("span", { class: "size-1.5 animate-bounce rounded-full bg-current opacity-60 [animation-delay:150ms]" }, null, -1),
						createElementVNode("span", { class: "size-1.5 animate-bounce rounded-full bg-current opacity-60 [animation-delay:300ms]" }, null, -1)
					])])) : props.allowHtml && props.message ? (openBlock(), createElementBlock("div", {
						key: 2,
						class: "whitespace-pre-wrap leading-snug",
						"data-testid": "chat-message-body",
						innerHTML: props.message
					}, null, 8, _hoisted_4)) : props.message ? (openBlock(), createElementBlock("div", _hoisted_5, toDisplayString(props.message), 1)) : createCommentVNode("", true)], 2),
					props.error ? (openBlock(), createElementBlock("p", _hoisted_6, toDisplayString(props.error), 1)) : createCommentVNode("", true),
					props.actions && props.actions.length > 0 ? (openBlock(), createElementBlock("div", {
						key: 1,
						class: normalizeClass(unref(cn)("flex flex-wrap gap-1", isEnd.value ? "justify-end" : "justify-start")),
						"data-testid": "chat-message-actions"
					}, [(openBlock(true), createElementBlock(Fragment, null, renderList(props.actions, (action) => {
						return openBlock(), createBlock(unref(Button_default), {
							key: action.id,
							type: "button",
							variant: "ghost",
							size: "sm",
							"data-action-id": action.id,
							onClick: ($event) => onAction(action.id)
						}, {
							default: withCtx(() => [action.icon && ActionIcons.value[action.icon] ? (openBlock(), createBlock(resolveDynamicComponent(action.icon ? ActionIcons.value[action.icon] : null), { key: 0 })) : createCommentVNode("", true), createElementVNode("span", null, toDisplayString(action.label), 1)]),
							_: 2
						}, 1032, ["data-action-id", "onClick"]);
					}), 128))], 2)) : createCommentVNode("", true)
				], 2),
				isEnd.value ? (openBlock(), createBlock(unref(Avatar_default), {
					key: 1,
					size: "sm",
					class: "mb-1",
					"data-testid": "chat-message-avatar"
				}, {
					default: withCtx(() => [props.authorAvatarUrl ? (openBlock(), createBlock(unref(AvatarImage_default), {
						key: 0,
						src: props.authorAvatarUrl,
						alt: props.authorName ?? props.role
					}, null, 8, ["src", "alt"])) : createCommentVNode("", true), createVNode(unref(AvatarFallback_default), null, {
						default: withCtx(() => [createTextVNode(toDisplayString(derivedAvatarFallback.value), 1)]),
						_: 1
					})]),
					_: 1
				})) : createCommentVNode("", true)
			], 10, _hoisted_1);
		};
	}
});
//#endregion
//#region src/components/compositions/elements/code/ChatMessage.vue
var ChatMessage_exports = /* @__PURE__ */ __exportAll({ default: () => ChatMessage_default });
var ChatMessage_default = ChatMessage_vue_vue_type_script_setup_true_lang_default;
//#endregion
export { ChatMessage_exports as n, ChatMessage_default as t };

//# sourceMappingURL=ChatMessage-DHcQCrR7.js.map