@xpert-ai/chatkit-web-component 0.2.0 → 0.3.0

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, _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, 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,1191 @@ 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_OVERLAY_COPY = {
1141
+ "en-US": {
1142
+ hideMessage: "Hide message",
1143
+ expandMessage: "Expand message",
1144
+ collapseMessage: "Collapse message",
1145
+ restoreMessage: "Show message",
1146
+ replyButton: "Reply",
1147
+ replyPlaceholder: "Reply...",
1148
+ sendButton: "Send",
1149
+ sendingButton: "Sending...",
1150
+ sendFailed: "Failed to send"
1151
+ },
1152
+ "zh-CN": {
1153
+ hideMessage: "隐藏消息",
1154
+ expandMessage: "展开消息",
1155
+ collapseMessage: "收起消息",
1156
+ restoreMessage: "显示消息",
1157
+ replyButton: "回复",
1158
+ replyPlaceholder: "输入回复...",
1159
+ sendButton: "发送",
1160
+ sendingButton: "发送中...",
1161
+ sendFailed: "发送失败"
1162
+ }
1163
+ };
1164
+ function stopEventPropagation(event) {
1165
+ event.stopPropagation();
1166
+ }
1167
+ function getViewportSize() {
1168
+ const visualViewport = window.visualViewport;
1169
+ return {
1170
+ width: (visualViewport == null ? void 0 : visualViewport.width) || window.innerWidth || 320,
1171
+ height: (visualViewport == null ? void 0 : visualViewport.height) || window.innerHeight || 480
1172
+ };
1173
+ }
1174
+ function readPersistedPosition(storageKey, persist) {
1175
+ if (!persist) {
1176
+ return null;
1177
+ }
1178
+ try {
1179
+ const raw = window.localStorage.getItem(storageKey);
1180
+ if (!raw) {
1181
+ return null;
1182
+ }
1183
+ const parsed = JSON.parse(raw);
1184
+ if (!parsed || typeof parsed !== "object" || typeof parsed.x !== "number" || typeof parsed.y !== "number") {
1185
+ return null;
1186
+ }
1187
+ return { x: parsed.x, y: parsed.y };
1188
+ } catch {
1189
+ return null;
1190
+ }
1191
+ }
1192
+ function writePersistedPosition(storageKey, persist, position) {
1193
+ if (!persist) {
1194
+ return;
1195
+ }
1196
+ try {
1197
+ window.localStorage.setItem(storageKey, JSON.stringify(position));
1198
+ } catch {
1199
+ }
1200
+ }
1201
+ function escapeCssUrl(value) {
1202
+ return value.replace(/["\\]/g, "\\$&");
1203
+ }
1204
+ function getRenderScale(scale) {
1205
+ return Math.max(0.1, scale) * PET_BASE_RENDER_SCALE;
1206
+ }
1207
+ function clampNumber(value, min, max) {
1208
+ return Math.min(max, Math.max(min, value));
1209
+ }
1210
+ function getDefaultLocale() {
1211
+ if (typeof window !== "undefined") {
1212
+ try {
1213
+ const stored = window.localStorage.getItem("chatkit:locale");
1214
+ if (stored) {
1215
+ return stored;
1216
+ }
1217
+ } catch {
1218
+ }
1219
+ }
1220
+ return typeof navigator !== "undefined" ? navigator.language : null;
1221
+ }
1222
+ function resolveCopyLocale(locale) {
1223
+ const normalized = (locale ?? getDefaultLocale() ?? "").trim().toLowerCase();
1224
+ if (normalized === "zh-cn" || normalized === "zh-hans" || normalized.startsWith("zh")) {
1225
+ return "zh-CN";
1226
+ }
1227
+ return "en-US";
1228
+ }
1229
+ function isPetState(value) {
1230
+ return value === "idle" || value === "running-right" || value === "running-left" || value === "waving" || value === "jumping" || value === "failed" || value === "waiting" || value === "running" || value === "review";
1231
+ }
1232
+ function parsePetStateChangePayload(value) {
1233
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1234
+ return null;
1235
+ }
1236
+ const payload = value;
1237
+ return isPetState(payload.state) ? { state: payload.state } : null;
1238
+ }
1239
+ function parsePetOptionsChangePayload(value) {
1240
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1241
+ return null;
1242
+ }
1243
+ const payload = value;
1244
+ if (payload.pet === null || typeof payload.pet === "boolean") {
1245
+ return { pet: payload.pet };
1246
+ }
1247
+ if (payload.pet && typeof payload.pet === "object" && !Array.isArray(payload.pet)) {
1248
+ return { pet: payload.pet };
1249
+ }
1250
+ return null;
1251
+ }
1252
+ function isThreadSummaryStatus(value) {
1253
+ return value === "running" || value === "completed" || value === "failed";
1254
+ }
1255
+ function getThreadSummaryKey(summary) {
1256
+ if (!summary) {
1257
+ return null;
1258
+ }
1259
+ return [
1260
+ summary.threadId,
1261
+ summary.messageId || summary.updatedAt || summary.message
1262
+ ].join(":");
1263
+ }
1264
+ function parseThreadSummaryPayload(value) {
1265
+ if (value === null) {
1266
+ return { summary: null };
1267
+ }
1268
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1269
+ return null;
1270
+ }
1271
+ const payload = value;
1272
+ 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)) {
1273
+ return null;
1274
+ }
1275
+ return {
1276
+ summary: {
1277
+ threadId: payload.threadId,
1278
+ title: payload.title,
1279
+ message: payload.message,
1280
+ status: payload.status,
1281
+ ...typeof payload.messageId === "string" && payload.messageId.trim() ? { messageId: payload.messageId } : {},
1282
+ ...typeof payload.updatedAt === "string" && payload.updatedAt.trim() ? { updatedAt: payload.updatedAt } : {}
1283
+ }
1284
+ };
1285
+ }
1286
+ function parseThreadSummaryLogPayload(value) {
1287
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
1288
+ return null;
1289
+ }
1290
+ const payload = value;
1291
+ if (payload.name !== "thread.summary") {
1292
+ return null;
1293
+ }
1294
+ return parseThreadSummaryPayload(payload.data ?? null);
1295
+ }
1296
+ class PetOverlay {
1297
+ constructor(root, options) {
1298
+ this.overlayElement = null;
1299
+ this.petElement = null;
1300
+ this.summaryElement = null;
1301
+ this.summaryToggleElement = null;
1302
+ this.mediaElement = null;
1303
+ this.options = null;
1304
+ this.resolved = null;
1305
+ this.summary = null;
1306
+ this.summaryRenderKey = null;
1307
+ this.dismissedSummaryKey = null;
1308
+ this.isSummaryCollapsed = false;
1309
+ this.isSummaryExpanded = false;
1310
+ this.isSummaryHovering = false;
1311
+ this.isReplyOpen = false;
1312
+ this.isReplySubmitting = false;
1313
+ this.replyError = null;
1314
+ this.replyDraft = "";
1315
+ this.replyInputElement = null;
1316
+ this.copyLocale = resolveCopyLocale();
1317
+ this.copy = PET_OVERLAY_COPY[this.copyLocale];
1318
+ this.currentState = "waiting";
1319
+ this.lastAutoState = "waiting";
1320
+ this.transient = null;
1321
+ this.position = null;
1322
+ this.dragPosition = null;
1323
+ this.dragOffset = { x: 0, y: 0 };
1324
+ this.lastDragPosition = null;
1325
+ this.lastDragClientX = null;
1326
+ this.dragAnimation = null;
1327
+ this.isDragging = false;
1328
+ this.isHovering = false;
1329
+ this.movedDuringDrag = false;
1330
+ this.prefersReducedMotion = false;
1331
+ this.frame = 0;
1332
+ this.completed = false;
1333
+ this.activeAnimationName = null;
1334
+ this.activeAnimationMode = null;
1335
+ this.frameTimer = null;
1336
+ this.restingDelayTimer = null;
1337
+ this.mediaQuery = null;
1338
+ this.connected = false;
1339
+ this.handleViewportChange = () => {
1340
+ this.render();
1341
+ };
1342
+ this.handleReducedMotionChange = () => {
1343
+ var _a2;
1344
+ this.prefersReducedMotion = Boolean((_a2 = this.mediaQuery) == null ? void 0 : _a2.matches);
1345
+ if (this.prefersReducedMotion) {
1346
+ this.transient = null;
1347
+ }
1348
+ this.render();
1349
+ };
1350
+ this.handlePointerEnter = () => {
1351
+ this.clearRestingDelayTimer();
1352
+ this.isHovering = true;
1353
+ this.rescheduleAnimation();
1354
+ };
1355
+ this.handlePointerLeave = () => {
1356
+ if (!this.isDragging) {
1357
+ this.enterRestingAfterDelay();
1358
+ }
1359
+ };
1360
+ this.handleSummaryPointerEnter = () => {
1361
+ this.isSummaryHovering = true;
1362
+ this.render();
1363
+ };
1364
+ this.handleSummaryPointerLeave = () => {
1365
+ this.isSummaryHovering = false;
1366
+ if (!this.isReplyOpen) {
1367
+ this.render();
1368
+ }
1369
+ };
1370
+ this.handleSummaryClick = () => {
1371
+ var _a2, _b2;
1372
+ const threadId = (_a2 = this.summary) == null ? void 0 : _a2.threadId.trim();
1373
+ if (!threadId) {
1374
+ return;
1375
+ }
1376
+ (_b2 = this.onThreadSummaryActivate) == null ? void 0 : _b2.call(this, threadId);
1377
+ };
1378
+ this.handleSummaryDelete = () => {
1379
+ const summaryKey = getThreadSummaryKey(this.summary);
1380
+ if (summaryKey) {
1381
+ this.dismissedSummaryKey = summaryKey;
1382
+ }
1383
+ this.isSummaryCollapsed = false;
1384
+ this.isReplyOpen = false;
1385
+ this.replyDraft = "";
1386
+ this.replyError = null;
1387
+ this.removeSummaryElements();
1388
+ };
1389
+ this.handleSummaryCollapseToggle = () => {
1390
+ this.isSummaryCollapsed = !this.isSummaryCollapsed;
1391
+ this.isSummaryExpanded = false;
1392
+ this.isReplyOpen = false;
1393
+ this.replyError = null;
1394
+ this.render();
1395
+ };
1396
+ this.handleSummaryExpandToggle = () => {
1397
+ this.isSummaryExpanded = !this.isSummaryExpanded;
1398
+ this.render();
1399
+ };
1400
+ this.handleReplyOpen = () => {
1401
+ this.isReplyOpen = true;
1402
+ this.replyError = null;
1403
+ this.render();
1404
+ };
1405
+ this.handleReplyInput = (event) => {
1406
+ const target = event.currentTarget;
1407
+ if (target instanceof HTMLInputElement) {
1408
+ this.replyDraft = target.value;
1409
+ this.replyError = null;
1410
+ }
1411
+ };
1412
+ this.handleReplySubmit = (event) => {
1413
+ event.preventDefault();
1414
+ void this.submitReply();
1415
+ };
1416
+ this.handleReplyKeyDown = (event) => {
1417
+ if (event.key !== "Escape") {
1418
+ return;
1419
+ }
1420
+ event.preventDefault();
1421
+ this.isReplyOpen = false;
1422
+ this.replyError = null;
1423
+ this.render();
1424
+ };
1425
+ this.handlePointerDown = (event) => {
1426
+ var _a2, _b2;
1427
+ if (!((_a2 = this.options) == null ? void 0 : _a2.position.draggable) || event.button !== 0) {
1428
+ return;
1429
+ }
1430
+ event.preventDefault();
1431
+ const rect = (_b2 = this.petElement) == null ? void 0 : _b2.getBoundingClientRect();
1432
+ if (!rect) {
1433
+ return;
1434
+ }
1435
+ const nextPosition = {
1436
+ x: rect.left,
1437
+ y: rect.top
1438
+ };
1439
+ this.dragOffset = {
1440
+ x: event.clientX - rect.left,
1441
+ y: event.clientY - rect.top
1442
+ };
1443
+ this.lastDragPosition = nextPosition;
1444
+ this.lastDragClientX = event.clientX;
1445
+ this.dragAnimation = null;
1446
+ this.movedDuringDrag = false;
1447
+ this.dragPosition = nextPosition;
1448
+ this.isDragging = true;
1449
+ this.clearRestingDelayTimer();
1450
+ this.isHovering = true;
1451
+ this.installDragListeners();
1452
+ this.rescheduleAnimation();
1453
+ };
1454
+ this.handlePointerMove = (event) => {
1455
+ const nextPosition = this.getNextDragPosition(event);
1456
+ const last = this.lastDragPosition;
1457
+ if (last && (Math.abs(last.x - nextPosition.x) > DRAG_DIRECTION_THRESHOLD_PX || Math.abs(last.y - nextPosition.y) > DRAG_DIRECTION_THRESHOLD_PX)) {
1458
+ this.movedDuringDrag = true;
1459
+ }
1460
+ if (this.lastDragClientX !== null) {
1461
+ const deltaX = event.clientX - this.lastDragClientX;
1462
+ if (deltaX > DRAG_DIRECTION_THRESHOLD_PX) {
1463
+ this.dragAnimation = "running-right";
1464
+ } else if (deltaX < -DRAG_DIRECTION_THRESHOLD_PX) {
1465
+ this.dragAnimation = "running-left";
1466
+ }
1467
+ }
1468
+ this.lastDragClientX = event.clientX;
1469
+ this.lastDragPosition = nextPosition;
1470
+ this.dragPosition = nextPosition;
1471
+ this.render();
1472
+ };
1473
+ this.handlePointerUp = (event) => {
1474
+ const finalPosition = this.lastDragPosition ?? this.getNextDragPosition(event);
1475
+ this.isDragging = false;
1476
+ this.dragPosition = null;
1477
+ this.dragAnimation = null;
1478
+ this.lastDragClientX = null;
1479
+ this.removeDragListeners();
1480
+ this.persistPosition(finalPosition);
1481
+ if (event.pointerType === "mouse" && this.isPointerOverPet(event)) {
1482
+ this.isHovering = true;
1483
+ this.rescheduleAnimation();
1484
+ } else {
1485
+ this.enterRestingAfterDelay();
1486
+ this.rescheduleAnimation();
1487
+ }
1488
+ };
1489
+ this.handleClick = () => {
1490
+ var _a2;
1491
+ if (this.movedDuringDrag) {
1492
+ return;
1493
+ }
1494
+ (_a2 = this.onActivate) == null ? void 0 : _a2.call(this);
1495
+ if (this.prefersReducedMotion) {
1496
+ return;
1497
+ }
1498
+ this.transient = { name: "waving" };
1499
+ this.render();
1500
+ };
1501
+ this.root = root;
1502
+ this.onActivate = options == null ? void 0 : options.onActivate;
1503
+ this.onReply = options == null ? void 0 : options.onReply;
1504
+ this.onThreadSummaryActivate = options == null ? void 0 : options.onThreadSummaryActivate;
1505
+ this.connect();
1506
+ }
1507
+ connect() {
1508
+ if (this.connected) {
1509
+ return;
1510
+ }
1511
+ this.connected = true;
1512
+ this.installViewportListeners();
1513
+ this.installReducedMotionListener();
1514
+ this.render();
1515
+ }
1516
+ setOptions(pet) {
1517
+ const nextOptions = normalizePetOptions(pet);
1518
+ this.options = nextOptions;
1519
+ if (!nextOptions) {
1520
+ this.isDragging = false;
1521
+ this.isHovering = false;
1522
+ this.position = null;
1523
+ this.dragPosition = null;
1524
+ this.dragAnimation = null;
1525
+ this.lastDragPosition = null;
1526
+ this.lastDragClientX = null;
1527
+ this.transient = null;
1528
+ this.resolved = null;
1529
+ this.clearRestingDelayTimer();
1530
+ this.removeDragListeners();
1531
+ this.removeOverlay();
1532
+ return;
1533
+ }
1534
+ this.position = readPersistedPosition(
1535
+ DEFAULT_PET_STORAGE_KEY,
1536
+ nextOptions.position.persist
1537
+ );
1538
+ if (nextOptions.behavior === "auto" && !this.prefersReducedMotion) {
1539
+ this.transient = { name: "waving" };
1540
+ }
1541
+ this.resolveCharacter();
1542
+ this.render();
1543
+ }
1544
+ setState(state) {
1545
+ var _a2;
1546
+ const previous = this.lastAutoState;
1547
+ this.lastAutoState = state;
1548
+ this.currentState = state;
1549
+ if (((_a2 = this.options) == null ? void 0 : _a2.behavior) === "auto" && !this.prefersReducedMotion && state === "idle" && (previous === "running" || previous === "review") && !this.transient) {
1550
+ this.transient = { name: "jumping" };
1551
+ } else if (state !== "idle") {
1552
+ this.transient = null;
1553
+ }
1554
+ this.render();
1555
+ }
1556
+ setLocale(locale) {
1557
+ const nextLocale = resolveCopyLocale(locale);
1558
+ if (nextLocale === this.copyLocale) {
1559
+ return;
1560
+ }
1561
+ this.copyLocale = nextLocale;
1562
+ this.copy = PET_OVERLAY_COPY[nextLocale];
1563
+ this.summaryRenderKey = null;
1564
+ this.render();
1565
+ }
1566
+ setThreadSummary(summary) {
1567
+ const previousKey = getThreadSummaryKey(this.summary);
1568
+ const nextKey = getThreadSummaryKey(summary);
1569
+ this.summary = summary;
1570
+ if (!summary) {
1571
+ this.isSummaryCollapsed = false;
1572
+ this.isSummaryExpanded = false;
1573
+ this.isSummaryHovering = false;
1574
+ this.isReplyOpen = false;
1575
+ this.isReplySubmitting = false;
1576
+ this.replyError = null;
1577
+ this.replyDraft = "";
1578
+ this.summaryRenderKey = null;
1579
+ this.removeSummaryElements();
1580
+ return;
1581
+ }
1582
+ if (previousKey !== nextKey) {
1583
+ this.isSummaryCollapsed = false;
1584
+ this.isSummaryExpanded = false;
1585
+ this.isSummaryHovering = false;
1586
+ this.isReplyOpen = false;
1587
+ this.isReplySubmitting = false;
1588
+ this.replyError = null;
1589
+ this.replyDraft = "";
1590
+ }
1591
+ this.render();
1592
+ }
1593
+ setThreadSummaryStatus(status) {
1594
+ if (!this.summary || this.summary.status === status) {
1595
+ return;
1596
+ }
1597
+ this.summary = { ...this.summary, status };
1598
+ this.render();
1599
+ }
1600
+ destroy() {
1601
+ var _a2, _b2, _c2, _d;
1602
+ if (!this.connected) {
1603
+ return;
1604
+ }
1605
+ this.connected = false;
1606
+ this.clearRestingDelayTimer();
1607
+ this.clearTimers();
1608
+ this.removeDragListeners();
1609
+ this.removeOverlay();
1610
+ window.removeEventListener("resize", this.handleViewportChange);
1611
+ (_a2 = window.visualViewport) == null ? void 0 : _a2.removeEventListener(
1612
+ "resize",
1613
+ this.handleViewportChange
1614
+ );
1615
+ (_b2 = window.visualViewport) == null ? void 0 : _b2.removeEventListener(
1616
+ "scroll",
1617
+ this.handleViewportChange
1618
+ );
1619
+ (_d = (_c2 = this.mediaQuery) == null ? void 0 : _c2.removeEventListener) == null ? void 0 : _d.call(
1620
+ _c2,
1621
+ "change",
1622
+ this.handleReducedMotionChange
1623
+ );
1624
+ this.mediaQuery = null;
1625
+ }
1626
+ installViewportListeners() {
1627
+ var _a2, _b2;
1628
+ window.addEventListener("resize", this.handleViewportChange);
1629
+ (_a2 = window.visualViewport) == null ? void 0 : _a2.addEventListener("resize", this.handleViewportChange);
1630
+ (_b2 = window.visualViewport) == null ? void 0 : _b2.addEventListener("scroll", this.handleViewportChange);
1631
+ }
1632
+ installReducedMotionListener() {
1633
+ var _a2, _b2;
1634
+ if (!window.matchMedia) {
1635
+ return;
1636
+ }
1637
+ this.mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
1638
+ this.prefersReducedMotion = this.mediaQuery.matches;
1639
+ (_b2 = (_a2 = this.mediaQuery).addEventListener) == null ? void 0 : _b2.call(
1640
+ _a2,
1641
+ "change",
1642
+ this.handleReducedMotionChange
1643
+ );
1644
+ }
1645
+ resolveCharacter() {
1646
+ if (!this.options) {
1647
+ this.resolved = null;
1648
+ return;
1649
+ }
1650
+ const character = this.options.character;
1651
+ this.resolved = resolvePetCharacter(character);
1652
+ }
1653
+ ensureOverlay() {
1654
+ if (this.overlayElement && this.petElement) {
1655
+ return;
1656
+ }
1657
+ const overlay = document.createElement("div");
1658
+ overlay.setAttribute("data-chatkit-host-pet-layer", "");
1659
+ overlay.style.position = "fixed";
1660
+ overlay.style.inset = "0";
1661
+ overlay.style.pointerEvents = "none";
1662
+ overlay.style.overflow = "visible";
1663
+ const style = document.createElement("style");
1664
+ style.textContent = `
1665
+ @keyframes chatkit-pet-summary-spin {
1666
+ to { transform: rotate(360deg); }
1667
+ }
1668
+ `;
1669
+ const pet = document.createElement("div");
1670
+ pet.setAttribute("data-chatkit-host-pet", "");
1671
+ pet.style.position = "absolute";
1672
+ pet.style.top = "0";
1673
+ pet.style.left = "0";
1674
+ pet.style.pointerEvents = "auto";
1675
+ pet.style.touchAction = "none";
1676
+ pet.style.userSelect = "none";
1677
+ pet.style.willChange = "transform";
1678
+ pet.addEventListener("pointerenter", this.handlePointerEnter);
1679
+ pet.addEventListener("pointerleave", this.handlePointerLeave);
1680
+ pet.addEventListener("pointerdown", this.handlePointerDown);
1681
+ pet.addEventListener("click", this.handleClick);
1682
+ overlay.append(style, pet);
1683
+ this.root.append(overlay);
1684
+ this.overlayElement = overlay;
1685
+ this.petElement = pet;
1686
+ }
1687
+ removeOverlay() {
1688
+ var _a2;
1689
+ this.clearRestingDelayTimer();
1690
+ this.clearTimers();
1691
+ if (this.petElement) {
1692
+ this.petElement.removeEventListener(
1693
+ "pointerenter",
1694
+ this.handlePointerEnter
1695
+ );
1696
+ this.petElement.removeEventListener(
1697
+ "pointerleave",
1698
+ this.handlePointerLeave
1699
+ );
1700
+ this.petElement.removeEventListener("pointerdown", this.handlePointerDown);
1701
+ this.petElement.removeEventListener("click", this.handleClick);
1702
+ }
1703
+ this.isHovering = false;
1704
+ this.removeSummaryElements();
1705
+ (_a2 = this.overlayElement) == null ? void 0 : _a2.remove();
1706
+ this.overlayElement = null;
1707
+ this.petElement = null;
1708
+ this.mediaElement = null;
1709
+ }
1710
+ removeSummaryElements() {
1711
+ var _a2, _b2;
1712
+ (_a2 = this.summaryElement) == null ? void 0 : _a2.remove();
1713
+ (_b2 = this.summaryToggleElement) == null ? void 0 : _b2.remove();
1714
+ this.summaryElement = null;
1715
+ this.summaryToggleElement = null;
1716
+ this.replyInputElement = null;
1717
+ this.summaryRenderKey = null;
1718
+ }
1719
+ getSize() {
1720
+ if (!this.options || !this.resolved) {
1721
+ return { width: 0, height: 0 };
1722
+ }
1723
+ const scale = getRenderScale(this.options.position.scale);
1724
+ const baseSize = {
1725
+ width: this.resolved.atlas.cellWidth,
1726
+ height: this.resolved.atlas.cellHeight
1727
+ };
1728
+ return {
1729
+ width: baseSize.width * scale,
1730
+ height: baseSize.height * scale
1731
+ };
1732
+ }
1733
+ getCurrentPosition(size) {
1734
+ const options = this.options;
1735
+ if (!options) {
1736
+ return { x: 0, y: 0 };
1737
+ }
1738
+ const viewport = getViewportSize();
1739
+ const padding = normalizeBoundsPadding(options.position.boundsPadding);
1740
+ const pin = options.position.pin === void 0 ? "bottom-right" : options.position.pin;
1741
+ const pinnedPosition = pin ? getPinnedPetPosition(pin, size, viewport, padding) : null;
1742
+ return clampPetPosition(
1743
+ this.dragPosition ?? this.position ?? pinnedPosition ?? { x: padding.left, y: padding.top },
1744
+ size,
1745
+ viewport,
1746
+ padding
1747
+ );
1748
+ }
1749
+ persistPosition(nextPosition) {
1750
+ if (!this.options) {
1751
+ return;
1752
+ }
1753
+ const size = this.getSize();
1754
+ const clamped = clampPetPosition(
1755
+ nextPosition,
1756
+ size,
1757
+ getViewportSize(),
1758
+ normalizeBoundsPadding(this.options.position.boundsPadding)
1759
+ );
1760
+ this.position = clamped;
1761
+ writePersistedPosition(
1762
+ DEFAULT_PET_STORAGE_KEY,
1763
+ this.options.position.persist,
1764
+ clamped
1765
+ );
1766
+ }
1767
+ getActiveAnimationName() {
1768
+ if (!this.options) {
1769
+ return "idle";
1770
+ }
1771
+ if (this.isDragging) {
1772
+ return this.dragAnimation ?? "running";
1773
+ }
1774
+ if (this.transient) {
1775
+ return this.transient.name;
1776
+ }
1777
+ if (this.options.behavior === "manual") {
1778
+ return "idle";
1779
+ }
1780
+ return this.currentState;
1781
+ }
1782
+ getActiveAnimationMode() {
1783
+ if (this.isDragging) {
1784
+ return "loop";
1785
+ }
1786
+ return this.transient ? "once" : "loop";
1787
+ }
1788
+ resetAnimationIfNeeded(name, mode) {
1789
+ if (this.activeAnimationName === name && this.activeAnimationMode === mode) {
1790
+ return;
1791
+ }
1792
+ this.clearTimers();
1793
+ this.activeAnimationName = name;
1794
+ this.activeAnimationMode = mode;
1795
+ this.frame = 0;
1796
+ this.completed = false;
1797
+ }
1798
+ render() {
1799
+ if (!this.options || !this.resolved) {
1800
+ this.clearTimers();
1801
+ if (this.petElement) {
1802
+ this.petElement.replaceChildren();
1803
+ }
1804
+ this.removeSummaryElements();
1805
+ this.mediaElement = null;
1806
+ this.activeAnimationName = null;
1807
+ this.activeAnimationMode = null;
1808
+ this.frame = 0;
1809
+ this.completed = false;
1810
+ return;
1811
+ }
1812
+ this.ensureOverlay();
1813
+ const overlay = this.overlayElement;
1814
+ const pet = this.petElement;
1815
+ if (!overlay || !pet) {
1816
+ return;
1817
+ }
1818
+ const size = this.getSize();
1819
+ const position = this.getCurrentPosition(size);
1820
+ const animationName = this.getActiveAnimationName();
1821
+ const animationMode = this.getActiveAnimationMode();
1822
+ this.resetAnimationIfNeeded(animationName, animationMode);
1823
+ overlay.style.zIndex = String(this.options.position.zIndex);
1824
+ pet.style.width = `${size.width}px`;
1825
+ pet.style.height = `${size.height}px`;
1826
+ pet.style.transform = `translate3d(${position.x}px, ${position.y}px, 0)`;
1827
+ pet.style.cursor = this.options.position.draggable ? this.isDragging ? "grabbing" : "grab" : "default";
1828
+ pet.dataset.petAnimation = animationName;
1829
+ pet.setAttribute("aria-label", this.options.ariaLabel);
1830
+ pet.setAttribute("role", "img");
1831
+ this.renderAtlas(animationName, animationMode);
1832
+ this.renderThreadSummary(position, size);
1833
+ this.scheduleNextFrame(animationName, animationMode);
1834
+ }
1835
+ renderThreadSummary(position, size) {
1836
+ var _a2, _b2, _c2;
1837
+ const summary = this.summary;
1838
+ const summaryKey = getThreadSummaryKey(summary);
1839
+ if (!summary || !summaryKey || this.dismissedSummaryKey === summaryKey) {
1840
+ this.removeSummaryElements();
1841
+ return;
1842
+ }
1843
+ if (this.isSummaryCollapsed) {
1844
+ this.renderCollapsedSummary(position, size);
1845
+ return;
1846
+ }
1847
+ const nextRenderKey = [
1848
+ summaryKey,
1849
+ summary.title,
1850
+ summary.message,
1851
+ summary.status,
1852
+ this.copyLocale,
1853
+ this.isSummaryExpanded ? "expanded" : "compact",
1854
+ this.isSummaryHovering ? "hover" : "rest",
1855
+ this.isReplyOpen ? "reply" : "closed",
1856
+ this.isReplySubmitting ? "submitting" : "ready",
1857
+ this.replyError ?? ""
1858
+ ].join("|");
1859
+ if (!this.summaryElement || this.summaryRenderKey !== nextRenderKey) {
1860
+ (_a2 = this.summaryElement) == null ? void 0 : _a2.remove();
1861
+ (_b2 = this.summaryToggleElement) == null ? void 0 : _b2.remove();
1862
+ this.summaryElement = this.createSummaryBubble(summary);
1863
+ this.summaryToggleElement = this.createSummaryToggleButton("v");
1864
+ (_c2 = this.overlayElement) == null ? void 0 : _c2.append(this.summaryElement, this.summaryToggleElement);
1865
+ this.summaryRenderKey = nextRenderKey;
1866
+ if (this.isReplyOpen && !this.isReplySubmitting) {
1867
+ window.setTimeout(() => {
1868
+ var _a3;
1869
+ return (_a3 = this.replyInputElement) == null ? void 0 : _a3.focus();
1870
+ }, 0);
1871
+ }
1872
+ }
1873
+ this.positionSummaryBubble(position, size);
1874
+ }
1875
+ renderCollapsedSummary(position, size) {
1876
+ var _a2, _b2;
1877
+ (_a2 = this.summaryElement) == null ? void 0 : _a2.remove();
1878
+ this.summaryElement = null;
1879
+ this.summaryRenderKey = null;
1880
+ if (!this.summaryToggleElement) {
1881
+ this.summaryToggleElement = this.createSummaryToggleButton("1");
1882
+ (_b2 = this.overlayElement) == null ? void 0 : _b2.append(this.summaryToggleElement);
1883
+ }
1884
+ this.summaryToggleElement.textContent = "1";
1885
+ this.positionSummaryToggleBadge(position, size);
1886
+ }
1887
+ positionSummaryToggleBadge(position, size) {
1888
+ const badge = this.summaryToggleElement;
1889
+ if (!badge) {
1890
+ return;
1891
+ }
1892
+ const viewport = getViewportSize();
1893
+ const badgeSize = 34;
1894
+ const x = clampNumber(
1895
+ position.x + size.width - badgeSize * 0.35,
1896
+ PET_SUMMARY_MARGIN,
1897
+ viewport.width - badgeSize - PET_SUMMARY_MARGIN
1898
+ );
1899
+ const y = clampNumber(
1900
+ position.y - badgeSize * 0.35,
1901
+ PET_SUMMARY_MARGIN,
1902
+ viewport.height - badgeSize - PET_SUMMARY_MARGIN
1903
+ );
1904
+ badge.style.width = `${badgeSize}px`;
1905
+ badge.style.height = `${badgeSize}px`;
1906
+ badge.style.transform = `translate3d(${x}px, ${y}px, 0)`;
1907
+ badge.style.borderRadius = "999px";
1908
+ }
1909
+ positionSummaryBubble(position, size) {
1910
+ const bubble = this.summaryElement;
1911
+ const toggle = this.summaryToggleElement;
1912
+ if (!bubble || !toggle) {
1913
+ return;
1914
+ }
1915
+ const viewport = getViewportSize();
1916
+ const width = Math.min(PET_SUMMARY_WIDTH, viewport.width - PET_SUMMARY_MARGIN * 2);
1917
+ bubble.style.width = `${width}px`;
1918
+ const bubbleHeight = bubble.offsetHeight || 96;
1919
+ const aboveY = position.y - bubbleHeight - PET_SUMMARY_GAP;
1920
+ const showAbove = aboveY >= PET_SUMMARY_MARGIN;
1921
+ const y = showAbove ? aboveY : clampNumber(
1922
+ position.y + size.height + PET_SUMMARY_GAP,
1923
+ PET_SUMMARY_MARGIN,
1924
+ viewport.height - bubbleHeight - PET_SUMMARY_MARGIN
1925
+ );
1926
+ const x = clampNumber(
1927
+ position.x + size.width / 2 - width / 2,
1928
+ PET_SUMMARY_MARGIN,
1929
+ viewport.width - width - PET_SUMMARY_MARGIN
1930
+ );
1931
+ bubble.style.transform = `translate3d(${x}px, ${y}px, 0)`;
1932
+ this.positionSummaryToggleBadge(position, size);
1933
+ }
1934
+ createSummaryBubble(summary) {
1935
+ const shouldShowReplyButton = this.isSummaryHovering && !this.isReplyOpen;
1936
+ const bubble = document.createElement("div");
1937
+ bubble.setAttribute("data-chatkit-pet-summary", "");
1938
+ bubble.addEventListener("pointerenter", this.handleSummaryPointerEnter);
1939
+ bubble.addEventListener("pointerleave", this.handleSummaryPointerLeave);
1940
+ bubble.addEventListener("click", this.handleSummaryClick);
1941
+ bubble.style.position = "absolute";
1942
+ bubble.style.top = "0";
1943
+ bubble.style.left = "0";
1944
+ bubble.style.boxSizing = "border-box";
1945
+ bubble.style.pointerEvents = "auto";
1946
+ bubble.style.padding = "12px 14px";
1947
+ bubble.style.paddingBottom = "12px";
1948
+ bubble.style.border = "1px solid rgba(148, 163, 184, 0.22)";
1949
+ bubble.style.borderRadius = "22px";
1950
+ bubble.style.background = "rgba(255, 255, 255, 0.94)";
1951
+ bubble.style.color = "#1f2937";
1952
+ bubble.style.boxShadow = "0 8px 24px rgba(15, 23, 42, 0.1)";
1953
+ bubble.style.font = '500 14px/1.35 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';
1954
+ bubble.style.backdropFilter = "blur(10px)";
1955
+ const header = document.createElement("div");
1956
+ header.style.display = "flex";
1957
+ header.style.alignItems = "center";
1958
+ header.style.gap = "8px";
1959
+ if (this.isSummaryHovering || this.isReplyOpen) {
1960
+ header.append(
1961
+ this.createSummaryActionButton(
1962
+ "x",
1963
+ this.copy.hideMessage,
1964
+ this.handleSummaryDelete
1965
+ )
1966
+ );
1967
+ }
1968
+ const title = document.createElement("div");
1969
+ title.textContent = summary.title;
1970
+ title.style.minWidth = "0";
1971
+ title.style.flex = "1";
1972
+ title.style.overflow = "hidden";
1973
+ title.style.textOverflow = "ellipsis";
1974
+ title.style.whiteSpace = "nowrap";
1975
+ title.style.fontWeight = "700";
1976
+ title.style.fontSize = "15px";
1977
+ header.append(title);
1978
+ if (this.isSummaryHovering || this.isReplyOpen) {
1979
+ header.append(
1980
+ this.createSummaryActionButton(
1981
+ this.isSummaryExpanded ? "-" : ">",
1982
+ this.isSummaryExpanded ? this.copy.collapseMessage : this.copy.expandMessage,
1983
+ this.handleSummaryExpandToggle
1984
+ )
1985
+ );
1986
+ } else {
1987
+ header.append(this.createStatusIcon(summary.status));
1988
+ }
1989
+ const message = document.createElement("div");
1990
+ message.textContent = summary.message;
1991
+ message.style.marginTop = "4px";
1992
+ message.style.fontWeight = "400";
1993
+ message.style.color = "#374151";
1994
+ message.style.overflow = "hidden";
1995
+ if (this.isSummaryExpanded) {
1996
+ message.style.maxHeight = "7em";
1997
+ message.style.overflowY = "auto";
1998
+ } else {
1999
+ message.style.display = "-webkit-box";
2000
+ message.style.setProperty("-webkit-line-clamp", "2");
2001
+ message.style.setProperty("-webkit-box-orient", "vertical");
2002
+ }
2003
+ bubble.append(header, message);
2004
+ if (shouldShowReplyButton) {
2005
+ const reply = this.createTextButton(
2006
+ this.copy.replyButton,
2007
+ this.handleReplyOpen
2008
+ );
2009
+ reply.style.position = "absolute";
2010
+ reply.style.right = "14px";
2011
+ reply.style.bottom = "10px";
2012
+ bubble.append(reply);
2013
+ }
2014
+ if (this.isReplyOpen) {
2015
+ bubble.append(this.createReplyForm());
2016
+ }
2017
+ return bubble;
2018
+ }
2019
+ createSummaryToggleButton(label) {
2020
+ const button = document.createElement("button");
2021
+ button.type = "button";
2022
+ button.textContent = label;
2023
+ button.title = label === "1" ? this.copy.restoreMessage : this.copy.collapseMessage;
2024
+ button.addEventListener("click", stopEventPropagation);
2025
+ button.addEventListener("click", this.handleSummaryCollapseToggle);
2026
+ button.style.position = "absolute";
2027
+ button.style.top = "0";
2028
+ button.style.left = "0";
2029
+ button.style.pointerEvents = "auto";
2030
+ button.style.border = "1px solid rgba(148, 163, 184, 0.28)";
2031
+ button.style.background = "rgba(248, 250, 252, 0.94)";
2032
+ button.style.color = "#475569";
2033
+ button.style.boxShadow = "0 6px 18px rgba(15, 23, 42, 0.1)";
2034
+ button.style.cursor = "pointer";
2035
+ button.style.font = '600 15px/1 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';
2036
+ button.style.display = "flex";
2037
+ button.style.alignItems = "center";
2038
+ button.style.justifyContent = "center";
2039
+ return button;
2040
+ }
2041
+ createStatusIcon(status) {
2042
+ const icon = document.createElement("span");
2043
+ icon.setAttribute("aria-hidden", "true");
2044
+ icon.style.display = "inline-flex";
2045
+ icon.style.width = "16px";
2046
+ icon.style.height = "16px";
2047
+ icon.style.alignItems = "center";
2048
+ icon.style.justifyContent = "center";
2049
+ icon.style.flex = "0 0 auto";
2050
+ if (status === "running") {
2051
+ icon.style.border = "2px solid rgba(71, 85, 105, 0.32)";
2052
+ icon.style.borderTopColor = "#64748b";
2053
+ icon.style.borderRadius = "999px";
2054
+ icon.style.animation = "chatkit-pet-summary-spin 900ms linear infinite";
2055
+ return icon;
2056
+ }
2057
+ icon.style.borderRadius = "999px";
2058
+ icon.style.fontSize = "12px";
2059
+ icon.style.fontWeight = "700";
2060
+ if (status === "failed") {
2061
+ icon.textContent = "!";
2062
+ icon.style.background = "#fee2e2";
2063
+ icon.style.color = "#b91c1c";
2064
+ return icon;
2065
+ }
2066
+ icon.textContent = "";
2067
+ icon.style.border = "2px solid #22c55e";
2068
+ icon.style.position = "relative";
2069
+ const check = document.createElement("span");
2070
+ check.style.width = "7px";
2071
+ check.style.height = "4px";
2072
+ check.style.borderLeft = "2px solid #22c55e";
2073
+ check.style.borderBottom = "2px solid #22c55e";
2074
+ check.style.transform = "rotate(-45deg) translate(1px, -1px)";
2075
+ icon.append(check);
2076
+ return icon;
2077
+ }
2078
+ createSummaryActionButton(label, title, onClick) {
2079
+ const button = document.createElement("button");
2080
+ button.type = "button";
2081
+ button.textContent = label;
2082
+ button.title = title;
2083
+ button.addEventListener("click", (event) => {
2084
+ event.preventDefault();
2085
+ event.stopPropagation();
2086
+ onClick();
2087
+ });
2088
+ button.style.width = "26px";
2089
+ button.style.height = "26px";
2090
+ button.style.border = "0";
2091
+ button.style.borderRadius = "999px";
2092
+ button.style.background = "rgba(241, 245, 249, 0.96)";
2093
+ button.style.color = "#475569";
2094
+ button.style.cursor = "pointer";
2095
+ button.style.font = '600 15px/1 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';
2096
+ return button;
2097
+ }
2098
+ createTextButton(label, onClick) {
2099
+ const button = document.createElement("button");
2100
+ button.type = "button";
2101
+ button.textContent = label;
2102
+ button.addEventListener("click", (event) => {
2103
+ event.preventDefault();
2104
+ event.stopPropagation();
2105
+ onClick();
2106
+ });
2107
+ button.style.border = "1px solid rgba(148, 163, 184, 0.28)";
2108
+ button.style.borderRadius = "999px";
2109
+ button.style.background = "rgba(248, 250, 252, 0.95)";
2110
+ button.style.color = "#334155";
2111
+ button.style.cursor = "pointer";
2112
+ button.style.padding = "3px 10px";
2113
+ button.style.font = '600 12px/1.4 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';
2114
+ return button;
2115
+ }
2116
+ createReplyForm() {
2117
+ const form = document.createElement("form");
2118
+ form.addEventListener("click", stopEventPropagation);
2119
+ form.addEventListener("submit", this.handleReplySubmit);
2120
+ form.addEventListener("keydown", this.handleReplyKeyDown);
2121
+ form.style.display = "flex";
2122
+ form.style.gap = "6px";
2123
+ form.style.alignItems = "center";
2124
+ form.style.marginTop = "8px";
2125
+ const input = document.createElement("input");
2126
+ input.type = "text";
2127
+ input.value = this.replyDraft;
2128
+ input.disabled = this.isReplySubmitting;
2129
+ input.placeholder = this.copy.replyPlaceholder;
2130
+ input.addEventListener("input", this.handleReplyInput);
2131
+ input.style.minWidth = "0";
2132
+ input.style.flex = "1";
2133
+ input.style.border = "1px solid rgba(148, 163, 184, 0.35)";
2134
+ input.style.borderRadius = "999px";
2135
+ input.style.padding = "6px 10px";
2136
+ input.style.font = '400 13px/1.2 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';
2137
+ this.replyInputElement = input;
2138
+ const send = document.createElement("button");
2139
+ send.type = "submit";
2140
+ send.textContent = this.isReplySubmitting ? this.copy.sendingButton : this.copy.sendButton;
2141
+ send.disabled = this.isReplySubmitting;
2142
+ send.style.border = "0";
2143
+ send.style.borderRadius = "999px";
2144
+ send.style.background = "#22c55e";
2145
+ send.style.color = "#052e16";
2146
+ send.style.cursor = this.isReplySubmitting ? "default" : "pointer";
2147
+ send.style.padding = "6px 10px";
2148
+ send.style.font = '700 12px/1.2 system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif';
2149
+ form.append(input, send);
2150
+ if (this.replyError) {
2151
+ const error = document.createElement("div");
2152
+ error.textContent = this.copy.sendFailed;
2153
+ error.style.flexBasis = "100%";
2154
+ error.style.color = "#b91c1c";
2155
+ error.style.fontSize = "12px";
2156
+ form.style.flexWrap = "wrap";
2157
+ form.append(error);
2158
+ }
2159
+ return form;
2160
+ }
2161
+ renderAtlas(animationName, animationMode) {
2162
+ var _a2;
2163
+ if (!this.petElement || ((_a2 = this.resolved) == null ? void 0 : _a2.kind) !== "atlas" || !this.options) {
2164
+ return;
2165
+ }
2166
+ if (!(this.mediaElement instanceof HTMLDivElement)) {
2167
+ const frame = document.createElement("div");
2168
+ frame.setAttribute("aria-hidden", "true");
2169
+ this.petElement.replaceChildren(frame);
2170
+ this.mediaElement = frame;
2171
+ }
2172
+ const frameElement = this.mediaElement;
2173
+ const atlas = this.resolved.atlas;
2174
+ const definition = atlas.animations[animationName] ?? atlas.animations.idle;
2175
+ const safeFrame = animationMode === "once" && this.completed ? Math.max(0, definition.frames - 1) : Math.min(this.frame, Math.max(0, definition.frames - 1));
2176
+ const scale = getRenderScale(this.options.position.scale);
2177
+ const sourceWidth = atlas.cellWidth;
2178
+ const sourceHeight = atlas.cellHeight;
2179
+ const backgroundWidth = atlas.columns * sourceWidth;
2180
+ const backgroundHeight = atlas.rows * sourceHeight;
2181
+ frameElement.style.width = `${sourceWidth}px`;
2182
+ frameElement.style.height = `${sourceHeight}px`;
2183
+ frameElement.style.overflow = "hidden";
2184
+ frameElement.style.transform = `scale(${scale})`;
2185
+ frameElement.style.transformOrigin = "top left";
2186
+ frameElement.style.pointerEvents = "none";
2187
+ frameElement.style.backgroundImage = `url("${escapeCssUrl(
2188
+ this.resolved.src
2189
+ )}")`;
2190
+ frameElement.style.backgroundRepeat = "no-repeat";
2191
+ frameElement.style.backgroundSize = `${backgroundWidth}px ${backgroundHeight}px`;
2192
+ frameElement.style.backgroundPosition = `${-safeFrame * sourceWidth}px ${-definition.row * sourceHeight}px`;
2193
+ frameElement.style.imageRendering = this.options.imageRendering;
2194
+ frameElement.dataset.petFrame = String(safeFrame);
2195
+ }
2196
+ scheduleNextFrame(animationName, animationMode) {
2197
+ if (this.prefersReducedMotion || this.completed || !this.resolved) {
2198
+ this.clearTimers();
2199
+ return;
2200
+ }
2201
+ if (this.frameTimer !== null) {
2202
+ return;
2203
+ }
2204
+ const atlas = this.resolved.atlas;
2205
+ const definition = atlas.animations[animationName] ?? atlas.animations.idle;
2206
+ const duration = definition.frameDurations[this.frame] ?? definition.frameDurations[definition.frameDurations.length - 1] ?? 150;
2207
+ const baseDuration = duration * PET_FRAME_DURATION_MULTIPLIER;
2208
+ const effectiveDuration = this.isHovering || this.isDragging ? baseDuration : baseDuration * PET_RESTING_FRAME_DURATION_MULTIPLIER;
2209
+ this.frameTimer = window.setTimeout(() => {
2210
+ this.frameTimer = null;
2211
+ const nextFrame = this.frame + 1;
2212
+ if (nextFrame >= definition.frames) {
2213
+ if (animationMode === "once") {
2214
+ this.completed = true;
2215
+ this.frame = Math.max(0, definition.frames - 1);
2216
+ this.finishTransient();
2217
+ return;
2218
+ }
2219
+ this.frame = 0;
2220
+ this.render();
2221
+ return;
2222
+ }
2223
+ this.frame = nextFrame;
2224
+ this.render();
2225
+ }, effectiveDuration);
2226
+ }
2227
+ clearTimers() {
2228
+ if (this.frameTimer !== null) {
2229
+ window.clearTimeout(this.frameTimer);
2230
+ this.frameTimer = null;
2231
+ }
2232
+ }
2233
+ clearRestingDelayTimer() {
2234
+ if (this.restingDelayTimer !== null) {
2235
+ window.clearTimeout(this.restingDelayTimer);
2236
+ this.restingDelayTimer = null;
2237
+ }
2238
+ }
2239
+ finishTransient() {
2240
+ this.transient = null;
2241
+ this.activeAnimationName = null;
2242
+ this.activeAnimationMode = null;
2243
+ this.render();
2244
+ }
2245
+ rescheduleAnimation() {
2246
+ this.clearTimers();
2247
+ this.render();
2248
+ }
2249
+ enterRestingAfterDelay() {
2250
+ this.clearRestingDelayTimer();
2251
+ this.isHovering = true;
2252
+ this.restingDelayTimer = window.setTimeout(() => {
2253
+ this.restingDelayTimer = null;
2254
+ if (this.isDragging) {
2255
+ return;
2256
+ }
2257
+ this.isHovering = false;
2258
+ this.rescheduleAnimation();
2259
+ }, PET_RESTING_DELAY_MS);
2260
+ }
2261
+ isPointerOverPet(event) {
2262
+ var _a2;
2263
+ const rect = (_a2 = this.petElement) == null ? void 0 : _a2.getBoundingClientRect();
2264
+ if (!rect) {
2265
+ return false;
2266
+ }
2267
+ return event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom;
2268
+ }
2269
+ async submitReply() {
2270
+ var _a2;
2271
+ const text = this.replyDraft.trim();
2272
+ if (!text || this.isReplySubmitting) {
2273
+ return;
2274
+ }
2275
+ this.isReplySubmitting = true;
2276
+ this.replyError = null;
2277
+ this.render();
2278
+ try {
2279
+ await ((_a2 = this.onReply) == null ? void 0 : _a2.call(this, text));
2280
+ this.replyDraft = "";
2281
+ this.isReplyOpen = false;
2282
+ this.isSummaryHovering = false;
2283
+ } catch {
2284
+ this.replyError = "Failed to send";
2285
+ } finally {
2286
+ this.isReplySubmitting = false;
2287
+ this.render();
2288
+ }
2289
+ }
2290
+ getNextDragPosition(event) {
2291
+ if (!this.options) {
2292
+ return { x: 0, y: 0 };
2293
+ }
2294
+ return clampPetPosition(
2295
+ {
2296
+ x: event.clientX - this.dragOffset.x,
2297
+ y: event.clientY - this.dragOffset.y
2298
+ },
2299
+ this.getSize(),
2300
+ getViewportSize(),
2301
+ normalizeBoundsPadding(this.options.position.boundsPadding)
2302
+ );
2303
+ }
2304
+ installDragListeners() {
2305
+ window.addEventListener("pointermove", this.handlePointerMove);
2306
+ window.addEventListener("pointerup", this.handlePointerUp, { once: true });
2307
+ window.addEventListener("pointercancel", this.handlePointerUp, {
2308
+ once: true
2309
+ });
2310
+ }
2311
+ removeDragListeners() {
2312
+ window.removeEventListener("pointermove", this.handlePointerMove);
2313
+ window.removeEventListener("pointerup", this.handlePointerUp);
2314
+ window.removeEventListener("pointercancel", this.handlePointerUp);
2315
+ }
2316
+ }
886
2317
  function getInnerOptions(options) {
887
2318
  return removeMethods(options);
888
2319
  }
@@ -906,7 +2337,15 @@ class ChatKitElementBase extends (_c = HTMLElement, _focusComposer_dec = [requir
906
2337
  __privateAdd(this, _frameUrl);
907
2338
  __privateAdd(this, _frame);
908
2339
  __privateAdd(this, _wrapper);
2340
+ __privateAdd(this, _launcherCloseButton);
2341
+ __privateAdd(this, _launcherOpen, false);
2342
+ __privateAdd(this, _framePetOptionsOverride);
909
2343
  __privateAdd(this, _shadow, this.attachShadow({ mode: "open" }));
2344
+ __privateAdd(this, _petOverlay, new PetOverlay(__privateGet(this, _shadow), {
2345
+ onActivate: () => __privateMethod(this, _ChatKitElementBase_instances, handlePetActivate_fn).call(this),
2346
+ onReply: (text) => __privateMethod(this, _ChatKitElementBase_instances, handlePetReply_fn).call(this, text),
2347
+ onThreadSummaryActivate: (threadId) => void __privateMethod(this, _ChatKitElementBase_instances, handlePetThreadSummaryActivate_fn).call(this, threadId)
2348
+ }));
910
2349
  __privateAdd(this, _resolveLoaded);
911
2350
  __privateAdd(this, _loaded, new Promise((resolve) => {
912
2351
  __privateSet(this, _resolveLoaded, resolve);
@@ -1001,6 +2440,9 @@ class ChatKitElementBase extends (_c = HTMLElement, _focusComposer_dec = [requir
1001
2440
  }
1002
2441
  }
1003
2442
  }));
2443
+ __privateAdd(this, _handleLauncherClose, () => {
2444
+ __privateMethod(this, _ChatKitElementBase_instances, setLauncherOpen_fn).call(this, false);
2445
+ });
1004
2446
  __privateAdd(this, _handleFrameLoad, () => {
1005
2447
  var _a2;
1006
2448
  this.dataset.loaded = "true";
@@ -1018,6 +2460,7 @@ class ChatKitElementBase extends (_c = HTMLElement, _focusComposer_dec = [requir
1018
2460
  this.capabilities = getCapabilities(profile);
1019
2461
  }
1020
2462
  connectedCallback() {
2463
+ __privateGet(this, _petOverlay).connect();
1021
2464
  const style = document.createElement("style");
1022
2465
  style.textContent = `
1023
2466
  :host {
@@ -1025,6 +2468,10 @@ class ChatKitElementBase extends (_c = HTMLElement, _focusComposer_dec = [requir
1025
2468
  position: relative;
1026
2469
  height: 100%;
1027
2470
  width: 100%;
2471
+ overflow: visible;
2472
+ }
2473
+ :host([data-display-mode="pet"]) {
2474
+ display: contents;
1028
2475
  }
1029
2476
  .ck-iframe {
1030
2477
  border: none;
@@ -1043,12 +2490,115 @@ class ChatKitElementBase extends (_c = HTMLElement, _focusComposer_dec = [requir
1043
2490
  overflow: hidden;
1044
2491
  opacity: 0;
1045
2492
  }
2493
+ .ck-launcher-close {
2494
+ display: none;
2495
+ }
2496
+ :host([data-display-mode="pet"]) .ck-wrapper {
2497
+ position: fixed;
2498
+ inset: auto 16px 16px auto;
2499
+ width: min(420px, calc(100vw - 32px));
2500
+ height: min(720px, calc(100vh - 32px));
2501
+ max-height: calc(100vh - 32px);
2502
+ overflow: visible;
2503
+ border: 1px solid rgba(148, 163, 184, 0.35);
2504
+ border-radius: 18px;
2505
+ background: Canvas;
2506
+ box-shadow:
2507
+ 0 24px 80px rgba(15, 23, 42, 0.22),
2508
+ 0 0 0 1px rgba(15, 23, 42, 0.04);
2509
+ opacity: 0;
2510
+ pointer-events: none;
2511
+ transform: translateY(12px) scale(0.98);
2512
+ transition:
2513
+ opacity 160ms ease,
2514
+ transform 160ms ease;
2515
+ z-index: 39;
2516
+ }
2517
+ :host([data-display-mode="pet"][data-chat-open="true"]) .ck-wrapper {
2518
+ opacity: 1;
2519
+ pointer-events: auto;
2520
+ transform: translateY(0) scale(1);
2521
+ }
2522
+ :host([data-display-mode="pet"]) .ck-iframe {
2523
+ border-radius: inherit;
2524
+ }
2525
+ :host([data-display-mode="pet"]) .ck-launcher-close {
2526
+ display: inline-flex;
2527
+ position: absolute;
2528
+ top: -10px;
2529
+ right: -10px;
2530
+ z-index: 2;
2531
+ width: 28px;
2532
+ height: 28px;
2533
+ align-items: center;
2534
+ justify-content: center;
2535
+ border: 1px solid rgba(148, 163, 184, 0.45);
2536
+ border-radius: 999px;
2537
+ background: rgba(255, 255, 255, 0.96);
2538
+ color: #475569;
2539
+ box-shadow: 0 8px 24px rgba(15, 23, 42, 0.18);
2540
+ cursor: pointer;
2541
+ font: inherit;
2542
+ font-size: 0;
2543
+ line-height: 1;
2544
+ }
2545
+ :host([data-display-mode="pet"]) .ck-launcher-close::before,
2546
+ :host([data-display-mode="pet"]) .ck-launcher-close::after {
2547
+ content: '';
2548
+ position: absolute;
2549
+ top: 50%;
2550
+ left: 50%;
2551
+ width: 14px;
2552
+ height: 2px;
2553
+ border-radius: 999px;
2554
+ background: currentColor;
2555
+ transform: translate(-50%, -50%) rotate(45deg);
2556
+ }
2557
+ :host([data-display-mode="pet"]) .ck-launcher-close::after {
2558
+ transform: translate(-50%, -50%) rotate(-45deg);
2559
+ }
2560
+ :host([data-display-mode="pet"]) .ck-launcher-close:hover {
2561
+ background: #fff;
2562
+ color: #0f172a;
2563
+ }
1046
2564
  :host([data-color-scheme="dark"]) .ck-iframe {
1047
2565
  color-scheme: dark only;
1048
2566
  }
2567
+ :host([data-color-scheme="dark"][data-display-mode="pet"]) .ck-wrapper {
2568
+ border-color: rgba(148, 163, 184, 0.28);
2569
+ background: #020617;
2570
+ box-shadow:
2571
+ 0 24px 80px rgba(0, 0, 0, 0.5),
2572
+ 0 0 0 1px rgba(255, 255, 255, 0.06);
2573
+ }
2574
+ :host([data-color-scheme="dark"][data-display-mode="pet"]) .ck-launcher-close {
2575
+ background: rgba(15, 23, 42, 0.88);
2576
+ border-color: rgba(148, 163, 184, 0.32);
2577
+ color: #cbd5e1;
2578
+ }
2579
+ :host([data-color-scheme="dark"][data-display-mode="pet"]) .ck-launcher-close:hover {
2580
+ background: #1e293b;
2581
+ color: #f8fafc;
2582
+ }
1049
2583
  :host([data-loaded="true"]) .ck-wrapper {
1050
2584
  opacity: 1;
1051
2585
  }
2586
+ :host([data-display-mode="pet"]:not([data-chat-open="true"])) .ck-wrapper {
2587
+ opacity: 0;
2588
+ }
2589
+ @media (max-width: 520px) {
2590
+ :host([data-display-mode="pet"]) .ck-wrapper {
2591
+ inset: auto 8px 8px 8px;
2592
+ width: auto;
2593
+ height: min(680px, calc(100vh - 16px));
2594
+ max-height: calc(100vh - 16px);
2595
+ border-radius: 16px;
2596
+ }
2597
+ :host([data-display-mode="pet"]) .ck-launcher-close {
2598
+ top: -8px;
2599
+ right: 8px;
2600
+ }
2601
+ }
1052
2602
  `;
1053
2603
  const frame = document.createElement("iframe");
1054
2604
  frame.className = "ck-iframe";
@@ -1064,6 +2614,13 @@ class ChatKitElementBase extends (_c = HTMLElement, _focusComposer_dec = [requir
1064
2614
  wrapper.className = "ck-wrapper";
1065
2615
  wrapper.appendChild(frame);
1066
2616
  __privateSet(this, _wrapper, wrapper);
2617
+ const closeButton = document.createElement("button");
2618
+ closeButton.className = "ck-launcher-close";
2619
+ closeButton.type = "button";
2620
+ closeButton.setAttribute("aria-label", "Close chat");
2621
+ closeButton.addEventListener("click", __privateGet(this, _handleLauncherClose));
2622
+ wrapper.appendChild(closeButton);
2623
+ __privateSet(this, _launcherCloseButton, closeButton);
1067
2624
  __privateGet(this, _shadow).append(style);
1068
2625
  __privateGet(this, _messenger).on("left_header_icon_click", () => {
1069
2626
  var _a2, _b2, _c2;
@@ -1074,6 +2631,18 @@ class ChatKitElementBase extends (_c = HTMLElement, _focusComposer_dec = [requir
1074
2631
  (_c2 = (_b2 = (_a2 = __privateGet(this, _opts)) == null ? void 0 : _a2.header) == null ? void 0 : _b2.rightAction) == null ? void 0 : _c2.onClick();
1075
2632
  });
1076
2633
  __privateGet(this, _messenger).on("public_event", ([event, data]) => {
2634
+ if (event === "log") {
2635
+ const payload = parseThreadSummaryLogPayload(data);
2636
+ if (payload) {
2637
+ __privateGet(this, _petOverlay).setThreadSummary(payload.summary);
2638
+ }
2639
+ } else if (event === "response.start") {
2640
+ __privateGet(this, _petOverlay).setThreadSummaryStatus("running");
2641
+ } else if (event === "response.end") {
2642
+ __privateGet(this, _petOverlay).setThreadSummaryStatus("completed");
2643
+ } else if (event === "response.stop") {
2644
+ __privateGet(this, _petOverlay).setThreadSummaryStatus("completed");
2645
+ }
1077
2646
  if (!this.capabilities.events.has(event)) return;
1078
2647
  if (event === "error" && "error" in data) {
1079
2648
  const error = fromPossibleFrameSafeError(data.error);
@@ -1087,6 +2656,19 @@ class ChatKitElementBase extends (_c = HTMLElement, _focusComposer_dec = [requir
1087
2656
  }
1088
2657
  this.dispatchEvent(new CustomEvent(`chatkit.${event}`, { detail: data }));
1089
2658
  });
2659
+ __privateGet(this, _messenger).on("pet_state_change", (data) => {
2660
+ const payload = parsePetStateChangePayload(data);
2661
+ if (payload) {
2662
+ __privateGet(this, _petOverlay).setState(payload.state);
2663
+ }
2664
+ });
2665
+ __privateGet(this, _messenger).on("pet_options_change", (data) => {
2666
+ const payload = parsePetOptionsChangePayload(data);
2667
+ if (payload) {
2668
+ __privateSet(this, _framePetOptionsOverride, payload.pet);
2669
+ __privateGet(this, _petOverlay).setOptions(__privateMethod(this, _ChatKitElementBase_instances, getOverlayPetOptions_fn).call(this));
2670
+ }
2671
+ });
1090
2672
  __privateGet(this, _messenger).on("unmount", () => {
1091
2673
  if (__privateGet(this, _wrapper) && __privateGet(this, _shadow).contains(__privateGet(this, _wrapper))) {
1092
2674
  __privateGet(this, _shadow).removeChild(__privateGet(this, _wrapper));
@@ -1109,16 +2691,25 @@ class ChatKitElementBase extends (_c = HTMLElement, _focusComposer_dec = [requir
1109
2691
  }
1110
2692
  }
1111
2693
  disconnectedCallback() {
1112
- var _a2;
2694
+ var _a2, _b2;
1113
2695
  (_a2 = __privateGet(this, _frame)) == null ? void 0 : _a2.removeEventListener("load", __privateGet(this, _handleFrameLoad));
2696
+ (_b2 = __privateGet(this, _launcherCloseButton)) == null ? void 0 : _b2.removeEventListener(
2697
+ "click",
2698
+ __privateGet(this, _handleLauncherClose)
2699
+ );
1114
2700
  __privateGet(this, _messenger).disconnect();
2701
+ __privateGet(this, _petOverlay).destroy();
1115
2702
  }
1116
2703
  applySanitizedOptions(newOptions) {
1117
2704
  __privateSet(this, _opts, newOptions);
2705
+ __privateGet(this, _petOverlay).setLocale(newOptions.locale);
2706
+ __privateGet(this, _petOverlay).setOptions(__privateMethod(this, _ChatKitElementBase_instances, getOverlayPetOptions_fn).call(this));
1118
2707
  if (__privateGet(this, _initialized)) {
1119
2708
  __privateMethod(this, _ChatKitElementBase_instances, setOptionsDataAttributes_fn).call(this, __privateGet(this, _opts));
1120
2709
  __privateGet(this, _loaded).then(() => {
1121
- __privateGet(this, _messenger).commands.setOptions(getInnerOptions(newOptions));
2710
+ __privateGet(this, _messenger).commands.setOptions(
2711
+ getInnerOptions(__privateMethod(this, _ChatKitElementBase_instances, getFrameOptions_fn).call(this, newOptions))
2712
+ );
1122
2713
  });
1123
2714
  } else {
1124
2715
  __privateMethod(this, _ChatKitElementBase_instances, maybeInit_fn).call(this);
@@ -1190,7 +2781,11 @@ _opts = new WeakMap();
1190
2781
  _frameUrl = new WeakMap();
1191
2782
  _frame = new WeakMap();
1192
2783
  _wrapper = new WeakMap();
2784
+ _launcherCloseButton = new WeakMap();
2785
+ _launcherOpen = new WeakMap();
2786
+ _framePetOptionsOverride = new WeakMap();
1193
2787
  _shadow = new WeakMap();
2788
+ _petOverlay = new WeakMap();
1194
2789
  _resolveLoaded = new WeakMap();
1195
2790
  _loaded = new WeakMap();
1196
2791
  _messenger = new WeakMap();
@@ -1202,7 +2797,96 @@ emitAndThrow_fn = function(error) {
1202
2797
  setOptionsDataAttributes_fn = function(options) {
1203
2798
  var _a2;
1204
2799
  this.dataset.colorScheme = typeof options.theme === "string" ? options.theme : ((_a2 = options.theme) == null ? void 0 : _a2.colorScheme) ?? "light";
2800
+ this.dataset.displayMode = __privateMethod(this, _ChatKitElementBase_instances, getDisplayMode_fn).call(this, options);
2801
+ if (__privateMethod(this, _ChatKitElementBase_instances, getDisplayMode_fn).call(this, options) !== "pet") {
2802
+ __privateMethod(this, _ChatKitElementBase_instances, setLauncherOpen_fn).call(this, false);
2803
+ }
2804
+ };
2805
+ getDisplayMode_fn = function(options = __privateGet(this, _opts)) {
2806
+ return (options == null ? void 0 : options.displayMode) === "pet" ? "pet" : "chat";
2807
+ };
2808
+ getConfiguredPetOptions_fn = function(options = __privateGet(this, _opts)) {
2809
+ if (!options) {
2810
+ return null;
2811
+ }
2812
+ if (__privateMethod(this, _ChatKitElementBase_instances, getDisplayMode_fn).call(this, options) === "pet" && !normalizePetOptions(options.pet ?? null)) {
2813
+ return true;
2814
+ }
2815
+ return options.pet ?? null;
2816
+ };
2817
+ getOverlayPetOptions_fn = function() {
2818
+ let pet = __privateGet(this, _framePetOptionsOverride) !== void 0 ? __privateGet(this, _framePetOptionsOverride) : __privateMethod(this, _ChatKitElementBase_instances, getConfiguredPetOptions_fn).call(this);
2819
+ if (__privateMethod(this, _ChatKitElementBase_instances, getDisplayMode_fn).call(this) === "pet" && !normalizePetOptions(pet ?? null)) {
2820
+ pet = true;
2821
+ }
2822
+ return __privateMethod(this, _ChatKitElementBase_instances, resolveOverlayPetOptions_fn).call(this, pet);
2823
+ };
2824
+ resolvePetAssetUrl_fn = function(src) {
2825
+ try {
2826
+ const base = new URL(
2827
+ __privateGet(this, _frameUrl) ?? window.location.href,
2828
+ window.location.origin
2829
+ );
2830
+ return new URL(src, base).toString();
2831
+ } catch {
2832
+ return src;
2833
+ }
2834
+ };
2835
+ resolveOverlayPetOptions_fn = function(pet) {
2836
+ const normalized = normalizePetOptions(pet ?? null);
2837
+ if (!normalized) {
2838
+ return null;
2839
+ }
2840
+ return {
2841
+ character: {
2842
+ ...normalized.character,
2843
+ src: __privateMethod(this, _ChatKitElementBase_instances, resolvePetAssetUrl_fn).call(this, normalized.character.src)
2844
+ },
2845
+ position: normalized.position,
2846
+ behavior: normalized.behavior,
2847
+ ariaLabel: normalized.ariaLabel,
2848
+ imageRendering: normalized.imageRendering
2849
+ };
2850
+ };
2851
+ getFrameOptions_fn = function(options) {
2852
+ const pet = __privateMethod(this, _ChatKitElementBase_instances, getConfiguredPetOptions_fn).call(this, options);
2853
+ if (pet === (options.pet ?? null)) {
2854
+ return options;
2855
+ }
2856
+ const nextOptions = { ...options };
2857
+ if (pet === null) {
2858
+ delete nextOptions.pet;
2859
+ } else {
2860
+ nextOptions.pet = pet;
2861
+ }
2862
+ return nextOptions;
2863
+ };
2864
+ setLauncherOpen_fn = function(open) {
2865
+ __privateSet(this, _launcherOpen, open);
2866
+ if (open) {
2867
+ this.dataset.chatOpen = "true";
2868
+ } else {
2869
+ delete this.dataset.chatOpen;
2870
+ }
2871
+ };
2872
+ handlePetActivate_fn = function() {
2873
+ if (__privateMethod(this, _ChatKitElementBase_instances, getDisplayMode_fn).call(this) !== "pet") {
2874
+ return;
2875
+ }
2876
+ __privateMethod(this, _ChatKitElementBase_instances, setLauncherOpen_fn).call(this, true);
2877
+ __privateGet(this, _loaded).then(() => this.focusComposer()).catch(() => void 0);
2878
+ };
2879
+ handlePetReply_fn = async function(text) {
2880
+ await this.sendUserMessage({ text });
2881
+ };
2882
+ handlePetThreadSummaryActivate_fn = async function(threadId) {
2883
+ if (__privateMethod(this, _ChatKitElementBase_instances, getDisplayMode_fn).call(this) === "pet") {
2884
+ __privateMethod(this, _ChatKitElementBase_instances, setLauncherOpen_fn).call(this, true);
2885
+ }
2886
+ await this.setThreadId(threadId);
2887
+ await this.focusComposer();
1205
2888
  };
2889
+ _handleLauncherClose = new WeakMap();
1206
2890
  getFrameUrl_fn = function() {
1207
2891
  if (!__privateGet(this, _frameUrl)) {
1208
2892
  throw new IntegrationError2(
@@ -1242,7 +2926,7 @@ maybeInit_fn = function() {
1242
2926
  const frameURL = new URL(__privateMethod(this, _ChatKitElementBase_instances, getFrameUrl_fn).call(this), window.location.origin);
1243
2927
  __privateGet(this, _messenger).setTargetOrigin(frameURL.origin);
1244
2928
  frameURL.hash = encodeBase64({
1245
- options: getInnerOptions(__privateGet(this, _opts)),
2929
+ options: getInnerOptions(__privateMethod(this, _ChatKitElementBase_instances, getFrameOptions_fn).call(this, __privateGet(this, _opts))),
1246
2930
  referrer: window.location.origin,
1247
2931
  profile: this.profile
1248
2932
  });