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