@xpert-ai/chatkit-web-component 0.2.1 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -47,7 +47,7 @@ var __privateGet = (obj, member, getter) => (__accessCheck(obj, member, "read fr
47
47
  var __privateAdd = (obj, member, value) => member.has(obj) ? __typeError("Cannot add the same private member more than once") : member instanceof WeakSet ? member.add(obj) : member.set(obj, value);
48
48
  var __privateSet = (obj, member, value, setter) => (__accessCheck(obj, member, "write to private field"), setter ? setter.call(obj, value) : member.set(obj, value), value);
49
49
  var __privateMethod = (obj, member, method) => (__accessCheck(obj, member, "access private method"), method);
50
- var _a, _b, _setTrainingOptOut_dec, _hideHistory_dec, _showHistory_dec, _sendCustomAction_dec, _shareThread_dec, _setThreadId_dec, _setComposerValue_dec, _sendUserMessage_dec, _fetchUpdates_dec, _focusComposer_dec, _c, _opts, _frameUrl, _frame, _wrapper, _shadow, _resolveLoaded, _loaded, _messenger, _ChatKitElementBase_instances, emitAndThrow_fn, setOptionsDataAttributes_fn, getFrameUrl_fn, setFrameUrl_fn, consumeFrameUrl_fn, _handleFrameLoad, _initialized, maybeInit_fn, _init;
50
+ var _a, _b, _setTrainingOptOut_dec, _hideHistory_dec, _showHistory_dec, _sendCustomAction_dec, _shareThread_dec, _setThreadId_dec, _setComposerValue_dec, _sendUserMessage_dec, _fetchUpdates_dec, _focusComposer_dec, _c, _opts, _frameUrl, _frame, _wrapper, _launcherCloseButton, _launcherOpen, _framePetOptionsOverride, _petClosedByContextMenu, _shadow, _petOverlay, _resolveLoaded, _loaded, _messenger, _ChatKitElementBase_instances, emitAndThrow_fn, setOptionsDataAttributes_fn, getDisplayMode_fn, getConfiguredPetOptions_fn, getOverlayPetOptions_fn, resolvePetAssetUrl_fn, resolveOverlayPetOptions_fn, getFrameOptions_fn, setLauncherOpen_fn, handlePetActivate_fn, handlePetClose_fn, handlePetReply_fn, handlePetThreadSummaryActivate_fn, _handleLauncherClose, getFrameUrl_fn, setFrameUrl_fn, consumeFrameUrl_fn, _handleFrameLoad, _initialized, maybeInit_fn, _init;
51
51
  class EventEmitter {
52
52
  constructor() {
53
53
  __publicField(this, "callbacks", /* @__PURE__ */ new Map());
@@ -865,6 +865,252 @@ class ChatFrameMessenger extends BaseMessenger {
865
865
  return true;
866
866
  }
867
867
  }
868
+ const PET_ANIMATION_NAMES = [
869
+ "idle",
870
+ "running-right",
871
+ "running-left",
872
+ "waving",
873
+ "jumping",
874
+ "failed",
875
+ "waiting",
876
+ "running",
877
+ "review"
878
+ ];
879
+ const petSpriteAtlas = {
880
+ columns: 8,
881
+ rows: 9,
882
+ cellWidth: 192,
883
+ cellHeight: 208,
884
+ animations: {
885
+ idle: {
886
+ row: 0,
887
+ frames: 6,
888
+ frameDurations: [280, 110, 110, 140, 140, 320]
889
+ },
890
+ "running-right": {
891
+ row: 1,
892
+ frames: 8,
893
+ frameDurations: [120, 120, 120, 120, 120, 120, 120, 220]
894
+ },
895
+ "running-left": {
896
+ row: 2,
897
+ frames: 8,
898
+ frameDurations: [120, 120, 120, 120, 120, 120, 120, 220]
899
+ },
900
+ waving: {
901
+ row: 3,
902
+ frames: 4,
903
+ frameDurations: [140, 140, 140, 280]
904
+ },
905
+ jumping: {
906
+ row: 4,
907
+ frames: 5,
908
+ frameDurations: [140, 140, 140, 140, 280]
909
+ },
910
+ failed: {
911
+ row: 5,
912
+ frames: 8,
913
+ frameDurations: [140, 140, 140, 140, 140, 140, 140, 240]
914
+ },
915
+ waiting: {
916
+ row: 6,
917
+ frames: 6,
918
+ frameDurations: [150, 150, 150, 150, 150, 260]
919
+ },
920
+ running: {
921
+ row: 7,
922
+ frames: 6,
923
+ frameDurations: [120, 120, 120, 120, 120, 220]
924
+ },
925
+ review: {
926
+ row: 8,
927
+ frames: 6,
928
+ frameDurations: [150, 150, 150, 150, 150, 280]
929
+ }
930
+ }
931
+ };
932
+ const DEFAULT_PET_BOUNDS_PADDING = {
933
+ top: 0,
934
+ right: 0,
935
+ bottom: 0,
936
+ left: 0
937
+ };
938
+ const DEFAULT_PET_STORAGE_KEY = "chatkit:pet:position:v1";
939
+ const DEFAULT_PET_SPRITESHEET_URL = "/pets/boba/spritesheet.webp";
940
+ const DEFAULT_PET_CHARACTER = {
941
+ type: "sprite-atlas",
942
+ src: DEFAULT_PET_SPRITESHEET_URL
943
+ };
944
+ const DEFAULT_POSITION = {
945
+ pin: "bottom-right",
946
+ draggable: true,
947
+ scale: 0.25,
948
+ persist: true,
949
+ zIndex: 40
950
+ };
951
+ function mergeFrameAnimation(base, override) {
952
+ return {
953
+ row: (override == null ? void 0 : override.row) ?? base.row,
954
+ frames: (override == null ? void 0 : override.frames) ?? base.frames,
955
+ frameDurations: (override == null ? void 0 : override.frameDurations) && override.frameDurations.length > 0 ? override.frameDurations : base.frameDurations
956
+ };
957
+ }
958
+ function mergePetSpriteAtlas(override) {
959
+ var _a2;
960
+ const animations = {};
961
+ for (const name of PET_ANIMATION_NAMES) {
962
+ animations[name] = mergeFrameAnimation(
963
+ petSpriteAtlas.animations[name],
964
+ (_a2 = override == null ? void 0 : override.animations) == null ? void 0 : _a2[name]
965
+ );
966
+ }
967
+ return {
968
+ columns: (override == null ? void 0 : override.columns) ?? petSpriteAtlas.columns,
969
+ rows: (override == null ? void 0 : override.rows) ?? petSpriteAtlas.rows,
970
+ cellWidth: (override == null ? void 0 : override.cellWidth) ?? petSpriteAtlas.cellWidth,
971
+ cellHeight: (override == null ? void 0 : override.cellHeight) ?? petSpriteAtlas.cellHeight,
972
+ animations
973
+ };
974
+ }
975
+ function normalizeCharacter(character) {
976
+ if (!character) {
977
+ return DEFAULT_PET_CHARACTER;
978
+ }
979
+ if (character.src) {
980
+ return character;
981
+ }
982
+ return DEFAULT_PET_CHARACTER;
983
+ }
984
+ function normalizePetOptions(pet) {
985
+ if (!pet) {
986
+ return null;
987
+ }
988
+ if (pet === true) {
989
+ return {
990
+ character: DEFAULT_PET_CHARACTER,
991
+ position: DEFAULT_POSITION,
992
+ behavior: "auto",
993
+ ariaLabel: "Animated pet",
994
+ imageRendering: "auto"
995
+ };
996
+ }
997
+ if (pet.enabled === false) {
998
+ return null;
999
+ }
1000
+ return {
1001
+ character: normalizeCharacter(pet.character),
1002
+ position: {
1003
+ ...DEFAULT_POSITION,
1004
+ ...pet.position
1005
+ },
1006
+ behavior: pet.behavior ?? "auto",
1007
+ ariaLabel: pet.ariaLabel ?? "Animated pet",
1008
+ imageRendering: pet.imageRendering ?? "auto"
1009
+ };
1010
+ }
1011
+ function resolvePetCharacter(character) {
1012
+ if (!character.src) {
1013
+ return null;
1014
+ }
1015
+ return {
1016
+ kind: "atlas",
1017
+ src: character.src,
1018
+ atlas: mergePetSpriteAtlas(character.atlas)
1019
+ };
1020
+ }
1021
+ function normalizeBoundsPadding(value) {
1022
+ if (typeof value === "number") {
1023
+ return {
1024
+ top: value,
1025
+ right: value,
1026
+ bottom: value,
1027
+ left: value
1028
+ };
1029
+ }
1030
+ return {
1031
+ top: (value == null ? void 0 : value.top) ?? DEFAULT_PET_BOUNDS_PADDING.top,
1032
+ right: (value == null ? void 0 : value.right) ?? DEFAULT_PET_BOUNDS_PADDING.right,
1033
+ bottom: (value == null ? void 0 : value.bottom) ?? DEFAULT_PET_BOUNDS_PADDING.bottom,
1034
+ left: (value == null ? void 0 : value.left) ?? DEFAULT_PET_BOUNDS_PADDING.left
1035
+ };
1036
+ }
1037
+ function clampPetPosition(position, size, viewport, padding) {
1038
+ const minX = padding.left;
1039
+ const minY = padding.top;
1040
+ const maxX = Math.max(minX, viewport.width - size.width - padding.right);
1041
+ const maxY = Math.max(minY, viewport.height - size.height - padding.bottom);
1042
+ return {
1043
+ x: Math.min(maxX, Math.max(minX, position.x)),
1044
+ y: Math.min(maxY, Math.max(minY, position.y))
1045
+ };
1046
+ }
1047
+ function getPinnedPetPosition(pin, size, viewport, padding) {
1048
+ const horizontalCenter = (viewport.width - size.width) / 2;
1049
+ const verticalCenter = (viewport.height - size.height) / 2;
1050
+ const right = viewport.width - size.width - padding.right;
1051
+ const bottom = viewport.height - size.height - padding.bottom;
1052
+ switch (pin) {
1053
+ case "top-left":
1054
+ return clampPetPosition(
1055
+ { x: padding.left, y: padding.top },
1056
+ size,
1057
+ viewport,
1058
+ padding
1059
+ );
1060
+ case "top":
1061
+ return clampPetPosition(
1062
+ { x: horizontalCenter, y: padding.top },
1063
+ size,
1064
+ viewport,
1065
+ padding
1066
+ );
1067
+ case "top-right":
1068
+ return clampPetPosition(
1069
+ { x: right, y: padding.top },
1070
+ size,
1071
+ viewport,
1072
+ padding
1073
+ );
1074
+ case "left":
1075
+ return clampPetPosition(
1076
+ { x: padding.left, y: verticalCenter },
1077
+ size,
1078
+ viewport,
1079
+ padding
1080
+ );
1081
+ case "center":
1082
+ return clampPetPosition(
1083
+ { x: horizontalCenter, y: verticalCenter },
1084
+ size,
1085
+ viewport,
1086
+ padding
1087
+ );
1088
+ case "right":
1089
+ return clampPetPosition(
1090
+ { x: right, y: verticalCenter },
1091
+ size,
1092
+ viewport,
1093
+ padding
1094
+ );
1095
+ case "bottom-left":
1096
+ return clampPetPosition(
1097
+ { x: padding.left, y: bottom },
1098
+ size,
1099
+ viewport,
1100
+ padding
1101
+ );
1102
+ case "bottom":
1103
+ return clampPetPosition(
1104
+ { x: horizontalCenter, y: bottom },
1105
+ size,
1106
+ viewport,
1107
+ padding
1108
+ );
1109
+ case "bottom-right":
1110
+ default:
1111
+ return clampPetPosition({ x: right, y: bottom }, size, viewport, padding);
1112
+ }
1113
+ }
868
1114
  const removeMethods = (obj, seen = /* @__PURE__ */ new WeakSet()) => {
869
1115
  if (typeof obj === "function") return "[ChatKitMethod]";
870
1116
  if (typeof obj !== "object" || obj === null) return obj;
@@ -883,6 +1129,1346 @@ const removeMethods = (obj, seen = /* @__PURE__ */ new WeakSet()) => {
883
1129
  }
884
1130
  return result;
885
1131
  };
1132
+ const DRAG_DIRECTION_THRESHOLD_PX = 2;
1133
+ const PET_BASE_RENDER_SCALE = 0.5;
1134
+ const PET_FRAME_DURATION_MULTIPLIER = 1.5;
1135
+ const PET_RESTING_FRAME_DURATION_MULTIPLIER = 3;
1136
+ const PET_RESTING_DELAY_MS = 2e3;
1137
+ const PET_SUMMARY_GAP = 12;
1138
+ const PET_SUMMARY_WIDTH = 320;
1139
+ const PET_SUMMARY_MARGIN = 12;
1140
+ const PET_CONTEXT_MENU_MARGIN = 8;
1141
+ const PET_OVERLAY_COPY = {
1142
+ "en-US": {
1143
+ closePetMenuItem: "Close pet",
1144
+ hideMessage: "Hide message",
1145
+ expandMessage: "Expand message",
1146
+ collapseMessage: "Collapse message",
1147
+ restoreMessage: "Show message",
1148
+ replyButton: "Reply",
1149
+ replyPlaceholder: "Reply...",
1150
+ sendButton: "Send",
1151
+ sendingButton: "Sending...",
1152
+ sendFailed: "Failed to send"
1153
+ },
1154
+ "zh-CN": {
1155
+ closePetMenuItem: "关闭宠物",
1156
+ hideMessage: "隐藏消息",
1157
+ expandMessage: "展开消息",
1158
+ collapseMessage: "收起消息",
1159
+ restoreMessage: "显示消息",
1160
+ replyButton: "回复",
1161
+ replyPlaceholder: "输入回复...",
1162
+ sendButton: "发送",
1163
+ sendingButton: "发送中...",
1164
+ sendFailed: "发送失败"
1165
+ }
1166
+ };
1167
+ function stopEventPropagation(event) {
1168
+ event.stopPropagation();
1169
+ }
1170
+ function getViewportSize() {
1171
+ const visualViewport = window.visualViewport;
1172
+ return {
1173
+ width: (visualViewport == null ? void 0 : visualViewport.width) || window.innerWidth || 320,
1174
+ height: (visualViewport == null ? void 0 : visualViewport.height) || window.innerHeight || 480
1175
+ };
1176
+ }
1177
+ function readPersistedPosition(storageKey, persist) {
1178
+ if (!persist) {
1179
+ return null;
1180
+ }
1181
+ try {
1182
+ const raw = window.localStorage.getItem(storageKey);
1183
+ if (!raw) {
1184
+ return null;
1185
+ }
1186
+ const parsed = JSON.parse(raw);
1187
+ if (!parsed || typeof parsed !== "object" || typeof parsed.x !== "number" || typeof parsed.y !== "number") {
1188
+ return null;
1189
+ }
1190
+ return { x: parsed.x, y: parsed.y };
1191
+ } catch {
1192
+ return null;
1193
+ }
1194
+ }
1195
+ function writePersistedPosition(storageKey, persist, position) {
1196
+ if (!persist) {
1197
+ return;
1198
+ }
1199
+ try {
1200
+ window.localStorage.setItem(storageKey, JSON.stringify(position));
1201
+ } catch {
1202
+ }
1203
+ }
1204
+ function escapeCssUrl(value) {
1205
+ return value.replace(/["\\]/g, "\\$&");
1206
+ }
1207
+ function getRenderScale(scale) {
1208
+ return Math.max(0.1, scale) * PET_BASE_RENDER_SCALE;
1209
+ }
1210
+ function clampNumber(value, min, max) {
1211
+ return Math.min(max, Math.max(min, value));
1212
+ }
1213
+ function getDefaultLocale() {
1214
+ if (typeof window !== "undefined") {
1215
+ try {
1216
+ const stored = window.localStorage.getItem("chatkit:locale");
1217
+ if (stored) {
1218
+ return stored;
1219
+ }
1220
+ } catch {
1221
+ }
1222
+ }
1223
+ return typeof navigator !== "undefined" ? navigator.language : null;
1224
+ }
1225
+ function resolveCopyLocale(locale) {
1226
+ const normalized = (locale ?? getDefaultLocale() ?? "").trim().toLowerCase();
1227
+ if (normalized === "zh-cn" || normalized === "zh-hans" || normalized.startsWith("zh")) {
1228
+ return "zh-CN";
1229
+ }
1230
+ return "en-US";
1231
+ }
1232
+ function isPetState(value) {
1233
+ return value === "idle" || value === "running-right" || value === "running-left" || value === "waving" || value === "jumping" || value === "failed" || value === "waiting" || value === "running" || value === "review";
1234
+ }
1235
+ function parsePetStateChangePayload(value) {
1236
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1237
+ return null;
1238
+ }
1239
+ const payload = value;
1240
+ return isPetState(payload.state) ? { state: payload.state } : null;
1241
+ }
1242
+ function parsePetOptionsChangePayload(value) {
1243
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1244
+ return null;
1245
+ }
1246
+ const payload = value;
1247
+ if (payload.pet === null || typeof payload.pet === "boolean") {
1248
+ return { pet: payload.pet };
1249
+ }
1250
+ if (payload.pet && typeof payload.pet === "object" && !Array.isArray(payload.pet)) {
1251
+ return { pet: payload.pet };
1252
+ }
1253
+ return null;
1254
+ }
1255
+ function isThreadSummaryStatus(value) {
1256
+ return value === "running" || value === "completed" || value === "failed";
1257
+ }
1258
+ function getThreadSummaryKey(summary) {
1259
+ if (!summary) {
1260
+ return null;
1261
+ }
1262
+ return [
1263
+ summary.threadId,
1264
+ summary.messageId || summary.updatedAt || summary.message
1265
+ ].join(":");
1266
+ }
1267
+ function parseThreadSummaryPayload(value) {
1268
+ if (value === null) {
1269
+ return { summary: null };
1270
+ }
1271
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1272
+ return null;
1273
+ }
1274
+ const payload = value;
1275
+ if (typeof payload.threadId !== "string" || !payload.threadId.trim() || typeof payload.title !== "string" || !payload.title.trim() || typeof payload.message !== "string" || !payload.message.trim() || !isThreadSummaryStatus(payload.status)) {
1276
+ return null;
1277
+ }
1278
+ return {
1279
+ summary: {
1280
+ threadId: payload.threadId,
1281
+ title: payload.title,
1282
+ message: payload.message,
1283
+ status: payload.status,
1284
+ ...typeof payload.messageId === "string" && payload.messageId.trim() ? { messageId: payload.messageId } : {},
1285
+ ...typeof payload.updatedAt === "string" && payload.updatedAt.trim() ? { updatedAt: payload.updatedAt } : {}
1286
+ }
1287
+ };
1288
+ }
1289
+ function parseThreadSummaryLogPayload(value) {
1290
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1291
+ return null;
1292
+ }
1293
+ const payload = value;
1294
+ if (payload.name !== "thread.summary") {
1295
+ return null;
1296
+ }
1297
+ return parseThreadSummaryPayload(payload.data ?? null);
1298
+ }
1299
+ class PetOverlay {
1300
+ constructor(root, options) {
1301
+ this.overlayElement = null;
1302
+ this.petElement = null;
1303
+ this.contextMenuElement = null;
1304
+ this.summaryElement = null;
1305
+ this.summaryToggleElement = null;
1306
+ this.mediaElement = null;
1307
+ this.options = null;
1308
+ this.resolved = null;
1309
+ this.summary = null;
1310
+ this.summaryRenderKey = null;
1311
+ this.dismissedSummaryKey = null;
1312
+ this.isSummaryCollapsed = false;
1313
+ this.isSummaryExpanded = false;
1314
+ this.isSummaryHovering = false;
1315
+ this.isReplyOpen = false;
1316
+ this.isReplySubmitting = false;
1317
+ this.replyError = null;
1318
+ this.replyDraft = "";
1319
+ this.replyInputElement = null;
1320
+ this.copyLocale = resolveCopyLocale();
1321
+ this.copy = PET_OVERLAY_COPY[this.copyLocale];
1322
+ this.currentState = "waiting";
1323
+ this.lastAutoState = "waiting";
1324
+ this.transient = null;
1325
+ this.position = null;
1326
+ this.dragPosition = null;
1327
+ this.dragOffset = { x: 0, y: 0 };
1328
+ this.lastDragPosition = null;
1329
+ this.lastDragClientX = null;
1330
+ this.dragAnimation = null;
1331
+ this.isDragging = false;
1332
+ this.isHovering = false;
1333
+ this.movedDuringDrag = false;
1334
+ this.prefersReducedMotion = false;
1335
+ this.frame = 0;
1336
+ this.completed = false;
1337
+ this.activeAnimationName = null;
1338
+ this.activeAnimationMode = null;
1339
+ this.frameTimer = null;
1340
+ this.restingDelayTimer = null;
1341
+ this.mediaQuery = null;
1342
+ this.connected = false;
1343
+ this.handleViewportChange = () => {
1344
+ this.closeContextMenu();
1345
+ this.render();
1346
+ };
1347
+ this.handleReducedMotionChange = () => {
1348
+ var _a2;
1349
+ this.prefersReducedMotion = Boolean((_a2 = this.mediaQuery) == null ? void 0 : _a2.matches);
1350
+ if (this.prefersReducedMotion) {
1351
+ this.transient = null;
1352
+ }
1353
+ this.render();
1354
+ };
1355
+ this.handlePointerEnter = () => {
1356
+ this.clearRestingDelayTimer();
1357
+ this.isHovering = true;
1358
+ this.rescheduleAnimation();
1359
+ };
1360
+ this.handlePointerLeave = () => {
1361
+ if (!this.isDragging) {
1362
+ this.enterRestingAfterDelay();
1363
+ }
1364
+ };
1365
+ this.handleContextMenu = (event) => {
1366
+ event.preventDefault();
1367
+ event.stopPropagation();
1368
+ this.openContextMenu({ x: event.clientX, y: event.clientY });
1369
+ };
1370
+ this.handleContextMenuEvent = (event) => {
1371
+ event.preventDefault();
1372
+ event.stopPropagation();
1373
+ };
1374
+ this.handleContextMenuOutsidePointerDown = (event) => {
1375
+ const menu = this.contextMenuElement;
1376
+ if (menu && event.composedPath().includes(menu)) {
1377
+ return;
1378
+ }
1379
+ this.closeContextMenu();
1380
+ };
1381
+ this.handleContextMenuKeyDown = (event) => {
1382
+ if (event.key !== "Escape") {
1383
+ return;
1384
+ }
1385
+ event.preventDefault();
1386
+ this.closeContextMenu();
1387
+ };
1388
+ this.handleClosePetMenuItemClick = (event) => {
1389
+ var _a2;
1390
+ event.preventDefault();
1391
+ event.stopPropagation();
1392
+ this.closeContextMenu();
1393
+ (_a2 = this.onClose) == null ? void 0 : _a2.call(this);
1394
+ };
1395
+ this.handleSummaryPointerEnter = () => {
1396
+ this.isSummaryHovering = true;
1397
+ this.render();
1398
+ };
1399
+ this.handleSummaryPointerLeave = () => {
1400
+ this.isSummaryHovering = false;
1401
+ if (!this.isReplyOpen) {
1402
+ this.render();
1403
+ }
1404
+ };
1405
+ this.handleSummaryClick = () => {
1406
+ var _a2, _b2;
1407
+ const threadId = (_a2 = this.summary) == null ? void 0 : _a2.threadId.trim();
1408
+ if (!threadId) {
1409
+ return;
1410
+ }
1411
+ (_b2 = this.onThreadSummaryActivate) == null ? void 0 : _b2.call(this, threadId);
1412
+ };
1413
+ this.handleSummaryDelete = () => {
1414
+ const summaryKey = getThreadSummaryKey(this.summary);
1415
+ if (summaryKey) {
1416
+ this.dismissedSummaryKey = summaryKey;
1417
+ }
1418
+ this.isSummaryCollapsed = false;
1419
+ this.isReplyOpen = false;
1420
+ this.replyDraft = "";
1421
+ this.replyError = null;
1422
+ this.removeSummaryElements();
1423
+ };
1424
+ this.handleSummaryCollapseToggle = () => {
1425
+ this.isSummaryCollapsed = !this.isSummaryCollapsed;
1426
+ this.isSummaryExpanded = false;
1427
+ this.isReplyOpen = false;
1428
+ this.replyError = null;
1429
+ this.render();
1430
+ };
1431
+ this.handleSummaryExpandToggle = () => {
1432
+ this.isSummaryExpanded = !this.isSummaryExpanded;
1433
+ this.render();
1434
+ };
1435
+ this.handleReplyOpen = () => {
1436
+ this.isReplyOpen = true;
1437
+ this.replyError = null;
1438
+ this.render();
1439
+ };
1440
+ this.handleReplyInput = (event) => {
1441
+ const target = event.currentTarget;
1442
+ if (target instanceof HTMLInputElement) {
1443
+ this.replyDraft = target.value;
1444
+ this.replyError = null;
1445
+ }
1446
+ };
1447
+ this.handleReplySubmit = (event) => {
1448
+ event.preventDefault();
1449
+ void this.submitReply();
1450
+ };
1451
+ this.handleReplyKeyDown = (event) => {
1452
+ if (event.key !== "Escape") {
1453
+ return;
1454
+ }
1455
+ event.preventDefault();
1456
+ this.isReplyOpen = false;
1457
+ this.replyError = null;
1458
+ this.render();
1459
+ };
1460
+ this.handlePointerDown = (event) => {
1461
+ var _a2, _b2;
1462
+ if (event.button !== 0 || event.ctrlKey) {
1463
+ return;
1464
+ }
1465
+ this.closeContextMenu();
1466
+ if (!((_a2 = this.options) == null ? void 0 : _a2.position.draggable)) {
1467
+ return;
1468
+ }
1469
+ event.preventDefault();
1470
+ const rect = (_b2 = this.petElement) == null ? void 0 : _b2.getBoundingClientRect();
1471
+ if (!rect) {
1472
+ return;
1473
+ }
1474
+ const nextPosition = {
1475
+ x: rect.left,
1476
+ y: rect.top
1477
+ };
1478
+ this.dragOffset = {
1479
+ x: event.clientX - rect.left,
1480
+ y: event.clientY - rect.top
1481
+ };
1482
+ this.lastDragPosition = nextPosition;
1483
+ this.lastDragClientX = event.clientX;
1484
+ this.dragAnimation = null;
1485
+ this.movedDuringDrag = false;
1486
+ this.dragPosition = nextPosition;
1487
+ this.isDragging = true;
1488
+ this.clearRestingDelayTimer();
1489
+ this.isHovering = true;
1490
+ this.installDragListeners();
1491
+ this.rescheduleAnimation();
1492
+ };
1493
+ this.handlePointerMove = (event) => {
1494
+ const nextPosition = this.getNextDragPosition(event);
1495
+ const last = this.lastDragPosition;
1496
+ if (last && (Math.abs(last.x - nextPosition.x) > DRAG_DIRECTION_THRESHOLD_PX || Math.abs(last.y - nextPosition.y) > DRAG_DIRECTION_THRESHOLD_PX)) {
1497
+ this.movedDuringDrag = true;
1498
+ }
1499
+ if (this.lastDragClientX !== null) {
1500
+ const deltaX = event.clientX - this.lastDragClientX;
1501
+ if (deltaX > DRAG_DIRECTION_THRESHOLD_PX) {
1502
+ this.dragAnimation = "running-right";
1503
+ } else if (deltaX < -DRAG_DIRECTION_THRESHOLD_PX) {
1504
+ this.dragAnimation = "running-left";
1505
+ }
1506
+ }
1507
+ this.lastDragClientX = event.clientX;
1508
+ this.lastDragPosition = nextPosition;
1509
+ this.dragPosition = nextPosition;
1510
+ this.render();
1511
+ };
1512
+ this.handlePointerUp = (event) => {
1513
+ const finalPosition = this.lastDragPosition ?? this.getNextDragPosition(event);
1514
+ this.isDragging = false;
1515
+ this.dragPosition = null;
1516
+ this.dragAnimation = null;
1517
+ this.lastDragClientX = null;
1518
+ this.removeDragListeners();
1519
+ this.persistPosition(finalPosition);
1520
+ if (event.pointerType === "mouse" && this.isPointerOverPet(event)) {
1521
+ this.isHovering = true;
1522
+ this.rescheduleAnimation();
1523
+ } else {
1524
+ this.enterRestingAfterDelay();
1525
+ this.rescheduleAnimation();
1526
+ }
1527
+ };
1528
+ this.handleClick = () => {
1529
+ var _a2;
1530
+ if (this.movedDuringDrag) {
1531
+ return;
1532
+ }
1533
+ (_a2 = this.onActivate) == null ? void 0 : _a2.call(this);
1534
+ if (this.prefersReducedMotion) {
1535
+ return;
1536
+ }
1537
+ this.transient = { name: "waving" };
1538
+ this.render();
1539
+ };
1540
+ this.root = root;
1541
+ this.onActivate = options == null ? void 0 : options.onActivate;
1542
+ this.onClose = options == null ? void 0 : options.onClose;
1543
+ this.onReply = options == null ? void 0 : options.onReply;
1544
+ this.onThreadSummaryActivate = options == null ? void 0 : options.onThreadSummaryActivate;
1545
+ this.connect();
1546
+ }
1547
+ connect() {
1548
+ if (this.connected) {
1549
+ return;
1550
+ }
1551
+ this.connected = true;
1552
+ this.installViewportListeners();
1553
+ this.installReducedMotionListener();
1554
+ this.render();
1555
+ }
1556
+ setOptions(pet) {
1557
+ this.closeContextMenu();
1558
+ const nextOptions = normalizePetOptions(pet);
1559
+ this.options = nextOptions;
1560
+ if (!nextOptions) {
1561
+ this.isDragging = false;
1562
+ this.isHovering = false;
1563
+ this.position = null;
1564
+ this.dragPosition = null;
1565
+ this.dragAnimation = null;
1566
+ this.lastDragPosition = null;
1567
+ this.lastDragClientX = null;
1568
+ this.transient = null;
1569
+ this.resolved = null;
1570
+ this.clearRestingDelayTimer();
1571
+ this.removeDragListeners();
1572
+ this.removeOverlay();
1573
+ return;
1574
+ }
1575
+ this.position = readPersistedPosition(
1576
+ DEFAULT_PET_STORAGE_KEY,
1577
+ nextOptions.position.persist
1578
+ );
1579
+ if (nextOptions.behavior === "auto" && !this.prefersReducedMotion) {
1580
+ this.transient = { name: "waving" };
1581
+ }
1582
+ this.resolveCharacter();
1583
+ this.render();
1584
+ }
1585
+ setState(state) {
1586
+ var _a2;
1587
+ const previous = this.lastAutoState;
1588
+ this.lastAutoState = state;
1589
+ this.currentState = state;
1590
+ if (((_a2 = this.options) == null ? void 0 : _a2.behavior) === "auto" && !this.prefersReducedMotion && state === "idle" && (previous === "running" || previous === "review") && !this.transient) {
1591
+ this.transient = { name: "jumping" };
1592
+ } else if (state !== "idle") {
1593
+ this.transient = null;
1594
+ }
1595
+ this.render();
1596
+ }
1597
+ setLocale(locale) {
1598
+ const nextLocale = resolveCopyLocale(locale);
1599
+ if (nextLocale === this.copyLocale) {
1600
+ return;
1601
+ }
1602
+ this.copyLocale = nextLocale;
1603
+ this.copy = PET_OVERLAY_COPY[nextLocale];
1604
+ this.summaryRenderKey = null;
1605
+ this.closeContextMenu();
1606
+ this.render();
1607
+ }
1608
+ setThreadSummary(summary) {
1609
+ const previousKey = getThreadSummaryKey(this.summary);
1610
+ const nextKey = getThreadSummaryKey(summary);
1611
+ this.summary = summary;
1612
+ if (!summary) {
1613
+ this.isSummaryCollapsed = false;
1614
+ this.isSummaryExpanded = false;
1615
+ this.isSummaryHovering = false;
1616
+ this.isReplyOpen = false;
1617
+ this.isReplySubmitting = false;
1618
+ this.replyError = null;
1619
+ this.replyDraft = "";
1620
+ this.summaryRenderKey = null;
1621
+ this.removeSummaryElements();
1622
+ return;
1623
+ }
1624
+ if (previousKey !== nextKey) {
1625
+ this.isSummaryCollapsed = false;
1626
+ this.isSummaryExpanded = false;
1627
+ this.isSummaryHovering = false;
1628
+ this.isReplyOpen = false;
1629
+ this.isReplySubmitting = false;
1630
+ this.replyError = null;
1631
+ this.replyDraft = "";
1632
+ }
1633
+ this.render();
1634
+ }
1635
+ setThreadSummaryStatus(status) {
1636
+ if (!this.summary || this.summary.status === status) {
1637
+ return;
1638
+ }
1639
+ this.summary = { ...this.summary, status };
1640
+ this.render();
1641
+ }
1642
+ destroy() {
1643
+ var _a2, _b2, _c2, _d;
1644
+ if (!this.connected) {
1645
+ return;
1646
+ }
1647
+ this.connected = false;
1648
+ this.clearRestingDelayTimer();
1649
+ this.clearTimers();
1650
+ this.removeDragListeners();
1651
+ this.removeOverlay();
1652
+ window.removeEventListener("resize", this.handleViewportChange);
1653
+ (_a2 = window.visualViewport) == null ? void 0 : _a2.removeEventListener(
1654
+ "resize",
1655
+ this.handleViewportChange
1656
+ );
1657
+ (_b2 = window.visualViewport) == null ? void 0 : _b2.removeEventListener(
1658
+ "scroll",
1659
+ this.handleViewportChange
1660
+ );
1661
+ (_d = (_c2 = this.mediaQuery) == null ? void 0 : _c2.removeEventListener) == null ? void 0 : _d.call(
1662
+ _c2,
1663
+ "change",
1664
+ this.handleReducedMotionChange
1665
+ );
1666
+ this.mediaQuery = null;
1667
+ }
1668
+ installViewportListeners() {
1669
+ var _a2, _b2;
1670
+ window.addEventListener("resize", this.handleViewportChange);
1671
+ (_a2 = window.visualViewport) == null ? void 0 : _a2.addEventListener(
1672
+ "resize",
1673
+ this.handleViewportChange
1674
+ );
1675
+ (_b2 = window.visualViewport) == null ? void 0 : _b2.addEventListener(
1676
+ "scroll",
1677
+ this.handleViewportChange
1678
+ );
1679
+ }
1680
+ installReducedMotionListener() {
1681
+ var _a2, _b2;
1682
+ if (!window.matchMedia) {
1683
+ return;
1684
+ }
1685
+ this.mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
1686
+ this.prefersReducedMotion = this.mediaQuery.matches;
1687
+ (_b2 = (_a2 = this.mediaQuery).addEventListener) == null ? void 0 : _b2.call(
1688
+ _a2,
1689
+ "change",
1690
+ this.handleReducedMotionChange
1691
+ );
1692
+ }
1693
+ resolveCharacter() {
1694
+ if (!this.options) {
1695
+ this.resolved = null;
1696
+ return;
1697
+ }
1698
+ const character = this.options.character;
1699
+ this.resolved = resolvePetCharacter(character);
1700
+ }
1701
+ ensureOverlay() {
1702
+ if (this.overlayElement && this.petElement) {
1703
+ return;
1704
+ }
1705
+ const overlay = document.createElement("div");
1706
+ overlay.setAttribute("data-chatkit-host-pet-layer", "");
1707
+ overlay.style.position = "fixed";
1708
+ overlay.style.inset = "0";
1709
+ overlay.style.pointerEvents = "none";
1710
+ overlay.style.overflow = "visible";
1711
+ const style = document.createElement("style");
1712
+ style.textContent = `
1713
+ @keyframes chatkit-pet-summary-spin {
1714
+ to { transform: rotate(360deg); }
1715
+ }
1716
+ `;
1717
+ const pet = document.createElement("div");
1718
+ pet.setAttribute("data-chatkit-host-pet", "");
1719
+ pet.style.position = "absolute";
1720
+ pet.style.top = "0";
1721
+ pet.style.left = "0";
1722
+ pet.style.pointerEvents = "auto";
1723
+ pet.style.touchAction = "none";
1724
+ pet.style.userSelect = "none";
1725
+ pet.style.willChange = "transform";
1726
+ pet.addEventListener("pointerenter", this.handlePointerEnter);
1727
+ pet.addEventListener("pointerleave", this.handlePointerLeave);
1728
+ pet.addEventListener("pointerdown", this.handlePointerDown);
1729
+ pet.addEventListener("contextmenu", this.handleContextMenu);
1730
+ pet.addEventListener("click", this.handleClick);
1731
+ overlay.append(style, pet);
1732
+ this.root.append(overlay);
1733
+ this.overlayElement = overlay;
1734
+ this.petElement = pet;
1735
+ }
1736
+ removeOverlay() {
1737
+ var _a2;
1738
+ this.clearRestingDelayTimer();
1739
+ this.clearTimers();
1740
+ this.closeContextMenu();
1741
+ if (this.petElement) {
1742
+ this.petElement.removeEventListener(
1743
+ "pointerenter",
1744
+ this.handlePointerEnter
1745
+ );
1746
+ this.petElement.removeEventListener(
1747
+ "pointerleave",
1748
+ this.handlePointerLeave
1749
+ );
1750
+ this.petElement.removeEventListener(
1751
+ "pointerdown",
1752
+ this.handlePointerDown
1753
+ );
1754
+ this.petElement.removeEventListener(
1755
+ "contextmenu",
1756
+ this.handleContextMenu
1757
+ );
1758
+ this.petElement.removeEventListener("click", this.handleClick);
1759
+ }
1760
+ this.isHovering = false;
1761
+ this.removeSummaryElements();
1762
+ (_a2 = this.overlayElement) == null ? void 0 : _a2.remove();
1763
+ this.overlayElement = null;
1764
+ this.petElement = null;
1765
+ this.mediaElement = null;
1766
+ }
1767
+ removeSummaryElements() {
1768
+ var _a2, _b2;
1769
+ (_a2 = this.summaryElement) == null ? void 0 : _a2.remove();
1770
+ (_b2 = this.summaryToggleElement) == null ? void 0 : _b2.remove();
1771
+ this.summaryElement = null;
1772
+ this.summaryToggleElement = null;
1773
+ this.replyInputElement = null;
1774
+ this.summaryRenderKey = null;
1775
+ }
1776
+ getSize() {
1777
+ if (!this.options || !this.resolved) {
1778
+ return { width: 0, height: 0 };
1779
+ }
1780
+ const scale = getRenderScale(this.options.position.scale);
1781
+ const baseSize = {
1782
+ width: this.resolved.atlas.cellWidth,
1783
+ height: this.resolved.atlas.cellHeight
1784
+ };
1785
+ return {
1786
+ width: baseSize.width * scale,
1787
+ height: baseSize.height * scale
1788
+ };
1789
+ }
1790
+ getCurrentPosition(size) {
1791
+ const options = this.options;
1792
+ if (!options) {
1793
+ return { x: 0, y: 0 };
1794
+ }
1795
+ const viewport = getViewportSize();
1796
+ const padding = normalizeBoundsPadding(options.position.boundsPadding);
1797
+ const pin = options.position.pin === void 0 ? "bottom-right" : options.position.pin;
1798
+ const pinnedPosition = pin ? getPinnedPetPosition(pin, size, viewport, padding) : null;
1799
+ return clampPetPosition(
1800
+ this.dragPosition ?? this.position ?? pinnedPosition ?? { x: padding.left, y: padding.top },
1801
+ size,
1802
+ viewport,
1803
+ padding
1804
+ );
1805
+ }
1806
+ persistPosition(nextPosition) {
1807
+ if (!this.options) {
1808
+ return;
1809
+ }
1810
+ const size = this.getSize();
1811
+ const clamped = clampPetPosition(
1812
+ nextPosition,
1813
+ size,
1814
+ getViewportSize(),
1815
+ normalizeBoundsPadding(this.options.position.boundsPadding)
1816
+ );
1817
+ this.position = clamped;
1818
+ writePersistedPosition(
1819
+ DEFAULT_PET_STORAGE_KEY,
1820
+ this.options.position.persist,
1821
+ clamped
1822
+ );
1823
+ }
1824
+ getActiveAnimationName() {
1825
+ if (!this.options) {
1826
+ return "idle";
1827
+ }
1828
+ if (this.isDragging) {
1829
+ return this.dragAnimation ?? "running";
1830
+ }
1831
+ if (this.transient) {
1832
+ return this.transient.name;
1833
+ }
1834
+ if (this.options.behavior === "manual") {
1835
+ return "idle";
1836
+ }
1837
+ return this.currentState;
1838
+ }
1839
+ getActiveAnimationMode() {
1840
+ if (this.isDragging) {
1841
+ return "loop";
1842
+ }
1843
+ return this.transient ? "once" : "loop";
1844
+ }
1845
+ resetAnimationIfNeeded(name, mode) {
1846
+ if (this.activeAnimationName === name && this.activeAnimationMode === mode) {
1847
+ return;
1848
+ }
1849
+ this.clearTimers();
1850
+ this.activeAnimationName = name;
1851
+ this.activeAnimationMode = mode;
1852
+ this.frame = 0;
1853
+ this.completed = false;
1854
+ }
1855
+ render() {
1856
+ if (!this.options || !this.resolved) {
1857
+ this.clearTimers();
1858
+ if (this.petElement) {
1859
+ this.petElement.replaceChildren();
1860
+ }
1861
+ this.removeSummaryElements();
1862
+ this.mediaElement = null;
1863
+ this.activeAnimationName = null;
1864
+ this.activeAnimationMode = null;
1865
+ this.frame = 0;
1866
+ this.completed = false;
1867
+ return;
1868
+ }
1869
+ this.ensureOverlay();
1870
+ const overlay = this.overlayElement;
1871
+ const pet = this.petElement;
1872
+ if (!overlay || !pet) {
1873
+ return;
1874
+ }
1875
+ const size = this.getSize();
1876
+ const position = this.getCurrentPosition(size);
1877
+ const animationName = this.getActiveAnimationName();
1878
+ const animationMode = this.getActiveAnimationMode();
1879
+ this.resetAnimationIfNeeded(animationName, animationMode);
1880
+ overlay.style.zIndex = String(this.options.position.zIndex);
1881
+ pet.style.width = `${size.width}px`;
1882
+ pet.style.height = `${size.height}px`;
1883
+ pet.style.transform = `translate3d(${position.x}px, ${position.y}px, 0)`;
1884
+ pet.style.cursor = this.options.position.draggable ? this.isDragging ? "grabbing" : "grab" : "default";
1885
+ pet.dataset.petAnimation = animationName;
1886
+ pet.setAttribute("aria-label", this.options.ariaLabel);
1887
+ pet.setAttribute("role", "img");
1888
+ this.renderAtlas(animationName, animationMode);
1889
+ this.renderThreadSummary(position, size);
1890
+ this.scheduleNextFrame(animationName, animationMode);
1891
+ }
1892
+ renderThreadSummary(position, size) {
1893
+ var _a2, _b2, _c2;
1894
+ const summary = this.summary;
1895
+ const summaryKey = getThreadSummaryKey(summary);
1896
+ if (!summary || !summaryKey || this.dismissedSummaryKey === summaryKey) {
1897
+ this.removeSummaryElements();
1898
+ return;
1899
+ }
1900
+ if (this.isSummaryCollapsed) {
1901
+ this.renderCollapsedSummary(position, size);
1902
+ return;
1903
+ }
1904
+ const nextRenderKey = [
1905
+ summaryKey,
1906
+ summary.title,
1907
+ summary.message,
1908
+ summary.status,
1909
+ this.copyLocale,
1910
+ this.isSummaryExpanded ? "expanded" : "compact",
1911
+ this.isSummaryHovering ? "hover" : "rest",
1912
+ this.isReplyOpen ? "reply" : "closed",
1913
+ this.isReplySubmitting ? "submitting" : "ready",
1914
+ this.replyError ?? ""
1915
+ ].join("|");
1916
+ if (!this.summaryElement || this.summaryRenderKey !== nextRenderKey) {
1917
+ (_a2 = this.summaryElement) == null ? void 0 : _a2.remove();
1918
+ (_b2 = this.summaryToggleElement) == null ? void 0 : _b2.remove();
1919
+ this.summaryElement = this.createSummaryBubble(summary);
1920
+ this.summaryToggleElement = this.createSummaryToggleButton("v");
1921
+ (_c2 = this.overlayElement) == null ? void 0 : _c2.append(
1922
+ this.summaryElement,
1923
+ this.summaryToggleElement
1924
+ );
1925
+ this.summaryRenderKey = nextRenderKey;
1926
+ if (this.isReplyOpen && !this.isReplySubmitting) {
1927
+ window.setTimeout(() => {
1928
+ var _a3;
1929
+ return (_a3 = this.replyInputElement) == null ? void 0 : _a3.focus();
1930
+ }, 0);
1931
+ }
1932
+ }
1933
+ this.positionSummaryBubble(position, size);
1934
+ }
1935
+ renderCollapsedSummary(position, size) {
1936
+ var _a2, _b2;
1937
+ (_a2 = this.summaryElement) == null ? void 0 : _a2.remove();
1938
+ this.summaryElement = null;
1939
+ this.summaryRenderKey = null;
1940
+ if (!this.summaryToggleElement) {
1941
+ this.summaryToggleElement = this.createSummaryToggleButton("1");
1942
+ (_b2 = this.overlayElement) == null ? void 0 : _b2.append(this.summaryToggleElement);
1943
+ }
1944
+ this.summaryToggleElement.textContent = "1";
1945
+ this.positionSummaryToggleBadge(position, size);
1946
+ }
1947
+ positionSummaryToggleBadge(position, size) {
1948
+ const badge = this.summaryToggleElement;
1949
+ if (!badge) {
1950
+ return;
1951
+ }
1952
+ const viewport = getViewportSize();
1953
+ const badgeSize = 34;
1954
+ const x = clampNumber(
1955
+ position.x + size.width - badgeSize * 0.35,
1956
+ PET_SUMMARY_MARGIN,
1957
+ viewport.width - badgeSize - PET_SUMMARY_MARGIN
1958
+ );
1959
+ const y = clampNumber(
1960
+ position.y - badgeSize * 0.35,
1961
+ PET_SUMMARY_MARGIN,
1962
+ viewport.height - badgeSize - PET_SUMMARY_MARGIN
1963
+ );
1964
+ badge.style.width = `${badgeSize}px`;
1965
+ badge.style.height = `${badgeSize}px`;
1966
+ badge.style.transform = `translate3d(${x}px, ${y}px, 0)`;
1967
+ badge.style.borderRadius = "999px";
1968
+ }
1969
+ positionSummaryBubble(position, size) {
1970
+ const bubble = this.summaryElement;
1971
+ const toggle = this.summaryToggleElement;
1972
+ if (!bubble || !toggle) {
1973
+ return;
1974
+ }
1975
+ const viewport = getViewportSize();
1976
+ const width = Math.min(
1977
+ PET_SUMMARY_WIDTH,
1978
+ viewport.width - PET_SUMMARY_MARGIN * 2
1979
+ );
1980
+ bubble.style.width = `${width}px`;
1981
+ const bubbleHeight = bubble.offsetHeight || 96;
1982
+ const aboveY = position.y - bubbleHeight - PET_SUMMARY_GAP;
1983
+ const showAbove = aboveY >= PET_SUMMARY_MARGIN;
1984
+ const y = showAbove ? aboveY : clampNumber(
1985
+ position.y + size.height + PET_SUMMARY_GAP,
1986
+ PET_SUMMARY_MARGIN,
1987
+ viewport.height - bubbleHeight - PET_SUMMARY_MARGIN
1988
+ );
1989
+ const x = clampNumber(
1990
+ position.x + size.width / 2 - width / 2,
1991
+ PET_SUMMARY_MARGIN,
1992
+ viewport.width - width - PET_SUMMARY_MARGIN
1993
+ );
1994
+ bubble.style.transform = `translate3d(${x}px, ${y}px, 0)`;
1995
+ this.positionSummaryToggleBadge(position, size);
1996
+ }
1997
+ createSummaryBubble(summary) {
1998
+ const shouldShowReplyButton = this.isSummaryHovering && !this.isReplyOpen;
1999
+ const bubble = document.createElement("div");
2000
+ bubble.setAttribute("data-chatkit-pet-summary", "");
2001
+ bubble.addEventListener("pointerenter", this.handleSummaryPointerEnter);
2002
+ bubble.addEventListener("pointerleave", this.handleSummaryPointerLeave);
2003
+ bubble.addEventListener("click", this.handleSummaryClick);
2004
+ bubble.style.position = "absolute";
2005
+ bubble.style.top = "0";
2006
+ bubble.style.left = "0";
2007
+ bubble.style.boxSizing = "border-box";
2008
+ bubble.style.pointerEvents = "auto";
2009
+ bubble.style.padding = "12px 14px";
2010
+ bubble.style.paddingBottom = "12px";
2011
+ bubble.style.border = "1px solid rgba(148, 163, 184, 0.22)";
2012
+ bubble.style.borderRadius = "22px";
2013
+ bubble.style.background = "rgba(255, 255, 255, 0.94)";
2014
+ bubble.style.color = "#1f2937";
2015
+ bubble.style.boxShadow = "0 8px 24px rgba(15, 23, 42, 0.1)";
2016
+ bubble.style.font = '500 14px/1.35 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';
2017
+ bubble.style.backdropFilter = "blur(10px)";
2018
+ const header = document.createElement("div");
2019
+ header.style.display = "flex";
2020
+ header.style.alignItems = "center";
2021
+ header.style.gap = "8px";
2022
+ if (this.isSummaryHovering || this.isReplyOpen) {
2023
+ header.append(
2024
+ this.createSummaryActionButton(
2025
+ "x",
2026
+ this.copy.hideMessage,
2027
+ this.handleSummaryDelete
2028
+ )
2029
+ );
2030
+ }
2031
+ const title = document.createElement("div");
2032
+ title.textContent = summary.title;
2033
+ title.style.minWidth = "0";
2034
+ title.style.flex = "1";
2035
+ title.style.overflow = "hidden";
2036
+ title.style.textOverflow = "ellipsis";
2037
+ title.style.whiteSpace = "nowrap";
2038
+ title.style.fontWeight = "700";
2039
+ title.style.fontSize = "15px";
2040
+ header.append(title);
2041
+ if (this.isSummaryHovering || this.isReplyOpen) {
2042
+ header.append(
2043
+ this.createSummaryActionButton(
2044
+ this.isSummaryExpanded ? "-" : ">",
2045
+ this.isSummaryExpanded ? this.copy.collapseMessage : this.copy.expandMessage,
2046
+ this.handleSummaryExpandToggle
2047
+ )
2048
+ );
2049
+ } else {
2050
+ header.append(this.createStatusIcon(summary.status));
2051
+ }
2052
+ const message = document.createElement("div");
2053
+ message.textContent = summary.message;
2054
+ message.style.marginTop = "4px";
2055
+ message.style.fontWeight = "400";
2056
+ message.style.color = "#374151";
2057
+ message.style.overflow = "hidden";
2058
+ if (this.isSummaryExpanded) {
2059
+ message.style.maxHeight = "7em";
2060
+ message.style.overflowY = "auto";
2061
+ } else {
2062
+ message.style.display = "-webkit-box";
2063
+ message.style.setProperty("-webkit-line-clamp", "2");
2064
+ message.style.setProperty("-webkit-box-orient", "vertical");
2065
+ }
2066
+ bubble.append(header, message);
2067
+ if (shouldShowReplyButton) {
2068
+ const reply = this.createTextButton(
2069
+ this.copy.replyButton,
2070
+ this.handleReplyOpen
2071
+ );
2072
+ reply.style.position = "absolute";
2073
+ reply.style.right = "14px";
2074
+ reply.style.bottom = "10px";
2075
+ bubble.append(reply);
2076
+ }
2077
+ if (this.isReplyOpen) {
2078
+ bubble.append(this.createReplyForm());
2079
+ }
2080
+ return bubble;
2081
+ }
2082
+ createSummaryToggleButton(label) {
2083
+ const button = document.createElement("button");
2084
+ button.type = "button";
2085
+ button.textContent = label;
2086
+ button.title = label === "1" ? this.copy.restoreMessage : this.copy.collapseMessage;
2087
+ button.addEventListener("click", stopEventPropagation);
2088
+ button.addEventListener("click", this.handleSummaryCollapseToggle);
2089
+ button.style.position = "absolute";
2090
+ button.style.top = "0";
2091
+ button.style.left = "0";
2092
+ button.style.pointerEvents = "auto";
2093
+ button.style.border = "1px solid rgba(148, 163, 184, 0.28)";
2094
+ button.style.background = "rgba(248, 250, 252, 0.94)";
2095
+ button.style.color = "#475569";
2096
+ button.style.boxShadow = "0 6px 18px rgba(15, 23, 42, 0.1)";
2097
+ button.style.cursor = "pointer";
2098
+ button.style.font = '600 15px/1 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';
2099
+ button.style.display = "flex";
2100
+ button.style.alignItems = "center";
2101
+ button.style.justifyContent = "center";
2102
+ return button;
2103
+ }
2104
+ createStatusIcon(status) {
2105
+ const icon = document.createElement("span");
2106
+ icon.setAttribute("aria-hidden", "true");
2107
+ icon.style.display = "inline-flex";
2108
+ icon.style.width = "16px";
2109
+ icon.style.height = "16px";
2110
+ icon.style.alignItems = "center";
2111
+ icon.style.justifyContent = "center";
2112
+ icon.style.flex = "0 0 auto";
2113
+ if (status === "running") {
2114
+ icon.style.border = "2px solid rgba(71, 85, 105, 0.32)";
2115
+ icon.style.borderTopColor = "#64748b";
2116
+ icon.style.borderRadius = "999px";
2117
+ icon.style.animation = "chatkit-pet-summary-spin 900ms linear infinite";
2118
+ return icon;
2119
+ }
2120
+ icon.style.borderRadius = "999px";
2121
+ icon.style.fontSize = "12px";
2122
+ icon.style.fontWeight = "700";
2123
+ if (status === "failed") {
2124
+ icon.textContent = "!";
2125
+ icon.style.background = "#fee2e2";
2126
+ icon.style.color = "#b91c1c";
2127
+ return icon;
2128
+ }
2129
+ icon.textContent = "";
2130
+ icon.style.border = "2px solid #22c55e";
2131
+ icon.style.position = "relative";
2132
+ const check = document.createElement("span");
2133
+ check.style.width = "7px";
2134
+ check.style.height = "4px";
2135
+ check.style.borderLeft = "2px solid #22c55e";
2136
+ check.style.borderBottom = "2px solid #22c55e";
2137
+ check.style.transform = "rotate(-45deg) translate(1px, -1px)";
2138
+ icon.append(check);
2139
+ return icon;
2140
+ }
2141
+ createSummaryActionButton(label, title, onClick) {
2142
+ const button = document.createElement("button");
2143
+ button.type = "button";
2144
+ button.textContent = label;
2145
+ button.title = title;
2146
+ button.addEventListener("click", (event) => {
2147
+ event.preventDefault();
2148
+ event.stopPropagation();
2149
+ onClick();
2150
+ });
2151
+ button.style.width = "26px";
2152
+ button.style.height = "26px";
2153
+ button.style.border = "0";
2154
+ button.style.borderRadius = "999px";
2155
+ button.style.background = "rgba(241, 245, 249, 0.96)";
2156
+ button.style.color = "#475569";
2157
+ button.style.cursor = "pointer";
2158
+ button.style.font = '600 15px/1 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';
2159
+ return button;
2160
+ }
2161
+ createTextButton(label, onClick) {
2162
+ const button = document.createElement("button");
2163
+ button.type = "button";
2164
+ button.textContent = label;
2165
+ button.addEventListener("click", (event) => {
2166
+ event.preventDefault();
2167
+ event.stopPropagation();
2168
+ onClick();
2169
+ });
2170
+ button.style.border = "1px solid rgba(148, 163, 184, 0.28)";
2171
+ button.style.borderRadius = "999px";
2172
+ button.style.background = "rgba(248, 250, 252, 0.95)";
2173
+ button.style.color = "#334155";
2174
+ button.style.cursor = "pointer";
2175
+ button.style.padding = "3px 10px";
2176
+ button.style.font = '600 12px/1.4 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';
2177
+ return button;
2178
+ }
2179
+ createReplyForm() {
2180
+ const form = document.createElement("form");
2181
+ form.addEventListener("click", stopEventPropagation);
2182
+ form.addEventListener("submit", this.handleReplySubmit);
2183
+ form.addEventListener("keydown", this.handleReplyKeyDown);
2184
+ form.style.display = "flex";
2185
+ form.style.gap = "6px";
2186
+ form.style.alignItems = "center";
2187
+ form.style.marginTop = "8px";
2188
+ const input = document.createElement("input");
2189
+ input.type = "text";
2190
+ input.value = this.replyDraft;
2191
+ input.disabled = this.isReplySubmitting;
2192
+ input.placeholder = this.copy.replyPlaceholder;
2193
+ input.addEventListener("input", this.handleReplyInput);
2194
+ input.style.minWidth = "0";
2195
+ input.style.flex = "1";
2196
+ input.style.border = "1px solid rgba(148, 163, 184, 0.35)";
2197
+ input.style.borderRadius = "999px";
2198
+ input.style.padding = "6px 10px";
2199
+ input.style.font = '400 13px/1.2 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';
2200
+ this.replyInputElement = input;
2201
+ const send = document.createElement("button");
2202
+ send.type = "submit";
2203
+ send.textContent = this.isReplySubmitting ? this.copy.sendingButton : this.copy.sendButton;
2204
+ send.disabled = this.isReplySubmitting;
2205
+ send.style.border = "0";
2206
+ send.style.borderRadius = "999px";
2207
+ send.style.background = "#22c55e";
2208
+ send.style.color = "#052e16";
2209
+ send.style.cursor = this.isReplySubmitting ? "default" : "pointer";
2210
+ send.style.padding = "6px 10px";
2211
+ send.style.font = '700 12px/1.2 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';
2212
+ form.append(input, send);
2213
+ if (this.replyError) {
2214
+ const error = document.createElement("div");
2215
+ error.textContent = this.copy.sendFailed;
2216
+ error.style.flexBasis = "100%";
2217
+ error.style.color = "#b91c1c";
2218
+ error.style.fontSize = "12px";
2219
+ form.style.flexWrap = "wrap";
2220
+ form.append(error);
2221
+ }
2222
+ return form;
2223
+ }
2224
+ createContextMenu() {
2225
+ const menu = document.createElement("div");
2226
+ menu.setAttribute("data-chatkit-pet-context-menu", "");
2227
+ menu.setAttribute("role", "menu");
2228
+ menu.addEventListener("contextmenu", this.handleContextMenuEvent);
2229
+ menu.addEventListener("pointerdown", stopEventPropagation);
2230
+ menu.addEventListener("click", stopEventPropagation);
2231
+ menu.style.position = "absolute";
2232
+ menu.style.top = "0";
2233
+ menu.style.left = "0";
2234
+ menu.style.boxSizing = "border-box";
2235
+ menu.style.minWidth = "132px";
2236
+ menu.style.padding = "4px";
2237
+ menu.style.pointerEvents = "auto";
2238
+ menu.style.border = "1px solid rgba(148, 163, 184, 0.28)";
2239
+ menu.style.borderRadius = "10px";
2240
+ menu.style.background = "rgba(255, 255, 255, 0.96)";
2241
+ menu.style.color = "#1f2937";
2242
+ menu.style.boxShadow = "0 12px 28px rgba(15, 23, 42, 0.16)";
2243
+ menu.style.font = '500 13px/1.3 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';
2244
+ menu.style.backdropFilter = "blur(10px)";
2245
+ const closeItem = document.createElement("button");
2246
+ closeItem.type = "button";
2247
+ closeItem.textContent = this.copy.closePetMenuItem;
2248
+ closeItem.setAttribute("role", "menuitem");
2249
+ closeItem.addEventListener("click", this.handleClosePetMenuItemClick);
2250
+ closeItem.style.display = "block";
2251
+ closeItem.style.width = "100%";
2252
+ closeItem.style.border = "0";
2253
+ closeItem.style.borderRadius = "7px";
2254
+ closeItem.style.background = "transparent";
2255
+ closeItem.style.color = "inherit";
2256
+ closeItem.style.cursor = "pointer";
2257
+ closeItem.style.padding = "7px 10px";
2258
+ closeItem.style.textAlign = "left";
2259
+ closeItem.style.font = "inherit";
2260
+ menu.append(closeItem);
2261
+ return menu;
2262
+ }
2263
+ openContextMenu(position) {
2264
+ var _a2;
2265
+ const overlay = this.overlayElement;
2266
+ if (!overlay) {
2267
+ return;
2268
+ }
2269
+ this.closeContextMenu();
2270
+ const menu = this.createContextMenu();
2271
+ overlay.append(menu);
2272
+ this.contextMenuElement = menu;
2273
+ this.positionContextMenu(position);
2274
+ (_a2 = menu.querySelector("button")) == null ? void 0 : _a2.focus({ preventScroll: true });
2275
+ window.addEventListener(
2276
+ "pointerdown",
2277
+ this.handleContextMenuOutsidePointerDown,
2278
+ true
2279
+ );
2280
+ window.addEventListener("keydown", this.handleContextMenuKeyDown);
2281
+ }
2282
+ closeContextMenu() {
2283
+ var _a2;
2284
+ (_a2 = this.contextMenuElement) == null ? void 0 : _a2.remove();
2285
+ this.contextMenuElement = null;
2286
+ window.removeEventListener(
2287
+ "pointerdown",
2288
+ this.handleContextMenuOutsidePointerDown,
2289
+ true
2290
+ );
2291
+ window.removeEventListener("keydown", this.handleContextMenuKeyDown);
2292
+ }
2293
+ positionContextMenu(position) {
2294
+ const menu = this.contextMenuElement;
2295
+ if (!menu) {
2296
+ return;
2297
+ }
2298
+ const viewport = getViewportSize();
2299
+ const width = menu.offsetWidth || 132;
2300
+ const height = menu.offsetHeight || 40;
2301
+ const maxX = Math.max(
2302
+ PET_CONTEXT_MENU_MARGIN,
2303
+ viewport.width - width - PET_CONTEXT_MENU_MARGIN
2304
+ );
2305
+ const maxY = Math.max(
2306
+ PET_CONTEXT_MENU_MARGIN,
2307
+ viewport.height - height - PET_CONTEXT_MENU_MARGIN
2308
+ );
2309
+ const x = clampNumber(position.x, PET_CONTEXT_MENU_MARGIN, maxX);
2310
+ const y = clampNumber(position.y, PET_CONTEXT_MENU_MARGIN, maxY);
2311
+ menu.style.transform = `translate3d(${x}px, ${y}px, 0)`;
2312
+ }
2313
+ renderAtlas(animationName, animationMode) {
2314
+ var _a2;
2315
+ if (!this.petElement || ((_a2 = this.resolved) == null ? void 0 : _a2.kind) !== "atlas" || !this.options) {
2316
+ return;
2317
+ }
2318
+ if (!(this.mediaElement instanceof HTMLDivElement)) {
2319
+ const frame = document.createElement("div");
2320
+ frame.setAttribute("aria-hidden", "true");
2321
+ this.petElement.replaceChildren(frame);
2322
+ this.mediaElement = frame;
2323
+ }
2324
+ const frameElement = this.mediaElement;
2325
+ const atlas = this.resolved.atlas;
2326
+ const definition = atlas.animations[animationName] ?? atlas.animations.idle;
2327
+ const safeFrame = animationMode === "once" && this.completed ? Math.max(0, definition.frames - 1) : Math.min(this.frame, Math.max(0, definition.frames - 1));
2328
+ const scale = getRenderScale(this.options.position.scale);
2329
+ const sourceWidth = atlas.cellWidth;
2330
+ const sourceHeight = atlas.cellHeight;
2331
+ const backgroundWidth = atlas.columns * sourceWidth;
2332
+ const backgroundHeight = atlas.rows * sourceHeight;
2333
+ frameElement.style.width = `${sourceWidth}px`;
2334
+ frameElement.style.height = `${sourceHeight}px`;
2335
+ frameElement.style.overflow = "hidden";
2336
+ frameElement.style.transform = `scale(${scale})`;
2337
+ frameElement.style.transformOrigin = "top left";
2338
+ frameElement.style.pointerEvents = "none";
2339
+ frameElement.style.backgroundImage = `url("${escapeCssUrl(
2340
+ this.resolved.src
2341
+ )}")`;
2342
+ frameElement.style.backgroundRepeat = "no-repeat";
2343
+ frameElement.style.backgroundSize = `${backgroundWidth}px ${backgroundHeight}px`;
2344
+ frameElement.style.backgroundPosition = `${-safeFrame * sourceWidth}px ${-definition.row * sourceHeight}px`;
2345
+ frameElement.style.imageRendering = this.options.imageRendering;
2346
+ frameElement.dataset.petFrame = String(safeFrame);
2347
+ }
2348
+ scheduleNextFrame(animationName, animationMode) {
2349
+ if (this.prefersReducedMotion || this.completed || !this.resolved) {
2350
+ this.clearTimers();
2351
+ return;
2352
+ }
2353
+ if (this.frameTimer !== null) {
2354
+ return;
2355
+ }
2356
+ const atlas = this.resolved.atlas;
2357
+ const definition = atlas.animations[animationName] ?? atlas.animations.idle;
2358
+ const duration = definition.frameDurations[this.frame] ?? definition.frameDurations[definition.frameDurations.length - 1] ?? 150;
2359
+ const baseDuration = duration * PET_FRAME_DURATION_MULTIPLIER;
2360
+ const effectiveDuration = this.isHovering || this.isDragging ? baseDuration : baseDuration * PET_RESTING_FRAME_DURATION_MULTIPLIER;
2361
+ this.frameTimer = window.setTimeout(() => {
2362
+ this.frameTimer = null;
2363
+ const nextFrame = this.frame + 1;
2364
+ if (nextFrame >= definition.frames) {
2365
+ if (animationMode === "once") {
2366
+ this.completed = true;
2367
+ this.frame = Math.max(0, definition.frames - 1);
2368
+ this.finishTransient();
2369
+ return;
2370
+ }
2371
+ this.frame = 0;
2372
+ this.render();
2373
+ return;
2374
+ }
2375
+ this.frame = nextFrame;
2376
+ this.render();
2377
+ }, effectiveDuration);
2378
+ }
2379
+ clearTimers() {
2380
+ if (this.frameTimer !== null) {
2381
+ window.clearTimeout(this.frameTimer);
2382
+ this.frameTimer = null;
2383
+ }
2384
+ }
2385
+ clearRestingDelayTimer() {
2386
+ if (this.restingDelayTimer !== null) {
2387
+ window.clearTimeout(this.restingDelayTimer);
2388
+ this.restingDelayTimer = null;
2389
+ }
2390
+ }
2391
+ finishTransient() {
2392
+ this.transient = null;
2393
+ this.activeAnimationName = null;
2394
+ this.activeAnimationMode = null;
2395
+ this.render();
2396
+ }
2397
+ rescheduleAnimation() {
2398
+ this.clearTimers();
2399
+ this.render();
2400
+ }
2401
+ enterRestingAfterDelay() {
2402
+ this.clearRestingDelayTimer();
2403
+ this.isHovering = true;
2404
+ this.restingDelayTimer = window.setTimeout(() => {
2405
+ this.restingDelayTimer = null;
2406
+ if (this.isDragging) {
2407
+ return;
2408
+ }
2409
+ this.isHovering = false;
2410
+ this.rescheduleAnimation();
2411
+ }, PET_RESTING_DELAY_MS);
2412
+ }
2413
+ isPointOverPet(clientX, clientY) {
2414
+ var _a2;
2415
+ const rect = (_a2 = this.petElement) == null ? void 0 : _a2.getBoundingClientRect();
2416
+ if (!rect) {
2417
+ return false;
2418
+ }
2419
+ return clientX >= rect.left && clientX <= rect.right && clientY >= rect.top && clientY <= rect.bottom;
2420
+ }
2421
+ isPointerOverPet(event) {
2422
+ return this.isPointOverPet(event.clientX, event.clientY);
2423
+ }
2424
+ async submitReply() {
2425
+ var _a2;
2426
+ const text = this.replyDraft.trim();
2427
+ if (!text || this.isReplySubmitting) {
2428
+ return;
2429
+ }
2430
+ this.isReplySubmitting = true;
2431
+ this.replyError = null;
2432
+ this.render();
2433
+ try {
2434
+ await ((_a2 = this.onReply) == null ? void 0 : _a2.call(this, text));
2435
+ this.replyDraft = "";
2436
+ this.isReplyOpen = false;
2437
+ this.isSummaryHovering = false;
2438
+ } catch {
2439
+ this.replyError = "Failed to send";
2440
+ } finally {
2441
+ this.isReplySubmitting = false;
2442
+ this.render();
2443
+ }
2444
+ }
2445
+ getNextDragPosition(event) {
2446
+ if (!this.options) {
2447
+ return { x: 0, y: 0 };
2448
+ }
2449
+ return clampPetPosition(
2450
+ {
2451
+ x: event.clientX - this.dragOffset.x,
2452
+ y: event.clientY - this.dragOffset.y
2453
+ },
2454
+ this.getSize(),
2455
+ getViewportSize(),
2456
+ normalizeBoundsPadding(this.options.position.boundsPadding)
2457
+ );
2458
+ }
2459
+ installDragListeners() {
2460
+ window.addEventListener("pointermove", this.handlePointerMove);
2461
+ window.addEventListener("pointerup", this.handlePointerUp, { once: true });
2462
+ window.addEventListener("pointercancel", this.handlePointerUp, {
2463
+ once: true
2464
+ });
2465
+ }
2466
+ removeDragListeners() {
2467
+ window.removeEventListener("pointermove", this.handlePointerMove);
2468
+ window.removeEventListener("pointerup", this.handlePointerUp);
2469
+ window.removeEventListener("pointercancel", this.handlePointerUp);
2470
+ }
2471
+ }
886
2472
  function getInnerOptions(options) {
887
2473
  return removeMethods(options);
888
2474
  }
@@ -906,7 +2492,17 @@ class ChatKitElementBase extends (_c = HTMLElement, _focusComposer_dec = [requir
906
2492
  __privateAdd(this, _frameUrl);
907
2493
  __privateAdd(this, _frame);
908
2494
  __privateAdd(this, _wrapper);
2495
+ __privateAdd(this, _launcherCloseButton);
2496
+ __privateAdd(this, _launcherOpen, false);
2497
+ __privateAdd(this, _framePetOptionsOverride);
2498
+ __privateAdd(this, _petClosedByContextMenu, false);
909
2499
  __privateAdd(this, _shadow, this.attachShadow({ mode: "open" }));
2500
+ __privateAdd(this, _petOverlay, new PetOverlay(__privateGet(this, _shadow), {
2501
+ onActivate: () => __privateMethod(this, _ChatKitElementBase_instances, handlePetActivate_fn).call(this),
2502
+ onClose: () => __privateMethod(this, _ChatKitElementBase_instances, handlePetClose_fn).call(this),
2503
+ onReply: (text) => __privateMethod(this, _ChatKitElementBase_instances, handlePetReply_fn).call(this, text),
2504
+ onThreadSummaryActivate: (threadId) => void __privateMethod(this, _ChatKitElementBase_instances, handlePetThreadSummaryActivate_fn).call(this, threadId)
2505
+ }));
910
2506
  __privateAdd(this, _resolveLoaded);
911
2507
  __privateAdd(this, _loaded, new Promise((resolve) => {
912
2508
  __privateSet(this, _resolveLoaded, resolve);
@@ -1001,6 +2597,9 @@ class ChatKitElementBase extends (_c = HTMLElement, _focusComposer_dec = [requir
1001
2597
  }
1002
2598
  }
1003
2599
  }));
2600
+ __privateAdd(this, _handleLauncherClose, () => {
2601
+ __privateMethod(this, _ChatKitElementBase_instances, setLauncherOpen_fn).call(this, false);
2602
+ });
1004
2603
  __privateAdd(this, _handleFrameLoad, () => {
1005
2604
  var _a2;
1006
2605
  this.dataset.loaded = "true";
@@ -1018,6 +2617,7 @@ class ChatKitElementBase extends (_c = HTMLElement, _focusComposer_dec = [requir
1018
2617
  this.capabilities = getCapabilities(profile);
1019
2618
  }
1020
2619
  connectedCallback() {
2620
+ __privateGet(this, _petOverlay).connect();
1021
2621
  const style = document.createElement("style");
1022
2622
  style.textContent = `
1023
2623
  :host {
@@ -1025,6 +2625,10 @@ class ChatKitElementBase extends (_c = HTMLElement, _focusComposer_dec = [requir
1025
2625
  position: relative;
1026
2626
  height: 100%;
1027
2627
  width: 100%;
2628
+ overflow: visible;
2629
+ }
2630
+ :host([data-display-mode="pet"]) {
2631
+ display: contents;
1028
2632
  }
1029
2633
  .ck-iframe {
1030
2634
  border: none;
@@ -1043,12 +2647,115 @@ class ChatKitElementBase extends (_c = HTMLElement, _focusComposer_dec = [requir
1043
2647
  overflow: hidden;
1044
2648
  opacity: 0;
1045
2649
  }
2650
+ .ck-launcher-close {
2651
+ display: none;
2652
+ }
2653
+ :host([data-display-mode="pet"]) .ck-wrapper {
2654
+ position: fixed;
2655
+ inset: auto 16px 16px auto;
2656
+ width: min(420px, calc(100vw - 32px));
2657
+ height: min(720px, calc(100vh - 32px));
2658
+ max-height: calc(100vh - 32px);
2659
+ overflow: visible;
2660
+ border: 1px solid rgba(148, 163, 184, 0.35);
2661
+ border-radius: 18px;
2662
+ background: Canvas;
2663
+ box-shadow:
2664
+ 0 24px 80px rgba(15, 23, 42, 0.22),
2665
+ 0 0 0 1px rgba(15, 23, 42, 0.04);
2666
+ opacity: 0;
2667
+ pointer-events: none;
2668
+ transform: translateY(12px) scale(0.98);
2669
+ transition:
2670
+ opacity 160ms ease,
2671
+ transform 160ms ease;
2672
+ z-index: 39;
2673
+ }
2674
+ :host([data-display-mode="pet"][data-chat-open="true"]) .ck-wrapper {
2675
+ opacity: 1;
2676
+ pointer-events: auto;
2677
+ transform: translateY(0) scale(1);
2678
+ }
2679
+ :host([data-display-mode="pet"]) .ck-iframe {
2680
+ border-radius: inherit;
2681
+ }
2682
+ :host([data-display-mode="pet"]) .ck-launcher-close {
2683
+ display: inline-flex;
2684
+ position: absolute;
2685
+ top: -10px;
2686
+ right: -10px;
2687
+ z-index: 2;
2688
+ width: 28px;
2689
+ height: 28px;
2690
+ align-items: center;
2691
+ justify-content: center;
2692
+ border: 1px solid rgba(148, 163, 184, 0.45);
2693
+ border-radius: 999px;
2694
+ background: rgba(255, 255, 255, 0.96);
2695
+ color: #475569;
2696
+ box-shadow: 0 8px 24px rgba(15, 23, 42, 0.18);
2697
+ cursor: pointer;
2698
+ font: inherit;
2699
+ font-size: 0;
2700
+ line-height: 1;
2701
+ }
2702
+ :host([data-display-mode="pet"]) .ck-launcher-close::before,
2703
+ :host([data-display-mode="pet"]) .ck-launcher-close::after {
2704
+ content: '';
2705
+ position: absolute;
2706
+ top: 50%;
2707
+ left: 50%;
2708
+ width: 14px;
2709
+ height: 2px;
2710
+ border-radius: 999px;
2711
+ background: currentColor;
2712
+ transform: translate(-50%, -50%) rotate(45deg);
2713
+ }
2714
+ :host([data-display-mode="pet"]) .ck-launcher-close::after {
2715
+ transform: translate(-50%, -50%) rotate(-45deg);
2716
+ }
2717
+ :host([data-display-mode="pet"]) .ck-launcher-close:hover {
2718
+ background: #fff;
2719
+ color: #0f172a;
2720
+ }
1046
2721
  :host([data-color-scheme="dark"]) .ck-iframe {
1047
2722
  color-scheme: dark only;
1048
2723
  }
2724
+ :host([data-color-scheme="dark"][data-display-mode="pet"]) .ck-wrapper {
2725
+ border-color: rgba(148, 163, 184, 0.28);
2726
+ background: #020617;
2727
+ box-shadow:
2728
+ 0 24px 80px rgba(0, 0, 0, 0.5),
2729
+ 0 0 0 1px rgba(255, 255, 255, 0.06);
2730
+ }
2731
+ :host([data-color-scheme="dark"][data-display-mode="pet"]) .ck-launcher-close {
2732
+ background: rgba(15, 23, 42, 0.88);
2733
+ border-color: rgba(148, 163, 184, 0.32);
2734
+ color: #cbd5e1;
2735
+ }
2736
+ :host([data-color-scheme="dark"][data-display-mode="pet"]) .ck-launcher-close:hover {
2737
+ background: #1e293b;
2738
+ color: #f8fafc;
2739
+ }
1049
2740
  :host([data-loaded="true"]) .ck-wrapper {
1050
2741
  opacity: 1;
1051
2742
  }
2743
+ :host([data-display-mode="pet"]:not([data-chat-open="true"])) .ck-wrapper {
2744
+ opacity: 0;
2745
+ }
2746
+ @media (max-width: 520px) {
2747
+ :host([data-display-mode="pet"]) .ck-wrapper {
2748
+ inset: auto 8px 8px 8px;
2749
+ width: auto;
2750
+ height: min(680px, calc(100vh - 16px));
2751
+ max-height: calc(100vh - 16px);
2752
+ border-radius: 16px;
2753
+ }
2754
+ :host([data-display-mode="pet"]) .ck-launcher-close {
2755
+ top: -8px;
2756
+ right: 8px;
2757
+ }
2758
+ }
1052
2759
  `;
1053
2760
  const frame = document.createElement("iframe");
1054
2761
  frame.className = "ck-iframe";
@@ -1064,6 +2771,13 @@ class ChatKitElementBase extends (_c = HTMLElement, _focusComposer_dec = [requir
1064
2771
  wrapper.className = "ck-wrapper";
1065
2772
  wrapper.appendChild(frame);
1066
2773
  __privateSet(this, _wrapper, wrapper);
2774
+ const closeButton = document.createElement("button");
2775
+ closeButton.className = "ck-launcher-close";
2776
+ closeButton.type = "button";
2777
+ closeButton.setAttribute("aria-label", "Close chat");
2778
+ closeButton.addEventListener("click", __privateGet(this, _handleLauncherClose));
2779
+ wrapper.appendChild(closeButton);
2780
+ __privateSet(this, _launcherCloseButton, closeButton);
1067
2781
  __privateGet(this, _shadow).append(style);
1068
2782
  __privateGet(this, _messenger).on("left_header_icon_click", () => {
1069
2783
  var _a2, _b2, _c2;
@@ -1074,6 +2788,18 @@ class ChatKitElementBase extends (_c = HTMLElement, _focusComposer_dec = [requir
1074
2788
  (_c2 = (_b2 = (_a2 = __privateGet(this, _opts)) == null ? void 0 : _a2.header) == null ? void 0 : _b2.rightAction) == null ? void 0 : _c2.onClick();
1075
2789
  });
1076
2790
  __privateGet(this, _messenger).on("public_event", ([event, data]) => {
2791
+ if (event === "log") {
2792
+ const payload = parseThreadSummaryLogPayload(data);
2793
+ if (payload) {
2794
+ __privateGet(this, _petOverlay).setThreadSummary(payload.summary);
2795
+ }
2796
+ } else if (event === "response.start") {
2797
+ __privateGet(this, _petOverlay).setThreadSummaryStatus("running");
2798
+ } else if (event === "response.end") {
2799
+ __privateGet(this, _petOverlay).setThreadSummaryStatus("completed");
2800
+ } else if (event === "response.stop") {
2801
+ __privateGet(this, _petOverlay).setThreadSummaryStatus("completed");
2802
+ }
1077
2803
  if (!this.capabilities.events.has(event)) return;
1078
2804
  if (event === "error" && "error" in data) {
1079
2805
  const error = fromPossibleFrameSafeError(data.error);
@@ -1087,6 +2813,22 @@ class ChatKitElementBase extends (_c = HTMLElement, _focusComposer_dec = [requir
1087
2813
  }
1088
2814
  this.dispatchEvent(new CustomEvent(`chatkit.${event}`, { detail: data }));
1089
2815
  });
2816
+ __privateGet(this, _messenger).on("pet_state_change", (data) => {
2817
+ const payload = parsePetStateChangePayload(data);
2818
+ if (payload) {
2819
+ __privateGet(this, _petOverlay).setState(payload.state);
2820
+ }
2821
+ });
2822
+ __privateGet(this, _messenger).on("pet_options_change", (data) => {
2823
+ const payload = parsePetOptionsChangePayload(data);
2824
+ if (payload) {
2825
+ if (!__privateGet(this, _petClosedByContextMenu) || payload.pet === null) {
2826
+ __privateSet(this, _petClosedByContextMenu, false);
2827
+ }
2828
+ __privateSet(this, _framePetOptionsOverride, payload.pet);
2829
+ __privateGet(this, _petOverlay).setOptions(__privateMethod(this, _ChatKitElementBase_instances, getOverlayPetOptions_fn).call(this));
2830
+ }
2831
+ });
1090
2832
  __privateGet(this, _messenger).on("unmount", () => {
1091
2833
  if (__privateGet(this, _wrapper) && __privateGet(this, _shadow).contains(__privateGet(this, _wrapper))) {
1092
2834
  __privateGet(this, _shadow).removeChild(__privateGet(this, _wrapper));
@@ -1109,16 +2851,26 @@ class ChatKitElementBase extends (_c = HTMLElement, _focusComposer_dec = [requir
1109
2851
  }
1110
2852
  }
1111
2853
  disconnectedCallback() {
1112
- var _a2;
2854
+ var _a2, _b2;
1113
2855
  (_a2 = __privateGet(this, _frame)) == null ? void 0 : _a2.removeEventListener("load", __privateGet(this, _handleFrameLoad));
2856
+ (_b2 = __privateGet(this, _launcherCloseButton)) == null ? void 0 : _b2.removeEventListener(
2857
+ "click",
2858
+ __privateGet(this, _handleLauncherClose)
2859
+ );
1114
2860
  __privateGet(this, _messenger).disconnect();
2861
+ __privateGet(this, _petOverlay).destroy();
1115
2862
  }
1116
2863
  applySanitizedOptions(newOptions) {
1117
2864
  __privateSet(this, _opts, newOptions);
2865
+ __privateSet(this, _petClosedByContextMenu, false);
2866
+ __privateGet(this, _petOverlay).setLocale(newOptions.locale);
2867
+ __privateGet(this, _petOverlay).setOptions(__privateMethod(this, _ChatKitElementBase_instances, getOverlayPetOptions_fn).call(this));
1118
2868
  if (__privateGet(this, _initialized)) {
1119
2869
  __privateMethod(this, _ChatKitElementBase_instances, setOptionsDataAttributes_fn).call(this, __privateGet(this, _opts));
1120
2870
  __privateGet(this, _loaded).then(() => {
1121
- __privateGet(this, _messenger).commands.setOptions(getInnerOptions(newOptions));
2871
+ __privateGet(this, _messenger).commands.setOptions(
2872
+ getInnerOptions(__privateMethod(this, _ChatKitElementBase_instances, getFrameOptions_fn).call(this, newOptions))
2873
+ );
1122
2874
  });
1123
2875
  } else {
1124
2876
  __privateMethod(this, _ChatKitElementBase_instances, maybeInit_fn).call(this);
@@ -1190,7 +2942,12 @@ _opts = new WeakMap();
1190
2942
  _frameUrl = new WeakMap();
1191
2943
  _frame = new WeakMap();
1192
2944
  _wrapper = new WeakMap();
2945
+ _launcherCloseButton = new WeakMap();
2946
+ _launcherOpen = new WeakMap();
2947
+ _framePetOptionsOverride = new WeakMap();
2948
+ _petClosedByContextMenu = new WeakMap();
1193
2949
  _shadow = new WeakMap();
2950
+ _petOverlay = new WeakMap();
1194
2951
  _resolveLoaded = new WeakMap();
1195
2952
  _loaded = new WeakMap();
1196
2953
  _messenger = new WeakMap();
@@ -1202,7 +2959,109 @@ emitAndThrow_fn = function(error) {
1202
2959
  setOptionsDataAttributes_fn = function(options) {
1203
2960
  var _a2;
1204
2961
  this.dataset.colorScheme = typeof options.theme === "string" ? options.theme : ((_a2 = options.theme) == null ? void 0 : _a2.colorScheme) ?? "light";
2962
+ this.dataset.displayMode = __privateMethod(this, _ChatKitElementBase_instances, getDisplayMode_fn).call(this, options);
2963
+ if (__privateMethod(this, _ChatKitElementBase_instances, getDisplayMode_fn).call(this, options) !== "pet") {
2964
+ __privateMethod(this, _ChatKitElementBase_instances, setLauncherOpen_fn).call(this, false);
2965
+ }
2966
+ };
2967
+ getDisplayMode_fn = function(options = __privateGet(this, _opts)) {
2968
+ return (options == null ? void 0 : options.displayMode) === "pet" ? "pet" : "chat";
2969
+ };
2970
+ getConfiguredPetOptions_fn = function(options = __privateGet(this, _opts)) {
2971
+ if (!options) {
2972
+ return null;
2973
+ }
2974
+ if (__privateMethod(this, _ChatKitElementBase_instances, getDisplayMode_fn).call(this, options) === "pet" && !normalizePetOptions(options.pet ?? null)) {
2975
+ return true;
2976
+ }
2977
+ return options.pet ?? null;
2978
+ };
2979
+ getOverlayPetOptions_fn = function() {
2980
+ if (__privateGet(this, _petClosedByContextMenu)) {
2981
+ return null;
2982
+ }
2983
+ let pet = __privateGet(this, _framePetOptionsOverride) !== void 0 ? __privateGet(this, _framePetOptionsOverride) : __privateMethod(this, _ChatKitElementBase_instances, getConfiguredPetOptions_fn).call(this);
2984
+ if (__privateMethod(this, _ChatKitElementBase_instances, getDisplayMode_fn).call(this) === "pet" && !normalizePetOptions(pet ?? null)) {
2985
+ pet = true;
2986
+ }
2987
+ return __privateMethod(this, _ChatKitElementBase_instances, resolveOverlayPetOptions_fn).call(this, pet);
2988
+ };
2989
+ resolvePetAssetUrl_fn = function(src) {
2990
+ try {
2991
+ const base = new URL(
2992
+ __privateGet(this, _frameUrl) ?? window.location.href,
2993
+ window.location.origin
2994
+ );
2995
+ return new URL(src, base).toString();
2996
+ } catch {
2997
+ return src;
2998
+ }
2999
+ };
3000
+ resolveOverlayPetOptions_fn = function(pet) {
3001
+ const normalized = normalizePetOptions(pet ?? null);
3002
+ if (!normalized) {
3003
+ return null;
3004
+ }
3005
+ return {
3006
+ character: {
3007
+ ...normalized.character,
3008
+ src: __privateMethod(this, _ChatKitElementBase_instances, resolvePetAssetUrl_fn).call(this, normalized.character.src)
3009
+ },
3010
+ position: normalized.position,
3011
+ behavior: normalized.behavior,
3012
+ ariaLabel: normalized.ariaLabel,
3013
+ imageRendering: normalized.imageRendering
3014
+ };
3015
+ };
3016
+ getFrameOptions_fn = function(options) {
3017
+ const pet = __privateMethod(this, _ChatKitElementBase_instances, getConfiguredPetOptions_fn).call(this, options);
3018
+ if (pet === (options.pet ?? null)) {
3019
+ return options;
3020
+ }
3021
+ const nextOptions = { ...options };
3022
+ if (pet === null) {
3023
+ delete nextOptions.pet;
3024
+ } else {
3025
+ nextOptions.pet = pet;
3026
+ }
3027
+ return nextOptions;
3028
+ };
3029
+ setLauncherOpen_fn = function(open) {
3030
+ __privateSet(this, _launcherOpen, open);
3031
+ if (open) {
3032
+ this.dataset.chatOpen = "true";
3033
+ } else {
3034
+ delete this.dataset.chatOpen;
3035
+ }
3036
+ };
3037
+ handlePetActivate_fn = function() {
3038
+ if (__privateMethod(this, _ChatKitElementBase_instances, getDisplayMode_fn).call(this) !== "pet") {
3039
+ return;
3040
+ }
3041
+ __privateMethod(this, _ChatKitElementBase_instances, setLauncherOpen_fn).call(this, true);
3042
+ __privateGet(this, _loaded).then(() => this.focusComposer()).catch(() => void 0);
3043
+ };
3044
+ handlePetClose_fn = function() {
3045
+ __privateSet(this, _petClosedByContextMenu, true);
3046
+ __privateSet(this, _framePetOptionsOverride, null);
3047
+ __privateMethod(this, _ChatKitElementBase_instances, setLauncherOpen_fn).call(this, false);
3048
+ __privateGet(this, _petOverlay).setOptions(null);
3049
+ if (__privateMethod(this, _ChatKitElementBase_instances, getDisplayMode_fn).call(this) === "pet") {
3050
+ return;
3051
+ }
3052
+ __privateGet(this, _loaded).then(() => __privateGet(this, _messenger).commands.setPetEnabled({ enabled: false })).catch(() => void 0);
3053
+ };
3054
+ handlePetReply_fn = async function(text) {
3055
+ await this.sendUserMessage({ text });
3056
+ };
3057
+ handlePetThreadSummaryActivate_fn = async function(threadId) {
3058
+ if (__privateMethod(this, _ChatKitElementBase_instances, getDisplayMode_fn).call(this) === "pet") {
3059
+ __privateMethod(this, _ChatKitElementBase_instances, setLauncherOpen_fn).call(this, true);
3060
+ }
3061
+ await this.setThreadId(threadId);
3062
+ await this.focusComposer();
1205
3063
  };
3064
+ _handleLauncherClose = new WeakMap();
1206
3065
  getFrameUrl_fn = function() {
1207
3066
  if (!__privateGet(this, _frameUrl)) {
1208
3067
  throw new IntegrationError2(
@@ -1242,7 +3101,7 @@ maybeInit_fn = function() {
1242
3101
  const frameURL = new URL(__privateMethod(this, _ChatKitElementBase_instances, getFrameUrl_fn).call(this), window.location.origin);
1243
3102
  __privateGet(this, _messenger).setTargetOrigin(frameURL.origin);
1244
3103
  frameURL.hash = encodeBase64({
1245
- options: getInnerOptions(__privateGet(this, _opts)),
3104
+ options: getInnerOptions(__privateMethod(this, _ChatKitElementBase_instances, getFrameOptions_fn).call(this, __privateGet(this, _opts))),
1246
3105
  referrer: window.location.origin,
1247
3106
  profile: this.profile
1248
3107
  });