@aleph-alpha/chat-kit 5.3.0 → 5.5.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.
- package/dist/{CkHistory.vue_vue_type_script_setup_true_lang-BcYJmbCd.js → CkHistory.vue_vue_type_script_setup_true_lang-C1busuyf.js} +65 -33
- package/dist/components/base/CkConversationLayout/CkConversationLayout.vue.d.ts.map +1 -1
- package/dist/components/composed/CkHistory/CkHistory.vue.d.ts +1 -0
- package/dist/components/composed/CkHistory/CkHistory.vue.d.ts.map +1 -1
- package/dist/components/composed/CkHistory/types.d.ts +9 -1
- package/dist/components/composed/CkHistory/types.d.ts.map +1 -1
- package/dist/components/index.js +1 -1
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/src/components/base/CkConversationLayout/CkConversationLayout.spec.ts +84 -1
- package/src/components/base/CkConversationLayout/CkConversationLayout.vue +61 -18
- package/src/components/base/CkHistoryWrapper/CkHistoryWrapper.vue +1 -1
- package/src/components/composed/CkHistory/CkHistory.spec.ts +30 -0
- package/src/components/composed/CkHistory/CkHistory.vue +5 -1
- package/src/components/composed/CkHistory/types.ts +9 -1
|
@@ -184,7 +184,7 @@ const _sfc_main$p = /* @__PURE__ */ defineComponent({
|
|
|
184
184
|
const _hoisted_1$e = { class: "ck-citation-card flex w-[22.5rem] max-w-[90vw] flex-col gap-2 rounded-md bg-background-surface-floating px-6 pb-6 pt-4 shadow-md" };
|
|
185
185
|
const _hoisted_2$8 = { class: "flex items-center gap-2" };
|
|
186
186
|
const _hoisted_3$7 = ["title"];
|
|
187
|
-
const _hoisted_4$
|
|
187
|
+
const _hoisted_4$7 = { class: "line-clamp-6 break-words text-sm leading-5 text-content-on-surface-secondary" };
|
|
188
188
|
const _hoisted_5$4 = {
|
|
189
189
|
key: 0,
|
|
190
190
|
class: "text-sm leading-5 text-content-on-surface-muted"
|
|
@@ -243,7 +243,7 @@ const _sfc_main$o = /* @__PURE__ */ defineComponent({
|
|
|
243
243
|
_: 1
|
|
244
244
|
}, 8, ["aria-label"])) : createCommentVNode("", true)
|
|
245
245
|
]),
|
|
246
|
-
createElementVNode("p", _hoisted_4$
|
|
246
|
+
createElementVNode("p", _hoisted_4$7, toDisplayString(__props.snippet), 1),
|
|
247
247
|
__props.locationLabel ? (openBlock(), createElementBlock("p", _hoisted_5$4, toDisplayString(__props.locationLabel), 1)) : createCommentVNode("", true)
|
|
248
248
|
]);
|
|
249
249
|
};
|
|
@@ -378,12 +378,13 @@ const _export_sfc = (sfc, props) => {
|
|
|
378
378
|
return target;
|
|
379
379
|
};
|
|
380
380
|
const CkCitation = /* @__PURE__ */ _export_sfc(_sfc_main$n, [["__scopeId", "data-v-73025da4"]]);
|
|
381
|
-
const _hoisted_1$c =
|
|
382
|
-
const _hoisted_2$7 =
|
|
381
|
+
const _hoisted_1$c = { class: "relative flex min-h-0 flex-col overflow-hidden" };
|
|
382
|
+
const _hoisted_2$7 = ["data-message-row"];
|
|
383
|
+
const _hoisted_3$6 = {
|
|
383
384
|
key: 0,
|
|
384
385
|
class: "flex min-w-0 justify-end"
|
|
385
386
|
};
|
|
386
|
-
const
|
|
387
|
+
const _hoisted_4$6 = {
|
|
387
388
|
key: 1,
|
|
388
389
|
class: "flex min-w-0 justify-start"
|
|
389
390
|
};
|
|
@@ -400,6 +401,8 @@ const _sfc_main$m = /* @__PURE__ */ defineComponent({
|
|
|
400
401
|
const isAutoScrollEnabled = ref(true);
|
|
401
402
|
const hasBottomSpacer = ref(false);
|
|
402
403
|
const spacerHeight = ref(0);
|
|
404
|
+
const showTopFade = ref(false);
|
|
405
|
+
const showBottomFade = ref(false);
|
|
403
406
|
let resizeObserver = null;
|
|
404
407
|
onMounted(() => {
|
|
405
408
|
const container = scrollContainerRef.value;
|
|
@@ -409,10 +412,12 @@ const _sfc_main$m = /* @__PURE__ */ defineComponent({
|
|
|
409
412
|
for (const entry of entries) {
|
|
410
413
|
containerHeight.value = entry.contentRect.height;
|
|
411
414
|
}
|
|
415
|
+
updateFades();
|
|
412
416
|
});
|
|
413
417
|
resizeObserver.observe(container);
|
|
414
418
|
nextTick(() => {
|
|
415
419
|
container.scrollTop = container.scrollHeight;
|
|
420
|
+
updateFades();
|
|
416
421
|
});
|
|
417
422
|
}
|
|
418
423
|
});
|
|
@@ -431,6 +436,15 @@ const _sfc_main$m = /* @__PURE__ */ defineComponent({
|
|
|
431
436
|
}
|
|
432
437
|
function handleScroll() {
|
|
433
438
|
isAutoScrollEnabled.value = isFollowingContent();
|
|
439
|
+
updateFades();
|
|
440
|
+
}
|
|
441
|
+
function updateFades() {
|
|
442
|
+
const container = scrollContainerRef.value;
|
|
443
|
+
if (!container) return;
|
|
444
|
+
const { scrollTop, scrollHeight, clientHeight } = container;
|
|
445
|
+
const maxScroll = scrollHeight - clientHeight;
|
|
446
|
+
showTopFade.value = scrollTop > 1;
|
|
447
|
+
showBottomFade.value = scrollTop < maxScroll - 1;
|
|
434
448
|
}
|
|
435
449
|
function updateSpacerHeight() {
|
|
436
450
|
const container = scrollContainerRef.value;
|
|
@@ -495,7 +509,10 @@ const _sfc_main$m = /* @__PURE__ */ defineComponent({
|
|
|
495
509
|
if (newLen <= (oldLen ?? 0)) return;
|
|
496
510
|
const lastMessage = props.messages[newLen - 1];
|
|
497
511
|
if (lastMessage?.role === "user") {
|
|
498
|
-
nextTick(() =>
|
|
512
|
+
nextTick(() => {
|
|
513
|
+
scrollUserMessageToTop();
|
|
514
|
+
updateFades();
|
|
515
|
+
});
|
|
499
516
|
}
|
|
500
517
|
}
|
|
501
518
|
);
|
|
@@ -510,37 +527,48 @@ const _sfc_main$m = /* @__PURE__ */ defineComponent({
|
|
|
510
527
|
if (isAutoScrollEnabled.value) {
|
|
511
528
|
scrollToEndOfContent();
|
|
512
529
|
}
|
|
530
|
+
updateFades();
|
|
513
531
|
});
|
|
514
532
|
}
|
|
515
533
|
},
|
|
516
534
|
{ deep: true }
|
|
517
535
|
);
|
|
518
536
|
return (_ctx, _cache) => {
|
|
519
|
-
return openBlock(), createElementBlock("div",
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
537
|
+
return openBlock(), createElementBlock("div", _hoisted_1$c, [
|
|
538
|
+
createElementVNode("div", {
|
|
539
|
+
"aria-hidden": "true",
|
|
540
|
+
class: normalizeClass(["pointer-events-none absolute inset-x-0 top-0 z-10 h-8 bg-gradient-to-b from-background-surface-secondary to-transparent transition-opacity duration-200", showTopFade.value ? "opacity-100" : "opacity-0"])
|
|
541
|
+
}, null, 2),
|
|
542
|
+
createElementVNode("div", {
|
|
543
|
+
ref_key: "scrollContainerRef",
|
|
544
|
+
ref: scrollContainerRef,
|
|
545
|
+
class: "relative flex min-h-0 flex-1 flex-col gap-8 overflow-y-auto",
|
|
546
|
+
onScroll: handleScroll
|
|
547
|
+
}, [
|
|
548
|
+
(openBlock(true), createElementBlock(Fragment, null, renderList(__props.messages, (message) => {
|
|
549
|
+
return openBlock(), createElementBlock("div", {
|
|
550
|
+
key: message.id,
|
|
551
|
+
"data-message-row": message.role,
|
|
552
|
+
class: "min-w-0"
|
|
553
|
+
}, [
|
|
554
|
+
message.role === "user" ? (openBlock(), createElementBlock("div", _hoisted_3$6, [
|
|
555
|
+
renderSlot(_ctx.$slots, "user-message", { message })
|
|
556
|
+
])) : (openBlock(), createElementBlock("div", _hoisted_4$6, [
|
|
557
|
+
renderSlot(_ctx.$slots, "agent-message", { message })
|
|
558
|
+
]))
|
|
559
|
+
], 8, _hoisted_2$7);
|
|
560
|
+
}), 128)),
|
|
561
|
+
hasBottomSpacer.value ? (openBlock(), createElementBlock("div", {
|
|
562
|
+
key: 0,
|
|
563
|
+
"aria-hidden": "true",
|
|
564
|
+
style: normalizeStyle({ minHeight: `${spacerHeight.value}px` })
|
|
565
|
+
}, null, 4)) : createCommentVNode("", true)
|
|
566
|
+
], 544),
|
|
567
|
+
createElementVNode("div", {
|
|
540
568
|
"aria-hidden": "true",
|
|
541
|
-
|
|
542
|
-
}, null,
|
|
543
|
-
]
|
|
569
|
+
class: normalizeClass(["pointer-events-none absolute inset-x-0 bottom-0 z-10 h-8 bg-gradient-to-t from-background-surface-secondary to-transparent transition-opacity duration-200", showBottomFade.value ? "opacity-100" : "opacity-0"])
|
|
570
|
+
}, null, 2)
|
|
571
|
+
]);
|
|
544
572
|
};
|
|
545
573
|
}
|
|
546
574
|
});
|
|
@@ -1931,7 +1959,7 @@ const _sfc_main$c = /* @__PURE__ */ defineComponent({
|
|
|
1931
1959
|
};
|
|
1932
1960
|
}
|
|
1933
1961
|
});
|
|
1934
|
-
const baseClass = "flex w-full min-w-0 flex-col
|
|
1962
|
+
const baseClass = "flex w-full min-w-0 flex-col py-2";
|
|
1935
1963
|
const _sfc_main$b = /* @__PURE__ */ defineComponent({
|
|
1936
1964
|
...{
|
|
1937
1965
|
name: "CkHistoryWrapper",
|
|
@@ -2706,7 +2734,8 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
2706
2734
|
showActionOnHover: { type: Boolean, default: true },
|
|
2707
2735
|
timeFormatter: { type: Function, default: formatRelativeTime },
|
|
2708
2736
|
collapsedLimit: { default: 5 },
|
|
2709
|
-
maxHeight: { default: void 0 }
|
|
2737
|
+
maxHeight: { default: void 0 },
|
|
2738
|
+
contentClass: { default: void 0 }
|
|
2710
2739
|
},
|
|
2711
2740
|
emits: ["select", "edit", "delete"],
|
|
2712
2741
|
setup(__props, { emit: __emit }) {
|
|
@@ -2744,7 +2773,10 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
|
|
|
2744
2773
|
return (_ctx, _cache) => {
|
|
2745
2774
|
return openBlock(), createElementBlock("div", null, [
|
|
2746
2775
|
createVNode(_sfc_main$b, {
|
|
2747
|
-
class: normalizeClass(
|
|
2776
|
+
class: normalizeClass([
|
|
2777
|
+
isExpanded.value && props.maxHeight ? "overflow-y-auto" : void 0,
|
|
2778
|
+
props.contentClass
|
|
2779
|
+
]),
|
|
2748
2780
|
style: normalizeStyle(
|
|
2749
2781
|
isExpanded.value && props.maxHeight ? { maxHeight: props.maxHeight } : void 0
|
|
2750
2782
|
)
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CkConversationLayout.vue.d.ts","sourceRoot":"","sources":["../../../../src/components/base/CkConversationLayout/CkConversationLayout.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CkConversationLayout.vue.d.ts","sourceRoot":"","sources":["../../../../src/components/base/CkConversationLayout/CkConversationLayout.vue"],"names":[],"mappings":"AA+PA,QAAA,MAAM,YAAY,GAAK,CAAC,SAAS;IAAE,EAAE,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,EAC5D,aAAa,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,OAAO,CAAC,EAC9D,YAAY,mBAAmB,CAAC,IAAI,CAAC,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,OAAO,CAAC,CAAC,EAC3G,gBAAgB,WAAW,CAAC,OAAO,CAAC,OAAO,WAAW,CAAC,CAAC,CAAC,QAAQ,CAAC,EAClE;WAsUO,OAAO,KAAK,EAAE,WAAW,GAAG,mBAAmB;kBAlU3C,CAAC,EAAE;MAkU2D,GAAG,CAAC,OAAO,UAAU,SAAS;QAAE,oBAAoB,EAAE,MAAM,CAAC,CAAA;KAAE,GAAG,CAAC,GAAG,EAAE,CAAC;YAC1I,CAAC,OAAO,EAAE,EAAE,KAAK,IAAI;WACtB,GAAG;;wBA/TO,CAAC,KAAK,EAAE;YAAE,OAAO,EAAE,CAAC,CAAA;SAAE,KAAK,IAAI;yBAC9B,CAAC,KAAK,EAAE;YAAE,OAAO,EAAE,CAAC,CAAA;SAAE,KAAK,IAAI;;UAgU3C,EAAE;EAEL,KACQ,OAAO,KAAK,EAAE,KAAK,GAAG;IAAE,KAAK,CAAC,EAAE,OAAO,CAAC,OAAO,WAAW,CAAC,CAAA;CAAI,CAAC;wBACvD,OAAO,YAAY;AAAxC,wBAAyC;AACzC,KAAK,mBAAmB,CAAC,CAAC,IAAI,CAAC,CAAC,SAAS,GAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,GAAG;KAAG,CAAC,IAAI,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAG,CAAC,GAAG,EAAE,CAAC"}
|
|
@@ -44,6 +44,7 @@ declare const __VLS_base: import("vue").DefineComponent<CkHistoryProps, {}, {},
|
|
|
44
44
|
timeFormatter: (updatedAtSeconds: number) => string;
|
|
45
45
|
collapsedLimit: number;
|
|
46
46
|
maxHeight: string;
|
|
47
|
+
contentClass: string;
|
|
47
48
|
}, {}, {}, {}, string, import("vue").ComponentProvideOptions, false, {}, any>;
|
|
48
49
|
declare const __VLS_export: __VLS_WithSlots<typeof __VLS_base, __VLS_Slots>;
|
|
49
50
|
declare const _default: typeof __VLS_export;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CkHistory.vue.d.ts","sourceRoot":"","sources":["../../../../src/components/composed/CkHistory/CkHistory.vue"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"CkHistory.vue.d.ts","sourceRoot":"","sources":["../../../../src/components/composed/CkHistory/CkHistory.vue"],"names":[],"mappings":"AAmMA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AACnD,OAAO,KAAK,EAAkB,cAAc,EAAE,MAAM,SAAS,CAAC;AAkB9D,KAAK,WAAW,GAAG;IACjB;;;;;;;;;;;;;;;;OAgBG;IACH,IAAI,EAAE,CAAC,KAAK,EAAE;QACZ,YAAY,EAAE,YAAY,CAAC;QAC3B,IAAI,EAAE,MAAM,CAAC;QACb,QAAQ,EAAE,OAAO,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,IAAI,EAAE,MAAM,GAAG,SAAS,CAAC;QACzB,MAAM,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;QACpC,IAAI,EAAE,MAAM,IAAI,CAAC;QACjB,MAAM,EAAE,MAAM,IAAI,CAAC;KACpB,KAAK,IAAI,CAAC;CACZ,CAAC;AAsTF,QAAA,MAAM,UAAU;;;;;;;;;;;;;;;;6EAId,CAAC;AACH,QAAA,MAAM,YAAY,EAAS,eAAe,CAAC,OAAO,UAAU,EAAE,WAAW,CAAC,CAAC;wBACtD,OAAO,YAAY;AAAxC,wBAAyC;AAWzC,KAAK,eAAe,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,GAAG;IAChC,QAAO;QACN,MAAM,EAAE,CAAC,CAAC;KACV,CAAA;CACD,CAAC"}
|
|
@@ -69,7 +69,7 @@ export interface CkHistoryProps {
|
|
|
69
69
|
* below the visible rows. Clicking it expands the list and makes it
|
|
70
70
|
* scrollable (capped at `maxHeight`).
|
|
71
71
|
*
|
|
72
|
-
* Set to `0`
|
|
72
|
+
* Set to `0` to disable collapsing — all conversations
|
|
73
73
|
* are shown and the list is always scrollable.
|
|
74
74
|
*
|
|
75
75
|
* @default 5
|
|
@@ -82,6 +82,14 @@ export interface CkHistoryProps {
|
|
|
82
82
|
* @default undefined — no max-height constraint
|
|
83
83
|
*/
|
|
84
84
|
maxHeight?: string;
|
|
85
|
+
/**
|
|
86
|
+
* Additional CSS class(es) applied to the inner `CkHistoryWrapper` that
|
|
87
|
+
* wraps the conversation rows. Useful for adjusting padding, spacing, or
|
|
88
|
+
* other layout concerns of the list container.
|
|
89
|
+
*
|
|
90
|
+
* @default undefined
|
|
91
|
+
*/
|
|
92
|
+
contentClass?: string;
|
|
85
93
|
}
|
|
86
94
|
/**
|
|
87
95
|
* Emitted events for `CkHistory`.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/components/composed/CkHistory/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B;;;;;;;;;;;;OAYG;IACH,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC;IACrC,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,EAAE,CAAC,gBAAgB,EAAE,MAAM,KAAK,MAAM,CAAC;IACrD;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../../../src/components/composed/CkHistory/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEnD;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,MAAM,WAAW,cAAc;IAC7B,iEAAiE;IACjE,aAAa,EAAE,YAAY,EAAE,CAAC;IAC9B;;;;;;;;;;;;OAYG;IACH,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,MAAM,CAAC;IACrC,yEAAyE;IACzE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB;;;OAGG;IACH,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB;;;OAGG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;;;;;;;;;OAYG;IACH,aAAa,CAAC,EAAE,CAAC,gBAAgB,EAAE,MAAM,KAAK,MAAM,CAAC;IACrD;;;;;;;;;;OAUG;IACH,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB;;;;;OAKG;IACH,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;;;OAMG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B;;;;;;;OAOG;IACH,MAAM,EAAE,CAAC,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,UAAU,CAAC,CAAC;IACxD,0EAA0E;IAC1E,IAAI,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;IACnC,4EAA4E;IAC5E,MAAM,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;CACtC"}
|
package/dist/components/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { _, a, C, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z } from "../CkHistory.vue_vue_type_script_setup_true_lang-
|
|
1
|
+
import { _, a, C, b, c, d, e, f, g, h, i, j, k, l, m, n, o, p, q, r, s, t, u, v, w, x, y, z } from "../CkHistory.vue_vue_type_script_setup_true_lang-C1busuyf.js";
|
|
2
2
|
export {
|
|
3
3
|
_ as CkAgentMessage,
|
|
4
4
|
a as CkAgentMessageHeader,
|
package/dist/index.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { u } from "./useMessageHandler-N50Yj-NU.js";
|
|
2
2
|
import { C, d, p, u as u2, a } from "./useChatKitLabels-DLy0BFx8.js";
|
|
3
3
|
import { S, c, d as d2, a as a2, u as u3, b, e, f } from "./index-CyrVnbS9.js";
|
|
4
|
-
import { _, a as a3, C as C2, b as b2, c as c2, d as d3, e as e2, f as f2, g, h, i, j, k, l, m, n, o, p as p2, q, r, s, t, u as u4, v, w, x, y, z, A } from "./CkHistory.vue_vue_type_script_setup_true_lang-
|
|
4
|
+
import { _, a as a3, C as C2, b as b2, c as c2, d as d3, e as e2, f as f2, g, h, i, j, k, l, m, n, o, p as p2, q, r, s, t, u as u4, v, w, x, y, z, A } from "./CkHistory.vue_vue_type_script_setup_true_lang-C1busuyf.js";
|
|
5
5
|
export {
|
|
6
6
|
C as CHAT_KIT_LABELS,
|
|
7
7
|
_ as CkAgentMessage,
|
package/package.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import CkConversationLayout from './CkConversationLayout.vue';
|
|
2
|
-
import { render, screen } from '@testing-library/vue';
|
|
2
|
+
import { fireEvent, render, screen } from '@testing-library/vue';
|
|
3
3
|
import { type Component, defineComponent, h } from 'vue';
|
|
4
4
|
|
|
5
5
|
const messages = [
|
|
@@ -126,4 +126,87 @@ describe('CkConversationLayout', () => {
|
|
|
126
126
|
expect(screen.getByText('42|2026-02-13|Hi')).toBeInTheDocument();
|
|
127
127
|
});
|
|
128
128
|
});
|
|
129
|
+
|
|
130
|
+
describe('scroll fade indicators', () => {
|
|
131
|
+
function getFadeElements(container: HTMLElement) {
|
|
132
|
+
return {
|
|
133
|
+
topFade: container.querySelector('.bg-gradient-to-b') as HTMLElement,
|
|
134
|
+
bottomFade: container.querySelector('.bg-gradient-to-t') as HTMLElement,
|
|
135
|
+
scrollEl: container.querySelector(
|
|
136
|
+
'[class*="overflow-y-auto"]',
|
|
137
|
+
) as HTMLElement,
|
|
138
|
+
};
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function setScrollMetrics(
|
|
142
|
+
el: HTMLElement,
|
|
143
|
+
{
|
|
144
|
+
scrollHeight,
|
|
145
|
+
clientHeight,
|
|
146
|
+
}: { scrollHeight: number; clientHeight: number },
|
|
147
|
+
) {
|
|
148
|
+
Object.defineProperty(el, 'scrollHeight', {
|
|
149
|
+
configurable: true,
|
|
150
|
+
value: scrollHeight,
|
|
151
|
+
});
|
|
152
|
+
Object.defineProperty(el, 'clientHeight', {
|
|
153
|
+
configurable: true,
|
|
154
|
+
value: clientHeight,
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
it('renders decorative top and bottom fade overlays', () => {
|
|
159
|
+
const { container } = renderLayout();
|
|
160
|
+
const { topFade, bottomFade } = getFadeElements(container);
|
|
161
|
+
|
|
162
|
+
expect(topFade).toBeTruthy();
|
|
163
|
+
expect(bottomFade).toBeTruthy();
|
|
164
|
+
expect(topFade.getAttribute('aria-hidden')).toBe('true');
|
|
165
|
+
expect(bottomFade.getAttribute('aria-hidden')).toBe('true');
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
it('hides both fades when the content is not scrollable', () => {
|
|
169
|
+
const { container } = renderLayout();
|
|
170
|
+
const { topFade, bottomFade } = getFadeElements(container);
|
|
171
|
+
|
|
172
|
+
expect(topFade.className).toContain('opacity-0');
|
|
173
|
+
expect(bottomFade.className).toContain('opacity-0');
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('shows both fades when scrolled into the middle of the content', async () => {
|
|
177
|
+
const { container } = renderLayout();
|
|
178
|
+
const { topFade, bottomFade, scrollEl } = getFadeElements(container);
|
|
179
|
+
|
|
180
|
+
setScrollMetrics(scrollEl, { scrollHeight: 1000, clientHeight: 400 });
|
|
181
|
+
scrollEl.scrollTop = 200;
|
|
182
|
+
await fireEvent.scroll(scrollEl);
|
|
183
|
+
|
|
184
|
+
expect(topFade.className).toContain('opacity-100');
|
|
185
|
+
expect(bottomFade.className).toContain('opacity-100');
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
it('hides the top fade at the start of the conversation', async () => {
|
|
189
|
+
const { container } = renderLayout();
|
|
190
|
+
const { topFade, bottomFade, scrollEl } = getFadeElements(container);
|
|
191
|
+
|
|
192
|
+
setScrollMetrics(scrollEl, { scrollHeight: 1000, clientHeight: 400 });
|
|
193
|
+
scrollEl.scrollTop = 0;
|
|
194
|
+
await fireEvent.scroll(scrollEl);
|
|
195
|
+
|
|
196
|
+
expect(topFade.className).toContain('opacity-0');
|
|
197
|
+
expect(bottomFade.className).toContain('opacity-100');
|
|
198
|
+
});
|
|
199
|
+
|
|
200
|
+
it('hides the bottom fade at the end of the conversation', async () => {
|
|
201
|
+
const { container } = renderLayout();
|
|
202
|
+
const { topFade, bottomFade, scrollEl } = getFadeElements(container);
|
|
203
|
+
|
|
204
|
+
setScrollMetrics(scrollEl, { scrollHeight: 1000, clientHeight: 400 });
|
|
205
|
+
scrollEl.scrollTop = 600;
|
|
206
|
+
await fireEvent.scroll(scrollEl);
|
|
207
|
+
|
|
208
|
+
expect(topFade.className).toContain('opacity-100');
|
|
209
|
+
expect(bottomFade.className).toContain('opacity-0');
|
|
210
|
+
});
|
|
211
|
+
});
|
|
129
212
|
});
|
|
@@ -18,6 +18,11 @@ const isAutoScrollEnabled = ref(true);
|
|
|
18
18
|
const hasBottomSpacer = ref(false);
|
|
19
19
|
const spacerHeight = ref(0);
|
|
20
20
|
|
|
21
|
+
// Whether there is scrollable content above / below the current viewport.
|
|
22
|
+
// Drives the top / bottom fade overlays that hint at more content to scroll to.
|
|
23
|
+
const showTopFade = ref(false);
|
|
24
|
+
const showBottomFade = ref(false);
|
|
25
|
+
|
|
21
26
|
let resizeObserver: ResizeObserver | null = null;
|
|
22
27
|
|
|
23
28
|
onMounted(() => {
|
|
@@ -28,12 +33,14 @@ onMounted(() => {
|
|
|
28
33
|
for (const entry of entries) {
|
|
29
34
|
containerHeight.value = entry.contentRect.height;
|
|
30
35
|
}
|
|
36
|
+
updateFades();
|
|
31
37
|
});
|
|
32
38
|
resizeObserver.observe(container);
|
|
33
39
|
|
|
34
40
|
// Initially scroll to the bottom of the conversation without any spacer
|
|
35
41
|
nextTick(() => {
|
|
36
42
|
container.scrollTop = container.scrollHeight;
|
|
43
|
+
updateFades();
|
|
37
44
|
});
|
|
38
45
|
}
|
|
39
46
|
});
|
|
@@ -60,6 +67,24 @@ function isFollowingContent(): boolean {
|
|
|
60
67
|
|
|
61
68
|
function handleScroll(): void {
|
|
62
69
|
isAutoScrollEnabled.value = isFollowingContent();
|
|
70
|
+
updateFades();
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Update the visibility of the top / bottom fade overlays based on the current
|
|
75
|
+
* scroll position. The top fade appears once the user has scrolled away from
|
|
76
|
+
* the start; the bottom fade appears while there is still content below the
|
|
77
|
+
* viewport. When the content fits entirely, both fades stay hidden.
|
|
78
|
+
*/
|
|
79
|
+
function updateFades(): void {
|
|
80
|
+
const container = scrollContainerRef.value;
|
|
81
|
+
if (!container) return;
|
|
82
|
+
|
|
83
|
+
const { scrollTop, scrollHeight, clientHeight } = container;
|
|
84
|
+
const maxScroll = scrollHeight - clientHeight;
|
|
85
|
+
|
|
86
|
+
showTopFade.value = scrollTop > 1;
|
|
87
|
+
showBottomFade.value = scrollTop < maxScroll - 1;
|
|
63
88
|
}
|
|
64
89
|
|
|
65
90
|
/**
|
|
@@ -153,7 +178,10 @@ watch(
|
|
|
153
178
|
if (newLen <= (oldLen ?? 0)) return;
|
|
154
179
|
const lastMessage = props.messages[newLen - 1];
|
|
155
180
|
if (lastMessage?.role === 'user') {
|
|
156
|
-
nextTick(() =>
|
|
181
|
+
nextTick(() => {
|
|
182
|
+
scrollUserMessageToTop();
|
|
183
|
+
updateFades();
|
|
184
|
+
});
|
|
157
185
|
}
|
|
158
186
|
},
|
|
159
187
|
);
|
|
@@ -171,6 +199,7 @@ watch(
|
|
|
171
199
|
if (isAutoScrollEnabled.value) {
|
|
172
200
|
scrollToEndOfContent();
|
|
173
201
|
}
|
|
202
|
+
updateFades();
|
|
174
203
|
});
|
|
175
204
|
}
|
|
176
205
|
},
|
|
@@ -179,29 +208,43 @@ watch(
|
|
|
179
208
|
</script>
|
|
180
209
|
|
|
181
210
|
<template>
|
|
182
|
-
<div
|
|
183
|
-
|
|
184
|
-
class="relative flex flex-col gap-8 overflow-y-auto"
|
|
185
|
-
@scroll="handleScroll"
|
|
186
|
-
>
|
|
211
|
+
<div class="relative flex min-h-0 flex-col overflow-hidden">
|
|
212
|
+
<!-- Top fade: hints that there is more content above the viewport -->
|
|
187
213
|
<div
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
:
|
|
191
|
-
|
|
214
|
+
aria-hidden="true"
|
|
215
|
+
class="pointer-events-none absolute inset-x-0 top-0 z-10 h-8 bg-gradient-to-b from-background-surface-secondary to-transparent transition-opacity duration-200"
|
|
216
|
+
:class="showTopFade ? 'opacity-100' : 'opacity-0'"
|
|
217
|
+
/>
|
|
218
|
+
<div
|
|
219
|
+
ref="scrollContainerRef"
|
|
220
|
+
class="relative flex min-h-0 flex-1 flex-col gap-8 overflow-y-auto"
|
|
221
|
+
@scroll="handleScroll"
|
|
192
222
|
>
|
|
193
|
-
<div
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
223
|
+
<div
|
|
224
|
+
v-for="message in messages"
|
|
225
|
+
:key="message.id"
|
|
226
|
+
:data-message-row="message.role"
|
|
227
|
+
class="min-w-0"
|
|
228
|
+
>
|
|
229
|
+
<div v-if="message.role === 'user'" class="flex min-w-0 justify-end">
|
|
230
|
+
<slot name="user-message" :message="message" />
|
|
231
|
+
</div>
|
|
232
|
+
<div v-else class="flex min-w-0 justify-start">
|
|
233
|
+
<slot name="agent-message" :message="message" />
|
|
234
|
+
</div>
|
|
198
235
|
</div>
|
|
236
|
+
<!-- Bottom spacer: shrinks as agent content grows to keep viewport stable -->
|
|
237
|
+
<div
|
|
238
|
+
v-if="hasBottomSpacer"
|
|
239
|
+
aria-hidden="true"
|
|
240
|
+
:style="{ minHeight: `${spacerHeight}px` }"
|
|
241
|
+
/>
|
|
199
242
|
</div>
|
|
200
|
-
<!-- Bottom
|
|
243
|
+
<!-- Bottom fade: hints that there is more content below the viewport -->
|
|
201
244
|
<div
|
|
202
|
-
v-if="hasBottomSpacer"
|
|
203
245
|
aria-hidden="true"
|
|
204
|
-
|
|
246
|
+
class="pointer-events-none absolute inset-x-0 bottom-0 z-10 h-8 bg-gradient-to-t from-background-surface-secondary to-transparent transition-opacity duration-200"
|
|
247
|
+
:class="showBottomFade ? 'opacity-100' : 'opacity-0'"
|
|
205
248
|
/>
|
|
206
249
|
</div>
|
|
207
250
|
</template>
|
|
@@ -13,7 +13,7 @@ const props = withDefaults(defineProps<CkHistoryWrapperProps>(), {
|
|
|
13
13
|
|
|
14
14
|
const attrs = useAttrs();
|
|
15
15
|
|
|
16
|
-
const baseClass = 'flex w-full min-w-0 flex-col
|
|
16
|
+
const baseClass = 'flex w-full min-w-0 flex-col py-2';
|
|
17
17
|
|
|
18
18
|
const rootClass = computed(() => {
|
|
19
19
|
const consumerClass =
|
|
@@ -433,4 +433,34 @@ describe('CkHistory', () => {
|
|
|
433
433
|
expect(emitted().select).toBeUndefined();
|
|
434
434
|
});
|
|
435
435
|
});
|
|
436
|
+
|
|
437
|
+
describe('contentClass', () => {
|
|
438
|
+
it('applies contentClass to the inner history wrapper', () => {
|
|
439
|
+
const { container } = render(CkHistory, {
|
|
440
|
+
props: {
|
|
441
|
+
conversations: [makeConversation({ id: 'c-1' })],
|
|
442
|
+
hrefResolver,
|
|
443
|
+
contentClass: 'px-2 custom-content',
|
|
444
|
+
},
|
|
445
|
+
});
|
|
446
|
+
|
|
447
|
+
const wrapper = container.querySelector('[data-slot="chat-history"]');
|
|
448
|
+
expect(wrapper).toBeTruthy();
|
|
449
|
+
expect(wrapper?.className).toMatch(/px-2/);
|
|
450
|
+
expect(wrapper?.className).toMatch(/custom-content/);
|
|
451
|
+
});
|
|
452
|
+
|
|
453
|
+
it('does not add any content class to the wrapper by default', () => {
|
|
454
|
+
const { container } = render(CkHistory, {
|
|
455
|
+
props: {
|
|
456
|
+
conversations: [makeConversation({ id: 'c-1' })],
|
|
457
|
+
hrefResolver,
|
|
458
|
+
},
|
|
459
|
+
});
|
|
460
|
+
|
|
461
|
+
const wrapper = container.querySelector('[data-slot="chat-history"]');
|
|
462
|
+
expect(wrapper).toBeTruthy();
|
|
463
|
+
expect(wrapper?.className).not.toMatch(/px-2/);
|
|
464
|
+
});
|
|
465
|
+
});
|
|
436
466
|
});
|
|
@@ -22,6 +22,7 @@ const props = withDefaults(defineProps<CkHistoryProps>(), {
|
|
|
22
22
|
timeFormatter: formatRelativeTime,
|
|
23
23
|
collapsedLimit: 5,
|
|
24
24
|
maxHeight: undefined,
|
|
25
|
+
contentClass: undefined,
|
|
25
26
|
});
|
|
26
27
|
|
|
27
28
|
const emit = defineEmits<CkHistoryEmits>();
|
|
@@ -106,7 +107,10 @@ function handleRowClick(c: Conversation, event: MouseEvent) {
|
|
|
106
107
|
<template>
|
|
107
108
|
<div>
|
|
108
109
|
<CkHistoryWrapper
|
|
109
|
-
:class="
|
|
110
|
+
:class="[
|
|
111
|
+
isExpanded && props.maxHeight ? 'overflow-y-auto' : undefined,
|
|
112
|
+
props.contentClass,
|
|
113
|
+
]"
|
|
110
114
|
:style="
|
|
111
115
|
isExpanded && props.maxHeight
|
|
112
116
|
? { maxHeight: props.maxHeight }
|
|
@@ -70,7 +70,7 @@ export interface CkHistoryProps {
|
|
|
70
70
|
* below the visible rows. Clicking it expands the list and makes it
|
|
71
71
|
* scrollable (capped at `maxHeight`).
|
|
72
72
|
*
|
|
73
|
-
* Set to `0`
|
|
73
|
+
* Set to `0` to disable collapsing — all conversations
|
|
74
74
|
* are shown and the list is always scrollable.
|
|
75
75
|
*
|
|
76
76
|
* @default 5
|
|
@@ -83,6 +83,14 @@ export interface CkHistoryProps {
|
|
|
83
83
|
* @default undefined — no max-height constraint
|
|
84
84
|
*/
|
|
85
85
|
maxHeight?: string;
|
|
86
|
+
/**
|
|
87
|
+
* Additional CSS class(es) applied to the inner `CkHistoryWrapper` that
|
|
88
|
+
* wraps the conversation rows. Useful for adjusting padding, spacing, or
|
|
89
|
+
* other layout concerns of the list container.
|
|
90
|
+
*
|
|
91
|
+
* @default undefined
|
|
92
|
+
*/
|
|
93
|
+
contentClass?: string;
|
|
86
94
|
}
|
|
87
95
|
|
|
88
96
|
/**
|