@limetech/lime-crm-building-blocks 1.118.1 → 1.119.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/CHANGELOG.md +7 -0
- package/dist/cjs/lime-crm-building-blocks.cjs.js +1 -1
- package/dist/cjs/limebb-alert-dialog.cjs.entry.js +1 -1
- package/dist/cjs/limebb-browser.cjs.entry.js +2 -2
- package/dist/cjs/limebb-chat-icon-list_3.cjs.entry.js +4 -4
- package/dist/cjs/limebb-chat-list.cjs.entry.js +336 -68
- package/dist/cjs/limebb-composer-toolbar.cjs.entry.js +2 -2
- package/dist/cjs/limebb-currency-picker.cjs.entry.js +1 -1
- package/dist/cjs/limebb-dashboard-widget.cjs.entry.js +1 -1
- package/dist/cjs/limebb-date-picker.cjs.entry.js +1 -1
- package/dist/cjs/limebb-date-range.cjs.entry.js +1 -1
- package/dist/cjs/limebb-document-chips.cjs.entry.js +1 -1
- package/dist/cjs/limebb-document-item.cjs.entry.js +2 -2
- package/dist/cjs/limebb-document-picker.cjs.entry.js +1 -1
- package/dist/cjs/limebb-feed-item-thumbnail-file-info.cjs.entry.js +1 -1
- package/dist/cjs/limebb-feed-timeline-item.cjs.entry.js +1 -1
- package/dist/cjs/limebb-feed.cjs.entry.js +1 -1
- package/dist/cjs/limebb-icon-picker.cjs.entry.js +1 -1
- package/dist/cjs/limebb-info-tile-format.cjs.entry.js +1 -1
- package/dist/cjs/limebb-info-tile.cjs.entry.js +1 -1
- package/dist/cjs/limebb-kanban-group.cjs.entry.js +1 -1
- package/dist/cjs/limebb-kanban-item.cjs.entry.js +1 -1
- package/dist/cjs/limebb-lime-query-builder.cjs.entry.js +1 -1
- package/dist/cjs/limebb-lime-query-filter-builder_3.cjs.entry.js +2 -2
- package/dist/cjs/limebb-lime-query-filter-comparison_2.cjs.entry.js +1 -1
- package/dist/cjs/limebb-lime-query-filter-group_3.cjs.entry.js +3 -3
- package/dist/cjs/limebb-lime-query-order-by-item.cjs.entry.js +2 -2
- package/dist/cjs/limebb-lime-query-response-format-builder.cjs.entry.js +1 -1
- package/dist/cjs/limebb-lime-query-response-format-editor_2.cjs.entry.js +1 -1
- package/dist/cjs/limebb-live-docs-info.cjs.entry.js +2 -2
- package/dist/cjs/limebb-locale-picker.cjs.entry.js +1 -1
- package/dist/cjs/limebb-mention-group-counter.cjs.entry.js +2 -2
- package/dist/cjs/limebb-navigation-button_2.cjs.entry.js +2 -2
- package/dist/cjs/limebb-notification-item.cjs.entry.js +1 -1
- package/dist/cjs/limebb-percentage-visualizer.cjs.entry.js +2 -2
- package/dist/cjs/limebb-text-editor.cjs.entry.js +1 -1
- package/dist/cjs/limebb-trend-indicator.cjs.entry.js +1 -1
- package/dist/cjs/loader.cjs.js +1 -1
- package/dist/collection/components/alert-dialog/alert-dialog.js +1 -1
- package/dist/collection/components/browser/browser.js +2 -2
- package/dist/collection/components/chat-list/chat-icon-list/chat-icon-list.js +1 -1
- package/dist/collection/components/chat-list/chat-item/chat-item.js +2 -2
- package/dist/collection/components/chat-list/chat-list.css +10 -10
- package/dist/collection/components/chat-list/chat-list.js +93 -25
- package/dist/collection/components/chat-list/process-chat-items.js +111 -45
- package/dist/collection/components/chat-list/scroll-anchor.js +93 -0
- package/dist/collection/components/chat-list/typing-indicator/typing-indicator.js +1 -1
- package/dist/collection/components/chat-list/typing-indicator-scroll.js +41 -0
- package/dist/collection/components/composer-toolbar/composer-toolbar.js +2 -2
- package/dist/collection/components/currency-picker/currency-picker.js +1 -1
- package/dist/collection/components/dashboard-widget/dashboard-widget.js +1 -1
- package/dist/collection/components/date-picker/date-picker.js +1 -1
- package/dist/collection/components/date-range/date-range.js +1 -1
- package/dist/collection/components/document-chips/document-chips.js +1 -1
- package/dist/collection/components/document-picker/document-item/document-item.js +2 -2
- package/dist/collection/components/document-picker/document-picker.js +1 -1
- package/dist/collection/components/feed/feed-item/feed-timeline-item.js +1 -1
- package/dist/collection/components/feed/feed-item-thumbnail-file-info/feed-item-thumbnail-file-info.js +1 -1
- package/dist/collection/components/feed/feed.js +1 -1
- package/dist/collection/components/icon-picker/icon-picker.js +1 -1
- package/dist/collection/components/info-tile/format/config/info-tile-format.js +1 -1
- package/dist/collection/components/info-tile/info-tile.js +1 -1
- package/dist/collection/components/kanban/kanban-group/kanban-group.js +1 -1
- package/dist/collection/components/kanban/kanban-item/kanban-item.js +1 -1
- package/dist/collection/components/lime-query-builder/expressions/lime-query-filter-comparison.js +1 -1
- package/dist/collection/components/lime-query-builder/expressions/lime-query-filter-group.js +2 -2
- package/dist/collection/components/lime-query-builder/expressions/lime-query-filter-not.js +1 -1
- package/dist/collection/components/lime-query-builder/lime-query-builder.js +1 -1
- package/dist/collection/components/lime-query-builder/lime-query-response-format-builder.js +1 -1
- package/dist/collection/components/lime-query-builder/limetype-field/limetype-field.js +1 -1
- package/dist/collection/components/lime-query-builder/order-by/order-by-editor.js +1 -1
- package/dist/collection/components/lime-query-builder/order-by/order-by-item.js +2 -2
- package/dist/collection/components/lime-query-builder/response-format/response-format-item.js +1 -1
- package/dist/collection/components/limeobject/file-viewer/live-docs-info.js +2 -2
- package/dist/collection/components/locale-picker/locale-picker.js +1 -1
- package/dist/collection/components/notification-list/notification-item/notification-item.js +1 -1
- package/dist/collection/components/percentage-visualizer/percentage-visualizer.js +2 -2
- package/dist/collection/components/summary-popover/summary-popover.js +2 -2
- package/dist/collection/components/text-editor/mention-group-counter.js +2 -2
- package/dist/collection/components/text-editor/text-editor.js +1 -1
- package/dist/collection/components/trend-indicator/trend-indicator.js +1 -1
- package/dist/components/chat-icon-list.js +1 -1
- package/dist/components/chat-item.js +1 -1
- package/dist/components/currency-picker.js +1 -1
- package/dist/components/date-picker.js +1 -1
- package/dist/components/document-item.js +1 -1
- package/dist/components/feed-item-thumbnail-file-info.js +1 -1
- package/dist/components/feed-timeline-item.js +1 -1
- package/dist/components/kanban-group.js +1 -1
- package/dist/components/kanban-item.js +1 -1
- package/dist/components/lime-query-filter-comparison.js +1 -1
- package/dist/components/lime-query-filter-expression.js +1 -1
- package/dist/components/limebb-alert-dialog.js +1 -1
- package/dist/components/limebb-browser.js +1 -1
- package/dist/components/limebb-chat-list.js +1 -1
- package/dist/components/limebb-composer-toolbar.js +1 -1
- package/dist/components/limebb-dashboard-widget.js +1 -1
- package/dist/components/limebb-date-range.js +1 -1
- package/dist/components/limebb-document-chips.js +1 -1
- package/dist/components/limebb-document-picker.js +1 -1
- package/dist/components/limebb-feed.js +1 -1
- package/dist/components/limebb-icon-picker.js +1 -1
- package/dist/components/limebb-info-tile-format.js +1 -1
- package/dist/components/limebb-info-tile.js +1 -1
- package/dist/components/limebb-lime-query-builder.js +1 -1
- package/dist/components/limebb-lime-query-response-format-builder.js +1 -1
- package/dist/components/limebb-locale-picker.js +1 -1
- package/dist/components/limebb-mention-group-counter.js +1 -1
- package/dist/components/limebb-text-editor.js +1 -1
- package/dist/components/limebb-trend-indicator.js +1 -1
- package/dist/components/limetype-field.js +1 -1
- package/dist/components/live-docs-info.js +1 -1
- package/dist/components/notification-item.js +1 -1
- package/dist/components/order-by-editor.js +1 -1
- package/dist/components/order-by-item.js +1 -1
- package/dist/components/percentage-visualizer.js +1 -1
- package/dist/components/response-format-item.js +1 -1
- package/dist/components/summary-popover.js +1 -1
- package/dist/components/typing-indicator.js +1 -1
- package/dist/esm/lime-crm-building-blocks.js +1 -1
- package/dist/esm/limebb-alert-dialog.entry.js +1 -1
- package/dist/esm/limebb-browser.entry.js +2 -2
- package/dist/esm/limebb-chat-icon-list_3.entry.js +4 -4
- package/dist/esm/limebb-chat-list.entry.js +337 -69
- package/dist/esm/limebb-composer-toolbar.entry.js +2 -2
- package/dist/esm/limebb-currency-picker.entry.js +1 -1
- package/dist/esm/limebb-dashboard-widget.entry.js +1 -1
- package/dist/esm/limebb-date-picker.entry.js +1 -1
- package/dist/esm/limebb-date-range.entry.js +1 -1
- package/dist/esm/limebb-document-chips.entry.js +1 -1
- package/dist/esm/limebb-document-item.entry.js +2 -2
- package/dist/esm/limebb-document-picker.entry.js +1 -1
- package/dist/esm/limebb-feed-item-thumbnail-file-info.entry.js +1 -1
- package/dist/esm/limebb-feed-timeline-item.entry.js +1 -1
- package/dist/esm/limebb-feed.entry.js +1 -1
- package/dist/esm/limebb-icon-picker.entry.js +1 -1
- package/dist/esm/limebb-info-tile-format.entry.js +1 -1
- package/dist/esm/limebb-info-tile.entry.js +1 -1
- package/dist/esm/limebb-kanban-group.entry.js +1 -1
- package/dist/esm/limebb-kanban-item.entry.js +1 -1
- package/dist/esm/limebb-lime-query-builder.entry.js +1 -1
- package/dist/esm/limebb-lime-query-filter-builder_3.entry.js +2 -2
- package/dist/esm/limebb-lime-query-filter-comparison_2.entry.js +1 -1
- package/dist/esm/limebb-lime-query-filter-group_3.entry.js +3 -3
- package/dist/esm/limebb-lime-query-order-by-item.entry.js +2 -2
- package/dist/esm/limebb-lime-query-response-format-builder.entry.js +1 -1
- package/dist/esm/limebb-lime-query-response-format-editor_2.entry.js +1 -1
- package/dist/esm/limebb-live-docs-info.entry.js +2 -2
- package/dist/esm/limebb-locale-picker.entry.js +1 -1
- package/dist/esm/limebb-mention-group-counter.entry.js +2 -2
- package/dist/esm/limebb-navigation-button_2.entry.js +2 -2
- package/dist/esm/limebb-notification-item.entry.js +1 -1
- package/dist/esm/limebb-percentage-visualizer.entry.js +2 -2
- package/dist/esm/limebb-text-editor.entry.js +1 -1
- package/dist/esm/limebb-trend-indicator.entry.js +1 -1
- package/dist/esm/loader.js +1 -1
- package/dist/lime-crm-building-blocks/lime-crm-building-blocks.esm.js +1 -1
- package/dist/lime-crm-building-blocks/{p-685dd8a1.entry.js → p-02a3530f.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-52fb2a66.entry.js → p-16ad65dc.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-6cb2d9dd.entry.js → p-2079ae59.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-c3b13800.entry.js → p-2aae332a.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-b3ee6683.entry.js → p-4edfa72a.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-b36ad4e8.entry.js → p-5058bc60.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-8477cb5d.entry.js → p-52fd0169.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-21ec697f.entry.js → p-54ae7814.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-35a51259.entry.js → p-54bb577b.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/p-59b992b3.entry.js +1 -0
- package/dist/lime-crm-building-blocks/{p-1a61674f.entry.js → p-5ef41ad0.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-f375d69a.entry.js → p-640c41a3.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-528f3635.entry.js → p-65485470.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-4ddd75bc.entry.js → p-655968ce.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-8a05a0e5.entry.js → p-67551f9d.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-152edb10.entry.js → p-750dbb18.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-bac3d599.entry.js → p-83e93ebd.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-fa41a9e6.entry.js → p-8a820ede.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/p-8da95b3a.entry.js +1 -0
- package/dist/lime-crm-building-blocks/{p-943c8589.entry.js → p-999c1628.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-62437a1d.entry.js → p-aea85d91.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-9ae55a96.entry.js → p-b17327da.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-71191041.entry.js → p-b3db6a41.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-6fdee70a.entry.js → p-b6895996.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-cff9bccd.entry.js → p-b92eedb5.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-aaeecca6.entry.js → p-c019f7f2.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-fdf269f7.entry.js → p-c3648986.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-ebe6040f.entry.js → p-cc07285b.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-ffb847d0.entry.js → p-cee4e6a6.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-18fc1a06.entry.js → p-d153e06d.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-be8dc8ae.entry.js → p-e33feb37.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-fcedbc77.entry.js → p-e4005988.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-a48a6ff8.entry.js → p-e8a0bbb8.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-eec0a0c8.entry.js → p-ebeddc29.entry.js} +1 -1
- package/dist/lime-crm-building-blocks/{p-5a1f0a2b.entry.js → p-fa808d3a.entry.js} +1 -1
- package/dist/types/components/chat-list/chat-list.d.ts +13 -3
- package/dist/types/components/chat-list/process-chat-items.d.ts +20 -4
- package/dist/types/components/chat-list/scroll-anchor.d.ts +46 -0
- package/dist/types/components/chat-list/typing-indicator-scroll.d.ts +18 -0
- package/dist/types/components.d.ts +4 -4
- package/package.json +1 -1
- package/dist/lime-crm-building-blocks/p-b10faec5.entry.js +0 -1
- package/dist/lime-crm-building-blocks/p-f23ea0e7.entry.js +0 -1
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { r as registerInstance, h, H as Host } from './index-BIwHMk6j.js';
|
|
1
|
+
import { r as registerInstance, h, H as Host, g as getElement } from './index-BIwHMk6j.js';
|
|
2
2
|
import { n } from './index.esm-BjlE4usG.js';
|
|
3
3
|
|
|
4
4
|
function isIconList(item) {
|
|
@@ -13,7 +13,7 @@ function getProcessedItemTimestamp(item) {
|
|
|
13
13
|
/**
|
|
14
14
|
* Processes a list of chat list inputs by adding date headers and a "new items" indicator.
|
|
15
15
|
*
|
|
16
|
-
* @param items - The list of items to process. Pre-sorted by `timestamp` in
|
|
16
|
+
* @param items - The list of items to process. Pre-sorted by `timestamp` in ascending order.
|
|
17
17
|
* @param dateTimeFormatter - A service used to format dates for the date headers.
|
|
18
18
|
* @param lastVisitedTimestamp - The timestamp of the user's last visit. Used to position the
|
|
19
19
|
* "new items" indicator.
|
|
@@ -27,16 +27,18 @@ function processChatItems(items, dateTimeFormatter, lastVisitedTimestamp) {
|
|
|
27
27
|
processedItems: [],
|
|
28
28
|
lastVisitedTimestamp: lastVisitedTimestamp,
|
|
29
29
|
dateTimeFormatter: dateTimeFormatter,
|
|
30
|
-
newItemIndicatorInserted: false,
|
|
31
|
-
lastProcessedDate: null,
|
|
32
|
-
hasUnseenNotifications: items.some((item) => lastVisitedTimestamp &&
|
|
33
|
-
new Date(item.timestamp) > lastVisitedTimestamp),
|
|
34
30
|
};
|
|
35
|
-
// Add processors here, in the order they should be executed
|
|
31
|
+
// Add processors here, in the order they should be executed.
|
|
32
|
+
// `insertNewItemIndicator` runs after `insertDateGroups` so the
|
|
33
|
+
// indicator can be placed at top level when the seen/unseen
|
|
34
|
+
// boundary falls between two groups, and only inside a group when
|
|
35
|
+
// the boundary falls within a single day. That placement makes
|
|
36
|
+
// `reverseProcessedItems` a pure two-level reverse — no group-
|
|
37
|
+
// boundary hoisting needed.
|
|
36
38
|
const processors = [
|
|
37
39
|
insertNotifications,
|
|
38
|
-
insertNewItemIndicator,
|
|
39
40
|
insertDateGroups,
|
|
41
|
+
insertNewItemIndicator,
|
|
40
42
|
];
|
|
41
43
|
const finalContext = createPipeline(initialContext, processors);
|
|
42
44
|
return finalContext.processedItems;
|
|
@@ -45,6 +47,32 @@ function createPipeline(initialContext, processors) {
|
|
|
45
47
|
// eslint-disable-next-line unicorn/no-array-reduce
|
|
46
48
|
return processors.reduce((context, processor) => processor(context), initialContext);
|
|
47
49
|
}
|
|
50
|
+
/**
|
|
51
|
+
* Reverses the chronological order of a processed-items array.
|
|
52
|
+
*
|
|
53
|
+
* Pure two-level reverse: the top-level array is reversed, and each
|
|
54
|
+
* group's items are reversed. `insertNewItemIndicator` places the
|
|
55
|
+
* indicator at top level when the seen/unseen boundary falls
|
|
56
|
+
* between groups, and only nests it inside a group when the
|
|
57
|
+
* boundary falls within a single day — so reversal never needs to
|
|
58
|
+
* move an indicator across levels to preserve its separator role.
|
|
59
|
+
*
|
|
60
|
+
* Used by `limebb-chat-list` when rendering in `newest-on-top`
|
|
61
|
+
* layout, so that DOM order continues to match visual order
|
|
62
|
+
* (newest-first in that layout), keeping copy/paste, screen-reader,
|
|
63
|
+
* and tab order aligned with what the user sees.
|
|
64
|
+
*
|
|
65
|
+
* @param items - processed items in ascending-by-timestamp order
|
|
66
|
+
* @returns processed items in descending-by-timestamp order
|
|
67
|
+
*/
|
|
68
|
+
function reverseProcessedItems(items) {
|
|
69
|
+
return items.toReversed().map((item) => {
|
|
70
|
+
if (item.type !== 'group') {
|
|
71
|
+
return item;
|
|
72
|
+
}
|
|
73
|
+
return Object.assign(Object.assign({}, item), { items: item.items.toReversed() });
|
|
74
|
+
});
|
|
75
|
+
}
|
|
48
76
|
/**
|
|
49
77
|
*
|
|
50
78
|
* @param context
|
|
@@ -65,61 +93,99 @@ function insertNotifications(context) {
|
|
|
65
93
|
* @param context
|
|
66
94
|
*/
|
|
67
95
|
function insertNewItemIndicator(context) {
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
96
|
+
if (!context.lastVisitedTimestamp) {
|
|
97
|
+
return context;
|
|
98
|
+
}
|
|
99
|
+
const groups = context.processedItems;
|
|
100
|
+
const lastVisited = context.lastVisitedTimestamp;
|
|
101
|
+
// Walk groups newest → oldest. Items and groups are sorted
|
|
102
|
+
// ascending, so at most one group straddles the seen/unseen
|
|
103
|
+
// boundary; the rest are entirely seen or entirely unseen. In an
|
|
104
|
+
// active chat where the newest item is already seen, the loop
|
|
105
|
+
// exits in O(1).
|
|
106
|
+
for (let g = groups.length - 1; g >= 0; g--) {
|
|
107
|
+
const group = groups[g];
|
|
108
|
+
if (group.type !== 'group') {
|
|
109
|
+
continue;
|
|
79
110
|
}
|
|
80
|
-
|
|
111
|
+
const seenIndex = findNewestSeenIndex(group.items, lastVisited);
|
|
112
|
+
if (seenIndex === -1) {
|
|
113
|
+
continue;
|
|
114
|
+
}
|
|
115
|
+
return placeIndicatorAtBoundary(context, groups, g, group, seenIndex);
|
|
81
116
|
}
|
|
82
|
-
|
|
83
|
-
context.newItemIndicatorInserted = newItemIndicatorInserted;
|
|
117
|
+
// No seen item found — everything is unseen, no boundary to mark.
|
|
84
118
|
return context;
|
|
85
119
|
}
|
|
120
|
+
function findNewestSeenIndex(items, lastVisited) {
|
|
121
|
+
for (let i = items.length - 1; i >= 0; i--) {
|
|
122
|
+
const timestamp = getProcessedItemTimestamp(items[i]);
|
|
123
|
+
if (timestamp === undefined) {
|
|
124
|
+
continue;
|
|
125
|
+
}
|
|
126
|
+
if (new Date(timestamp) <= lastVisited) {
|
|
127
|
+
return i;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return -1;
|
|
131
|
+
}
|
|
132
|
+
function placeIndicatorAtBoundary(context, groups, groupIndex, group, seenIndex) {
|
|
133
|
+
const isLastItemInGroup = seenIndex === group.items.length - 1;
|
|
134
|
+
const isLastGroup = groupIndex === groups.length - 1;
|
|
135
|
+
// Newest seen item is the very last item overall → everything is
|
|
136
|
+
// seen, nothing to mark.
|
|
137
|
+
if (isLastItemInGroup && isLastGroup) {
|
|
138
|
+
return context;
|
|
139
|
+
}
|
|
140
|
+
// Seen item is last in its group → boundary is between groups.
|
|
141
|
+
// Place the indicator at top level so reversal stays a pure
|
|
142
|
+
// two-level reverse.
|
|
143
|
+
if (isLastItemInGroup) {
|
|
144
|
+
return Object.assign(Object.assign({}, context), { processedItems: [
|
|
145
|
+
...groups.slice(0, groupIndex + 1),
|
|
146
|
+
{ type: 'newItemIndicator' },
|
|
147
|
+
...groups.slice(groupIndex + 1),
|
|
148
|
+
] });
|
|
149
|
+
}
|
|
150
|
+
// Boundary falls inside a single day — indicator stays nested.
|
|
151
|
+
const newGroupItems = [
|
|
152
|
+
...group.items.slice(0, seenIndex + 1),
|
|
153
|
+
{ type: 'newItemIndicator' },
|
|
154
|
+
...group.items.slice(seenIndex + 1),
|
|
155
|
+
];
|
|
156
|
+
return Object.assign(Object.assign({}, context), { processedItems: [
|
|
157
|
+
...groups.slice(0, groupIndex),
|
|
158
|
+
Object.assign(Object.assign({}, group), { items: newGroupItems }),
|
|
159
|
+
...groups.slice(groupIndex + 1),
|
|
160
|
+
] });
|
|
161
|
+
}
|
|
86
162
|
/**
|
|
87
163
|
*
|
|
88
164
|
* @param context
|
|
89
165
|
*/
|
|
90
|
-
// eslint-disable-next-line sonarjs/cognitive-complexity
|
|
91
166
|
function insertDateGroups(context) {
|
|
92
167
|
const newProcessedItems = [];
|
|
93
168
|
let currentGroup = null;
|
|
94
169
|
let lastProcessedDate = null;
|
|
95
170
|
for (const item of context.processedItems) {
|
|
96
|
-
if (item.type
|
|
97
|
-
|
|
98
|
-
const currentDate = context.dateTimeFormatter.format(currentTimestamp, 'date');
|
|
99
|
-
if (currentDate !== lastProcessedDate) {
|
|
100
|
-
if (currentGroup) {
|
|
101
|
-
newProcessedItems.push(currentGroup);
|
|
102
|
-
}
|
|
103
|
-
currentGroup = {
|
|
104
|
-
type: 'group',
|
|
105
|
-
groupType: 'dateGroup',
|
|
106
|
-
heading: currentDate,
|
|
107
|
-
items: [],
|
|
108
|
-
};
|
|
109
|
-
lastProcessedDate = currentDate;
|
|
110
|
-
}
|
|
111
|
-
if (currentGroup) {
|
|
112
|
-
currentGroup.items.push(item);
|
|
113
|
-
}
|
|
171
|
+
if (item.type !== 'chat' && item.type !== 'iconList') {
|
|
172
|
+
continue;
|
|
114
173
|
}
|
|
115
|
-
|
|
174
|
+
const currentDate = context.dateTimeFormatter.format(new Date(item.item.timestamp), 'date');
|
|
175
|
+
if (currentDate !== lastProcessedDate) {
|
|
116
176
|
if (currentGroup) {
|
|
117
|
-
|
|
118
|
-
}
|
|
119
|
-
else {
|
|
120
|
-
newProcessedItems.push(item);
|
|
177
|
+
newProcessedItems.push(currentGroup);
|
|
121
178
|
}
|
|
179
|
+
currentGroup = {
|
|
180
|
+
type: 'group',
|
|
181
|
+
groupType: 'dateGroup',
|
|
182
|
+
heading: currentDate,
|
|
183
|
+
items: [item],
|
|
184
|
+
};
|
|
185
|
+
lastProcessedDate = currentDate;
|
|
186
|
+
continue;
|
|
122
187
|
}
|
|
188
|
+
currentGroup === null || currentGroup === void 0 ? void 0 : currentGroup.items.push(item);
|
|
123
189
|
}
|
|
124
190
|
if (currentGroup) {
|
|
125
191
|
newProcessedItems.push(currentGroup);
|
|
@@ -127,14 +193,153 @@ function insertDateGroups(context) {
|
|
|
127
193
|
return Object.assign(Object.assign({}, context), { processedItems: newProcessedItems });
|
|
128
194
|
}
|
|
129
195
|
|
|
130
|
-
|
|
196
|
+
// "Near enough the newest edge to count as sticky." 50px is roughly
|
|
197
|
+
// two message-bubble margins; a user who is within that distance
|
|
198
|
+
// clearly wasn't scrolling back through history, so we treat their
|
|
199
|
+
// position as "stuck to newest" and re-pin on each items update.
|
|
200
|
+
const NEAR_NEWEST_THRESHOLD_PX = 50;
|
|
201
|
+
/**
|
|
202
|
+
* Keeps a scroll container stuck to its "newest" edge as items are
|
|
203
|
+
* appended, so long as the user hasn't scrolled away.
|
|
204
|
+
*
|
|
205
|
+
* We use imperative scrolling rather than `flex-direction: column-reverse`
|
|
206
|
+
* so DOM order matches visual order (copy/paste, screen readers, tab
|
|
207
|
+
* order all align with what the user sees). CSS `overflow-anchor: auto`
|
|
208
|
+
* — the default and left enabled here — solves a different problem:
|
|
209
|
+
* preserving scroll position when content is inserted *above* the
|
|
210
|
+
* viewport. It doesn't stick the scroll to the newest edge when items
|
|
211
|
+
* arrive below the viewport, which is what chat typically needs; that
|
|
212
|
+
* requires the imperative approach in this class.
|
|
213
|
+
*
|
|
214
|
+
* Lifecycle:
|
|
215
|
+
* - `beforeRender()` in `componentWillRender` — snapshot whether the
|
|
216
|
+
* user is near the newest edge, using the order the scroll position
|
|
217
|
+
* was last measured against. Capturing here (synchronously, before
|
|
218
|
+
* the new DOM lands) avoids the race a scroll-event listener would
|
|
219
|
+
* have with `componentDidRender`.
|
|
220
|
+
* - `afterRender()` in `componentDidRender` — if the snapshot said
|
|
221
|
+
* "near newest", re-pin to the newest edge (new `scrollHeight`).
|
|
222
|
+
* - `repinIfSticky()` for out-of-band re-pins (e.g. after the typing
|
|
223
|
+
* indicator's height transition finishes — its `scrollHeight`
|
|
224
|
+
* change lands after `componentDidRender`).
|
|
225
|
+
*
|
|
226
|
+
* Scroll-container contract: the passed element must itself be the
|
|
227
|
+
* scrolling ancestor (the element whose `scrollTop` / `scrollHeight`
|
|
228
|
+
* / `clientHeight` reflect the chat list's scroll state). In practice
|
|
229
|
+
* that is the component's host, which sets `overflow: hidden auto` on
|
|
230
|
+
* itself. If future refactors introduce an inner scrolling wrapper,
|
|
231
|
+
* pass that wrapper instead.
|
|
232
|
+
*/
|
|
233
|
+
class ScrollAnchor {
|
|
234
|
+
constructor(scrollContainer, getOrder, initialOrder) {
|
|
235
|
+
this.scrollContainer = scrollContainer;
|
|
236
|
+
this.getOrder = getOrder;
|
|
237
|
+
this.isSticky = true;
|
|
238
|
+
this.paintedOrder = initialOrder;
|
|
239
|
+
}
|
|
240
|
+
beforeRender() {
|
|
241
|
+
if (!this.scrollContainer.isConnected) {
|
|
242
|
+
return;
|
|
243
|
+
}
|
|
244
|
+
// Measure against the order the scroll position was last painted
|
|
245
|
+
// with. If `order` just changed, the scroll position still refers
|
|
246
|
+
// to the previous layout until this render commits.
|
|
247
|
+
this.isSticky =
|
|
248
|
+
this.distanceFromNewestEdge(this.paintedOrder) <
|
|
249
|
+
NEAR_NEWEST_THRESHOLD_PX;
|
|
250
|
+
}
|
|
251
|
+
afterRender() {
|
|
252
|
+
if (!this.scrollContainer.isConnected) {
|
|
253
|
+
return;
|
|
254
|
+
}
|
|
255
|
+
this.paintedOrder = this.getOrder();
|
|
256
|
+
if (this.isSticky) {
|
|
257
|
+
this.scrollToNewest();
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
repinIfSticky() {
|
|
261
|
+
if (!this.scrollContainer.isConnected) {
|
|
262
|
+
return;
|
|
263
|
+
}
|
|
264
|
+
if (this.isSticky) {
|
|
265
|
+
this.scrollToNewest();
|
|
266
|
+
}
|
|
267
|
+
}
|
|
268
|
+
scrollToNewest() {
|
|
269
|
+
const target = this.getOrder() === 'oldest-on-top'
|
|
270
|
+
? this.scrollContainer.scrollHeight
|
|
271
|
+
: 0;
|
|
272
|
+
// Reading `scrollTop` is a cheap (already-measured) lookup, and
|
|
273
|
+
// short-circuiting avoids forcing a layout when we'd write the
|
|
274
|
+
// same value — important under high-frequency re-renders
|
|
275
|
+
// (streaming AI output).
|
|
276
|
+
if (this.scrollContainer.scrollTop === target) {
|
|
277
|
+
return;
|
|
278
|
+
}
|
|
279
|
+
this.scrollContainer.scrollTop = target;
|
|
280
|
+
}
|
|
281
|
+
distanceFromNewestEdge(order) {
|
|
282
|
+
return order === 'oldest-on-top'
|
|
283
|
+
? this.scrollContainer.scrollHeight -
|
|
284
|
+
this.scrollContainer.scrollTop -
|
|
285
|
+
this.scrollContainer.clientHeight
|
|
286
|
+
: this.scrollContainer.scrollTop;
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
// The CSS property the typing-indicator container transitions.
|
|
291
|
+
// Mirrored from chat-list.scss `.typing-indicator-height-animation
|
|
292
|
+
// { transition: grid-template-rows ... }`. The runtime verifier below
|
|
293
|
+
// guards against the SCSS and the handler-side filter silently
|
|
294
|
+
// disagreeing.
|
|
295
|
+
const HEIGHT_ANIMATION_PROPERTY = 'grid-template-rows';
|
|
296
|
+
/**
|
|
297
|
+
* Returns a `transitionend` listener for the typing indicator's
|
|
298
|
+
* height transition. Filters by property name so unrelated
|
|
299
|
+
* transitions on the same element (e.g. opacity) don't trigger the
|
|
300
|
+
* callback.
|
|
301
|
+
* @param onHeightTransitionEnd
|
|
302
|
+
*/
|
|
303
|
+
function createHeightTransitionEndHandler(onHeightTransitionEnd) {
|
|
304
|
+
return (event) => {
|
|
305
|
+
if (event.propertyName !== HEIGHT_ANIMATION_PROPERTY) {
|
|
306
|
+
return;
|
|
307
|
+
}
|
|
308
|
+
onHeightTransitionEnd();
|
|
309
|
+
};
|
|
310
|
+
}
|
|
311
|
+
/**
|
|
312
|
+
* Verifies that the passed element actually transitions on the
|
|
313
|
+
* property the height-transition handler filters on. Surfaces SCSS
|
|
314
|
+
* drift loudly instead of silently breaking auto-scroll-on-indicator-
|
|
315
|
+
* appearance.
|
|
316
|
+
* @param element
|
|
317
|
+
*/
|
|
318
|
+
function verifyHeightAnimationProperty(element) {
|
|
319
|
+
if (!element) {
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
const transitionProperty = globalThis.getComputedStyle(element).transitionProperty;
|
|
323
|
+
if (!transitionProperty) {
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
const properties = new Set(transitionProperty.split(',').map((p) => p.trim()));
|
|
327
|
+
if (!properties.has('all') && !properties.has(HEIGHT_ANIMATION_PROPERTY)) {
|
|
328
|
+
console.warn(`[limebb-chat-list] Typing indicator is transitioning \`${transitionProperty}\` instead of \`${HEIGHT_ANIMATION_PROPERTY}\`. The auto-scroll on indicator appearance will not fire. Update the CSS or the handler so they match.`);
|
|
329
|
+
}
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
const chatListCss = () => `@charset "UTF-8";:host(limebb-chat-list){--limel-top-edge-fade-height:0.75rem;isolation:isolate;--limel-overflow-mask-vertical:linear-gradient( to bottom, transparent 0%, black calc(0% + var(--limel-top-edge-fade-height, 1rem)), black calc(100% - var(--limel-bottom-edge-fade-height, 1rem)), transparent 100% );-webkit-mask-image:var(--limel-overflow-mask-vertical);mask-image:var(--limel-overflow-mask-vertical);padding-top:var(--limel-top-edge-fade-height, 1rem);padding-bottom:var(--limel-bottom-edge-fade-height, 1rem);box-sizing:border-box;display:flex;flex-direction:column;gap:0.5rem;height:100%;width:100%;min-width:0;min-height:0;padding:var(--limel-top-edge-fade-height) 0.5rem;overflow:hidden auto}:host(limebb-chat-list.is-empty){padding:0}*{box-sizing:border-box}limel-spinner{align-self:center;justify-self:center;margin:auto}.date-group{isolation:isolate;display:flex;flex-direction:inherit;gap:0.5rem}.date-heading{position:sticky;z-index:1;top:0.25rem;display:flex;border-radius:9rem;padding:0.25rem 0.5rem;margin:0 auto;width:fit-content;font-size:0.75rem;line-height:1;color:rgb(var(--contrast-900));backdrop-filter:blur(0.5rem);-webkit-backdrop-filter:blur(0.5rem);transition:color 0.2s ease, border-color 0.4s ease}.date-heading:hover{color:rgb(var(--contrast-1000));border-color:rgb(var(--contrast-500))}.date-heading:hover:before{opacity:1}.date-heading:before{transition:opacity 0.2s ease;content:"";position:absolute;z-index:-1;inset:0;opacity:0.6;border-radius:inherit;background-color:rgb(var(--contrast-100))}.new-items-indicator{position:relative;isolation:isolate;display:flex;align-items:center;justify-content:flex-end;margin:0.25rem 0}.new-items-indicator hr{border:none;position:absolute;width:100%;height:1px;background-color:rgb(var(--color-red-lighter))}.new-items-indicator h3{z-index:1;padding:0 0.5rem;border-radius:1rem;margin:0 1rem;font-size:small;line-height:0.75rem;text-transform:lowercase;color:rgb(var(--color-red-default));background-color:rgb(var(--contrast-100))}.typing-indicator-height-animation{--limebb-chat-typing-opacity-transition-speed:0.1s;--limebb-chat-typing-opacity-transition-delay:0s;--limebb-chat-typing-grid-template-rows-transition-speed:0.3s;position:sticky;z-index:1;transition:grid-template-rows var(--limebb-chat-typing-grid-template-rows-transition-speed) ease;display:grid;grid-template-rows:0}.typing-indicator-height-animation div{transition:opacity var(--limebb-chat-typing-opacity-transition-speed) ease var(--limebb-chat-typing-opacity-transition-delay);overflow:hidden;opacity:0}:host(limebb-chat-list[order=oldest-on-top]) .typing-indicator-height-animation{bottom:0}:host(limebb-chat-list[order=newest-on-top]) .typing-indicator-height-animation{top:0}:host(limebb-chat-list[is-typing-indicator-visible]) .typing-indicator-height-animation{--limebb-chat-typing-opacity-transition-speed:0.4s;--limebb-chat-typing-opacity-transition-delay:0.3s;--limebb-chat-typing-grid-template-rows-transition-speed:0.46s;grid-template-rows:1.5rem}:host(limebb-chat-list[is-typing-indicator-visible]) .typing-indicator-height-animation div{opacity:1}.date-group limebb-chat-item{--limebb-promoted-action-bar-grid-template-rows:0fr}:host(limebb-chat-list[order=oldest-on-top]) .date-group:last-of-type limebb-chat-item:last-of-type{--limebb-promoted-action-bar-grid-template-rows:1fr}:host(limebb-chat-list[order=newest-on-top]) .date-group:first-of-type limebb-chat-item:first-of-type{--limebb-promoted-action-bar-grid-template-rows:1fr}`;
|
|
131
333
|
|
|
132
334
|
const ChatList = class {
|
|
133
335
|
constructor(hostRef) {
|
|
134
336
|
registerInstance(this, hostRef);
|
|
135
337
|
/**
|
|
136
338
|
* List of items to display in the feed.
|
|
137
|
-
* These items must be sorted by their `timestamp` in
|
|
339
|
+
* These items must be sorted by their `timestamp` in ascending order
|
|
340
|
+
* (oldest first, newest last). This matches the natural visual order
|
|
341
|
+
* for the default `oldest-on-top` layout, keeping DOM order aligned
|
|
342
|
+
* with visual order for copy/paste, screen readers, and tab order.
|
|
138
343
|
*
|
|
139
344
|
* See the [ChatListItem](#/type/ChatListItem/) type for the kinds of
|
|
140
345
|
* items that can appear in the list.
|
|
@@ -148,29 +353,56 @@ const ChatList = class {
|
|
|
148
353
|
*
|
|
149
354
|
* :::important
|
|
150
355
|
* Using this prop will _not_ automatically sort the chat items for you!
|
|
151
|
-
* You still need to pass the items in the correct order (
|
|
152
|
-
* This prop
|
|
356
|
+
* You still need to pass the items in the correct order (ascending order by timestamp — oldest first).
|
|
357
|
+
* This prop only affects the direction of the elements in the user interface,
|
|
153
358
|
* such as the location of the typing indicator or the scrollbars.
|
|
154
359
|
* :::
|
|
155
360
|
*/
|
|
156
361
|
this.order = 'oldest-on-top';
|
|
157
362
|
this.processedItems = [];
|
|
363
|
+
this.handleHeightTransitionEnd = createHeightTransitionEndHandler(() => { var _a; return (_a = this.scrollAnchor) === null || _a === void 0 ? void 0 : _a.repinIfSticky(); });
|
|
158
364
|
}
|
|
159
365
|
handleItemsChange() {
|
|
160
366
|
let lastVisited = null;
|
|
161
367
|
if (this.lastVisitedTimestamp) {
|
|
162
368
|
lastVisited = parseToUTCDate(this.lastVisitedTimestamp);
|
|
163
369
|
}
|
|
164
|
-
|
|
370
|
+
const processed = processChatItems(this.items, this.dateTimeFormatter, lastVisited);
|
|
371
|
+
this.processedItems =
|
|
372
|
+
this.order === 'newest-on-top'
|
|
373
|
+
? reverseProcessedItems(processed)
|
|
374
|
+
: processed;
|
|
165
375
|
}
|
|
166
376
|
componentWillLoad() {
|
|
167
377
|
this.handleItemsChange();
|
|
378
|
+
this.scrollAnchor = new ScrollAnchor(this.host, () => this.order, this.order);
|
|
379
|
+
}
|
|
380
|
+
componentDidLoad() {
|
|
381
|
+
var _a;
|
|
382
|
+
verifyHeightAnimationProperty((_a = this.host.shadowRoot) === null || _a === void 0 ? void 0 : _a.querySelector('.typing-indicator-height-animation'));
|
|
383
|
+
}
|
|
384
|
+
componentWillRender() {
|
|
385
|
+
if (this.items.length === 0) {
|
|
386
|
+
// Nothing to measure or scroll against. `isSticky` retains
|
|
387
|
+
// its last value (default `true`), so the first non-empty
|
|
388
|
+
// render still pins correctly.
|
|
389
|
+
return;
|
|
390
|
+
}
|
|
391
|
+
this.scrollAnchor.beforeRender();
|
|
392
|
+
}
|
|
393
|
+
componentDidRender() {
|
|
394
|
+
if (this.items.length === 0) {
|
|
395
|
+
return;
|
|
396
|
+
}
|
|
397
|
+
this.scrollAnchor.afterRender();
|
|
168
398
|
}
|
|
169
399
|
render() {
|
|
170
|
-
return (h(Host, { key: '
|
|
400
|
+
return (h(Host, { key: '002369dc1f47978696b4eb8ac7189f794568b0b4', class: {
|
|
171
401
|
'is-empty': this.items.length === 0 &&
|
|
172
402
|
!this.isTypingIndicatorVisible,
|
|
173
|
-
}, "aria-busy": this.isBusy(), role: "log" }, this.renderSpinner(),
|
|
403
|
+
}, "aria-busy": this.isBusy(), role: "log" }, this.renderSpinner(), this.order === 'newest-on-top' &&
|
|
404
|
+
this.renderTypingIndicatorBlock(), this.renderChatItems(), this.order === 'oldest-on-top' &&
|
|
405
|
+
this.renderTypingIndicatorBlock()));
|
|
174
406
|
}
|
|
175
407
|
renderSpinner() {
|
|
176
408
|
if (!this.loading) {
|
|
@@ -178,6 +410,14 @@ const ChatList = class {
|
|
|
178
410
|
}
|
|
179
411
|
return h("limel-spinner", null);
|
|
180
412
|
}
|
|
413
|
+
renderTypingIndicatorBlock() {
|
|
414
|
+
// The indicator's grid-template-rows transition grows the
|
|
415
|
+
// container over ~0.46s. `componentDidRender` fires before the
|
|
416
|
+
// transition starts, so `scrollHeight` at that moment doesn't
|
|
417
|
+
// include the final height. `handleHeightTransitionEnd` re-pins
|
|
418
|
+
// once the transition lands.
|
|
419
|
+
return (h("div", { class: "typing-indicator-height-animation", onTransitionEnd: this.handleHeightTransitionEnd }, h("div", null, this.renderTypingIndicator())));
|
|
420
|
+
}
|
|
181
421
|
renderTypingIndicator() {
|
|
182
422
|
if (!this.isTypingIndicatorVisible) {
|
|
183
423
|
return;
|
|
@@ -193,33 +433,54 @@ const ChatList = class {
|
|
|
193
433
|
case 'newItemIndicator': {
|
|
194
434
|
return this.renderIndicator();
|
|
195
435
|
}
|
|
196
|
-
|
|
436
|
+
case 'chat':
|
|
437
|
+
case 'iconList': {
|
|
438
|
+
// `insertDateGroups` wraps every `chat` / `iconList`
|
|
439
|
+
// in a `group`, so these variants shouldn't appear
|
|
440
|
+
// at top level. If the processor pipeline is ever
|
|
441
|
+
// reordered, render nothing rather than double-
|
|
442
|
+
// render once the wrapping group includes them.
|
|
197
443
|
return null;
|
|
198
444
|
}
|
|
445
|
+
default: {
|
|
446
|
+
return assertNever(item);
|
|
447
|
+
}
|
|
199
448
|
}
|
|
200
449
|
});
|
|
201
450
|
}
|
|
202
451
|
renderGroup(group) {
|
|
203
452
|
const chatItems = group.items.map((item) => {
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
453
|
+
switch (item.type) {
|
|
454
|
+
case 'chat': {
|
|
455
|
+
return this.renderChatItem(item.item);
|
|
456
|
+
}
|
|
457
|
+
case 'iconList': {
|
|
458
|
+
return this.renderIconList(item.item);
|
|
459
|
+
}
|
|
460
|
+
case 'newItemIndicator': {
|
|
461
|
+
return this.renderIndicator();
|
|
462
|
+
}
|
|
463
|
+
case 'group': {
|
|
464
|
+
// Date groups don't nest. A compile-time `never`
|
|
465
|
+
// here would require a separate nested-item type;
|
|
466
|
+
// this runtime null return is the pragmatic
|
|
467
|
+
// middle ground.
|
|
468
|
+
return null;
|
|
469
|
+
}
|
|
470
|
+
default: {
|
|
471
|
+
return assertNever(item);
|
|
472
|
+
}
|
|
212
473
|
}
|
|
213
474
|
});
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
475
|
+
// Key the section by the group's heading (unique per date, and
|
|
476
|
+
// stable across item additions). Must not vary with group
|
|
477
|
+
// content: if it did, appending a new message would change the
|
|
478
|
+
// key and cause Stencil to remount the whole section, briefly
|
|
479
|
+
// collapsing scrollHeight and scrolling the list to the top
|
|
480
|
+
// before `componentDidRender` scrolls it back.
|
|
481
|
+
const sectionKey = 'date-group-' + group.heading;
|
|
218
482
|
const headingId = `heading-${sectionKey}`.replaceAll(/[^a-zA-Z0-9_-]/g, '_');
|
|
219
483
|
const dateHeading = (h("a", { id: headingId, class: "date-heading", role: "heading", "aria-level": 2 }, group.heading));
|
|
220
|
-
if (this.order === 'oldest-on-top') {
|
|
221
|
-
return (h("section", { class: "date-group", key: sectionKey, "aria-labelledby": headingId }, chatItems, dateHeading));
|
|
222
|
-
}
|
|
223
484
|
return (h("section", { class: "date-group", key: sectionKey, "aria-labelledby": headingId }, dateHeading, chatItems));
|
|
224
485
|
}
|
|
225
486
|
renderChatItem(item) {
|
|
@@ -240,9 +501,13 @@ const ChatList = class {
|
|
|
240
501
|
get translator() {
|
|
241
502
|
return this.platform.get(n.Translate);
|
|
242
503
|
}
|
|
504
|
+
get host() { return getElement(this); }
|
|
243
505
|
static get watchers() { return {
|
|
244
506
|
"items": [{
|
|
245
507
|
"handleItemsChange": 0
|
|
508
|
+
}],
|
|
509
|
+
"order": [{
|
|
510
|
+
"handleItemsChange": 0
|
|
246
511
|
}]
|
|
247
512
|
}; }
|
|
248
513
|
};
|
|
@@ -252,6 +517,9 @@ function parseToUTCDate(date) {
|
|
|
252
517
|
}
|
|
253
518
|
return new Date(date); // This will automatically be UTC
|
|
254
519
|
}
|
|
520
|
+
function assertNever(value) {
|
|
521
|
+
throw new Error(`Unexpected value in exhaustive switch: ${JSON.stringify(value)}`);
|
|
522
|
+
}
|
|
255
523
|
ChatList.style = chatListCss();
|
|
256
524
|
|
|
257
525
|
export { ChatList as limebb_chat_list };
|
|
@@ -64,8 +64,8 @@ const ComposerToolbar = class {
|
|
|
64
64
|
}
|
|
65
65
|
render() {
|
|
66
66
|
return [
|
|
67
|
-
h("div", { key: '
|
|
68
|
-
h("slot", { key: '
|
|
67
|
+
h("div", { key: '6034b2945edfd9b613f606f8bb4fb0db81c1390f', class: "actions" }, h("slot", { key: '82b9bc14d80aedd3320af70bc63d3a908db6a7b2', name: "leading" }), this.renderFileInput(), this.renderTriggerActions(), h("slot", { key: '338fc1b7c7ec3f7dfedb123b7e09dd05f75fc45c', name: "trailing" })),
|
|
68
|
+
h("slot", { key: '57b277b772cbaf702e619ecbd6ff9032718b87b7', name: "primary-action" }),
|
|
69
69
|
];
|
|
70
70
|
}
|
|
71
71
|
get translator() {
|
|
@@ -1968,7 +1968,7 @@ const CurrencyPicker = class {
|
|
|
1968
1968
|
};
|
|
1969
1969
|
}
|
|
1970
1970
|
render() {
|
|
1971
|
-
return (h("limel-picker", { key: '
|
|
1971
|
+
return (h("limel-picker", { key: '12d166b930a2864eefbb16c4d66706dd02b54112', label: this.label || this.defaultLabel, value: this.createListItem(this.value), helperText: this.helperText, onChange: this.handleChange, badgeIcons: false, disabled: this.disabled, required: this.required, readonly: this.readonly, invalid: this.readonly, searcher: this.search }));
|
|
1972
1972
|
}
|
|
1973
1973
|
getCurrencyName(code) {
|
|
1974
1974
|
var _a;
|
|
@@ -16,7 +16,7 @@ const DashboardComponent = class {
|
|
|
16
16
|
};
|
|
17
17
|
}
|
|
18
18
|
render() {
|
|
19
|
-
return [this.renderHeader(), h("slot", { key: '
|
|
19
|
+
return [this.renderHeader(), h("slot", { key: 'f5202c8c5d6ceb3e01420c6045ecb5589fed915a', name: "content" })];
|
|
20
20
|
}
|
|
21
21
|
};
|
|
22
22
|
DashboardComponent.style = dashboardWidgetCss();
|
|
@@ -73,7 +73,7 @@ const DatePicker = class {
|
|
|
73
73
|
if (this.value) {
|
|
74
74
|
this.shouldEmitValueAsString = typeof this.value === 'string';
|
|
75
75
|
}
|
|
76
|
-
return (h("limel-date-picker", { key: '
|
|
76
|
+
return (h("limel-date-picker", { key: 'f3276cfc57128c566248a97e5fea9a3dcc107888', disabled: this.disabled, readonly: this.readonly, invalid: this.invalid, label: this.label, placeholder: this.placeholder, helperText: this.helperText, required: this.required, value: this.parseDateValue(), type: this.type, language: this.language, formatter: this.formatter, onChange: this.handleChange }));
|
|
77
77
|
}
|
|
78
78
|
parseDateValue() {
|
|
79
79
|
const value = this.value;
|
|
@@ -21,7 +21,7 @@ const DateRange = class {
|
|
|
21
21
|
this.originalEndTime = this.endTime;
|
|
22
22
|
}
|
|
23
23
|
render() {
|
|
24
|
-
return (h("div", { key: '
|
|
24
|
+
return (h("div", { key: 'e00abfd31fcae2a4279ae2194696b5cffb76dd79', class: "date-pickers" }, this.renderStartDatePicker(), this.renderEndDatePicker()));
|
|
25
25
|
}
|
|
26
26
|
renderStartDatePicker() {
|
|
27
27
|
if (!this.originalStartTime) {
|
|
@@ -345,7 +345,7 @@ const DocumentChips = class {
|
|
|
345
345
|
this.revokeAllBlobUrls();
|
|
346
346
|
}
|
|
347
347
|
render() {
|
|
348
|
-
return (h(Host, { key: '
|
|
348
|
+
return (h(Host, { key: '93d00770917014b1de6e380db6b102859210fded', role: "list", "aria-label": this.accessibleLabel }, this.files.map((file) => this.renderFile(file))));
|
|
349
349
|
}
|
|
350
350
|
renderFile(file) {
|
|
351
351
|
const isReady = !file.uploadState || file.uploadState === 'done';
|
|
@@ -114,10 +114,10 @@ const DocumentItemComponent = class {
|
|
|
114
114
|
render() {
|
|
115
115
|
const isUnavailable = this.isUnavailable();
|
|
116
116
|
const image = this.getImage();
|
|
117
|
-
return (h(Host, { key: '
|
|
117
|
+
return (h(Host, { key: '97fe779b6706627e3abb9729b6ea2933d5ccafb4', id: String(this.item.file.id), class: {
|
|
118
118
|
'has-image': !!image,
|
|
119
119
|
'has-error': !!this.item.hasError,
|
|
120
|
-
}, role: this.type === 'radio' ? 'radio' : 'checkbox', "aria-checked": this.item.selected ? 'true' : 'false', "aria-disabled": isUnavailable ? 'true' : 'false', tabIndex: isUnavailable ? -1 : 0 }, h("limel-card", { key: '
|
|
120
|
+
}, role: this.type === 'radio' ? 'radio' : 'checkbox', "aria-checked": this.item.selected ? 'true' : 'false', "aria-disabled": isUnavailable ? 'true' : 'false', tabIndex: isUnavailable ? -1 : 0 }, h("limel-card", { key: 'c897ca8a474b6b2e2f9e722507dd4b038ece058b', image: image, clickable: isUnavailable ? false : true, onClick: this.handleDocumentItemClick, onKeyDown: this.handleKeyDown }, h("div", { key: 'cc75606770a2e0edeab4111e6e04608f6d841b6e', slot: "component" }, this.renderFileSize(), this.renderBooleanInput())), this.renderHelp()));
|
|
121
121
|
}
|
|
122
122
|
renderBooleanInput() {
|
|
123
123
|
const id = this.getControlId();
|
|
@@ -66,7 +66,7 @@ const DocumentPicker = class {
|
|
|
66
66
|
this.labelId = createRandomString();
|
|
67
67
|
}
|
|
68
68
|
render() {
|
|
69
|
-
return (h(Host, { key: '
|
|
69
|
+
return (h(Host, { key: 'd3d8d080de7dd9ceec2cbfa7382e9ac669c2d35b' }, h("limel-notched-outline", { key: '978b42774a036eccb8f347231a98b495e7b520a0', labelId: this.labelId, label: this.label, required: this.required, invalid: this.invalid, hasFloatingLabel: true }, h("limel-masonry-layout", { key: '5aa49ca5764d4b25dae50754ab77498beeaf016c', slot: "content", role: this.type === 'radio' ? 'radiogroup' : 'group', "aria-labelledby": this.label ? this.labelId : undefined, "aria-describedby": this.helperText ? this.helperTextId : undefined }, this.renderItems())), this.renderHelperLine()));
|
|
70
70
|
}
|
|
71
71
|
renderItems() {
|
|
72
72
|
return this.items.map((item) => (h("limebb-document-item", { platform: this.platform, context: this.context, item: item, key: item.file.id, type: this.type, onInteract: this.handleItemInteract })));
|
|
@@ -7,7 +7,7 @@ const FeedItemThumbnailFileInfo = class {
|
|
|
7
7
|
registerInstance(this, hostRef);
|
|
8
8
|
}
|
|
9
9
|
render() {
|
|
10
|
-
return h("span", { key: '
|
|
10
|
+
return h("span", { key: 'ed2f52dbd7899d308078d5cee6e9e7bc3e6c0f50' }, this.description);
|
|
11
11
|
}
|
|
12
12
|
};
|
|
13
13
|
FeedItemThumbnailFileInfo.style = feedItemThumbnailFileInfoCss();
|