@convokitapp/vue-ui 0.4.1 → 0.6.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 +73 -0
- package/PARITY.md +35 -6
- package/README.md +107 -1
- package/dist/index.cjs +445 -83
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +46 -1
- package/dist/index.css.map +1 -1
- package/dist/index.d.cts +142 -17
- package/dist/index.d.ts +142 -17
- package/dist/index.js +443 -81
- package/dist/index.js.map +1 -1
- package/package.json +3 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,78 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.6.0
|
|
4
|
+
|
|
5
|
+
- Inbox previews and unread counts. SDK-backed lists page `listInbox` by
|
|
6
|
+
opaque cursor in activity order (newest surviving message first, empty rooms
|
|
7
|
+
by creation time); `hasMore` follows the server's `nextCursor`. Pages merge
|
|
8
|
+
by conversation ID with the later entry winning, re-ordered by
|
|
9
|
+
`(activityAt desc, id desc)` unless `filter.comparator` is set. Page checks:
|
|
10
|
+
at most `limit` entries, non-blank unique IDs, and a cursor that advances
|
|
11
|
+
(`Inbox pagination did not advance`); the offset-era "full page with no new
|
|
12
|
+
IDs" rule applies to the legacy path only. `mergeInboxEntries` is exported.
|
|
13
|
+
- State: `summaries` (`ReadonlyMap<string, InboxSummary>`) and `currentUserId`
|
|
14
|
+
on `useConversationList` / `ConversationListState`; `''` and empty without a
|
|
15
|
+
session, on the legacy path and after disposal.
|
|
16
|
+
- Default rows: preview line (`You: …`, `<name>: …` in groups, media
|
|
17
|
+
placeholders `Photo` / file name or `File` / `Location` / `Contact`),
|
|
18
|
+
activity time, unread badge (`99+` above 99 or when capped; accessible name
|
|
19
|
+
`<count> unread`, `99+ unread` when capped; label hidden from the
|
|
20
|
+
accessibility tree), bold title while unread. New theme token `badge`
|
|
21
|
+
(`--ckui-badge`, default primary). `#conversation-item` slot props gain
|
|
22
|
+
`summary` and `currentUserId`; `ConversationListView` accepts `summaries`
|
|
23
|
+
and `currentUserId`. Inline `Retry` requests the next page when `hasMore`
|
|
24
|
+
and `onLoadMore` are bound (bypassing the duplicate-request guard), else
|
|
25
|
+
refreshes; it renders only when a callback exists.
|
|
26
|
+
- Live updates: `inbox_activity` is throttled by `activityRefreshWindowMs`
|
|
27
|
+
(default 500, 0 = immediate; max-wait window, generation-guarded, cleared on
|
|
28
|
+
dispose/session end, `unref`'d where available); `inbox_changed` refreshes
|
|
29
|
+
immediately and drops a pending window. `refresh()` walks from the head with
|
|
30
|
+
`limit = min(100, target − consumed)`, `target = max(pageSize, loaded)`,
|
|
31
|
+
continues past fully hidden pages and never publishes an empty list with
|
|
32
|
+
`hasMore` while pages remain; rows, summaries, cursor and `hasMore` swap
|
|
33
|
+
atomically.
|
|
34
|
+
- Adapter: optional `listInbox?({ limit, cursor, archived })` and
|
|
35
|
+
`onInboxActivity?(handler, onError?)`; the default adapter implements both.
|
|
36
|
+
Adapters without `listInbox` and custom `pageLoader`s keep the 0.5 offset
|
|
37
|
+
path with empty summaries. A 404 from `listInbox` falls back to that path for
|
|
38
|
+
the store's life without evicting rows (warned once); a legacy 404 still
|
|
39
|
+
evicts, 401/403 evict, 400 keeps rows and reports.
|
|
40
|
+
- Requires core SDK 0.6.x (`listInbox`, `InboxPage` / `InboxEntry` /
|
|
41
|
+
`InboxSummary`, `realtime.onInboxActivity`) and the coordinated backend.
|
|
42
|
+
|
|
43
|
+
## 0.5.0
|
|
44
|
+
|
|
45
|
+
- Precise read positions. Receipts resolve per user from a monotonic read-through
|
|
46
|
+
position `(createdAt, id)` when the server provides one, and fall back to the
|
|
47
|
+
acknowledgement time only for legacy participants without a position. A read
|
|
48
|
+
request that arrives late no longer marks messages that were rendered after it
|
|
49
|
+
as read. The state exposes `readPositionByUserId` beside `readAtByUserId`;
|
|
50
|
+
`readerIdsFor`, `defaultReadersResolver`, `MessageListView` and
|
|
51
|
+
`ConversationView` accept both (`readAtByUserId` alone still works).
|
|
52
|
+
- Targeted acknowledgements. Automatic and explicit reads name the newest
|
|
53
|
+
rendered, non-pending message (`throughMessageId`); nothing is sent while
|
|
54
|
+
nothing is rendered. A withheld media-only row is acknowledged once its
|
|
55
|
+
hydration renders it. One request is in flight at a time, a follow-up is
|
|
56
|
+
resolved at send time, and targets at or before the accepted one are skipped.
|
|
57
|
+
A target the server does not know (`MESSAGE_NOT_FOUND`) is skipped and the
|
|
58
|
+
next newest row is acknowledged once; membership failures still surface as
|
|
59
|
+
errors.
|
|
60
|
+
- Visibility gating. Automatic acknowledgements wait while the document is
|
|
61
|
+
hidden and resume when it becomes visible; the SDK-backed `Conversation`
|
|
62
|
+
wires `document.visibilityState` and `visibilitychange`, and controllers gain
|
|
63
|
+
`setVisible(visible)`. Unknown, prerender and server environments count as
|
|
64
|
+
visible. `markReadOnLoad` / `markReadOnReceive` keep their meaning; with both
|
|
65
|
+
off no request is ever sent, including on visibility changes.
|
|
66
|
+
- 0.5.0 adapter change: `ConvoKitUiClient.markConversationRead(conversationId,
|
|
67
|
+
options?)` receives `{ throughMessageId }`. Custom adapters must forward it
|
|
68
|
+
and report an unknown target with `code: 'MESSAGE_NOT_FOUND'` (or a 404
|
|
69
|
+
without a code). One-argument implementations still type-check but would
|
|
70
|
+
acknowledge the server's newest message instead of the rendered one.
|
|
71
|
+
- Requires core SDK 0.5.x (`Participant.readPosition`, `ReadEvent.readPosition`,
|
|
72
|
+
`markConversationRead` target) and the coordinated backend. Mixed fleet:
|
|
73
|
+
precise receipts need both the sender's and the reader's clients on 0.5;
|
|
74
|
+
0.4 readers keep timestamp semantics and keep parsing the additive payload.
|
|
75
|
+
|
|
3
76
|
## 0.4.1
|
|
4
77
|
|
|
5
78
|
- Describe a confirmed outgoing message without readers as `Sent` instead of
|
package/PARITY.md
CHANGED
|
@@ -14,10 +14,20 @@ while using Vue-native composition patterns.
|
|
|
14
14
|
| Conversation state | Controller | `useConversation` | `useConversation` |
|
|
15
15
|
| Conversation-list state | Controller | `useConversationList` | `useConversationList` |
|
|
16
16
|
| Inbox offset pagination and de-duplication | Yes | Yes | Yes |
|
|
17
|
+
| Inbox cursor pagination, activity order, later-entry merge | Yes | Yes | Yes |
|
|
18
|
+
| Inbox summaries and viewer in list state (`summaries`, `currentUserId`) | Yes | Yes | Yes |
|
|
19
|
+
| Preview / time / unread badge rows (`badge` token) | `badgeColor` | `--ckui-badge` | `--ckui-badge` |
|
|
20
|
+
| Row replacements receive `summary` / `currentUserId` | `rowBuilder` | Render props | `#conversation-item` slot |
|
|
21
|
+
| `inbox_activity` throttle (`activityRefreshWindowMs`) | Yes | Yes | Yes |
|
|
22
|
+
| Adapter `listInbox` / `onInboxActivity` | Required | Optional | Optional |
|
|
23
|
+
| Inbox 404 fallback to the offset path | Yes | Yes | Yes |
|
|
17
24
|
| Search, archived, participant, predicate, sort filters | Yes | Yes | Yes |
|
|
18
25
|
| Realtime messages, typing, reads | Yes | Yes | Yes |
|
|
19
26
|
| Pending state without provisional timestamps or receipts | Yes | Yes | Yes |
|
|
20
27
|
| Read markers and reader resolution | Yes | Yes | Yes |
|
|
28
|
+
| Read positions (`readPositionByUserId`, `lastReadAt` fallback) | Yes | Yes | Yes |
|
|
29
|
+
| Targeted acknowledgements (`throughMessageId`, newest rendered row) | Yes | Yes | Yes |
|
|
30
|
+
| Visibility-gated auto-read | `WidgetsBindingObserver` | `visibilitychange` | `visibilitychange` |
|
|
21
31
|
| Mark read on load/receive | Yes | Yes | Yes |
|
|
22
32
|
| Typing idle timeout | Yes | Yes | Yes |
|
|
23
33
|
| Image, file, location, contact rendering | Yes | Yes | Yes |
|
|
@@ -32,10 +42,29 @@ Vue also exposes controlled/uncontrolled composer text through `v-model`,
|
|
|
32
42
|
per-part `classNames` and `styles`, `unstyled` mode, native root attributes,
|
|
33
43
|
image loading policy, time formatting, scroll behavior controls, callback props,
|
|
34
44
|
and exposed composable controllers.
|
|
35
|
-
##
|
|
45
|
+
## Read-position parity (0.5.0)
|
|
36
46
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
47
|
+
Every UI applies the same receipt rule per user: a read position wins when
|
|
48
|
+
present (`covers` by `(createdAt, id)`), otherwise `lastReadAt` is compared
|
|
49
|
+
with `createdAt`. Acknowledgements target the newest rendered non-pending
|
|
50
|
+
message, coalesce to one request in flight, skip targets at or before the last
|
|
51
|
+
accepted one, re-issue once on a `MESSAGE_NOT_FOUND` miss, and wait while the
|
|
52
|
+
platform reports the view as hidden. The adapter interface gained the optional
|
|
53
|
+
target in all libraries (`markConversationRead(conversationId, options?)` here).
|
|
54
|
+
The parity script checks API presence only; the store, rendered-view and
|
|
55
|
+
actual-SDK protocol tests verify behavior.
|
|
56
|
+
|
|
57
|
+
## Inbox parity (0.6.0)
|
|
58
|
+
|
|
59
|
+
Every UI pages the inbox by the server cursor, keeps the server's order within a
|
|
60
|
+
page, merges pages by conversation ID with the later entry winning, and
|
|
61
|
+
re-orders merged rows by `(activityAt desc, id desc)` unless a comparator is
|
|
62
|
+
set. Rows show the same preview (`You:` for the viewer, `<name>:` for a named
|
|
63
|
+
member of a group of more than two, `Photo` / file name or `File` /
|
|
64
|
+
`Location` / `Contact` for media-only messages), the activity time, and an
|
|
65
|
+
unread badge (`99+` above 99 or when capped; accessible name
|
|
66
|
+
`<count> unread`). `inbox_activity` signals are coalesced by a max-wait window
|
|
67
|
+
(`activityRefreshWindowMs`, default 500 ms); `inbox_changed` stays immediate.
|
|
68
|
+
A 404 from the inbox route falls back to the offset path for the store's life
|
|
69
|
+
without evicting rows. The parity script checks API presence only; the store,
|
|
70
|
+
rendered-view and actual-SDK protocol tests verify behavior.
|
package/README.md
CHANGED
|
@@ -11,6 +11,105 @@ React package: system typography, separated rows, subtle borders, compact
|
|
|
11
11
|
actions, and restrained radii. It remains framework-CSS independent and does
|
|
12
12
|
not require Tailwind in the host application.
|
|
13
13
|
|
|
14
|
+
## 0.6.0 inbox previews and unread counts
|
|
15
|
+
|
|
16
|
+
This release requires JavaScript SDK 0.6.x (`listInbox`, `onInboxActivity`)
|
|
17
|
+
and the coordinated backend (`GET /api/v1/inbox`, the `inbox_activity` event).
|
|
18
|
+
|
|
19
|
+
- SDK-backed lists arrive in inbox order: the newest surviving message time
|
|
20
|
+
first (an empty room sorts by its creation time), paged by an opaque server
|
|
21
|
+
cursor instead of an offset. The store keeps the server's order within a page
|
|
22
|
+
and, whenever pages are combined (load more, refresh), merges by conversation
|
|
23
|
+
ID with the later entry winning and re-orders by `(activityAt desc, id desc)`.
|
|
24
|
+
Setting `filter.comparator` replaces that order; `updatedAt` is never an
|
|
25
|
+
ordering input. `mergeInboxEntries(current, incoming)` is exported and applies
|
|
26
|
+
the same rule.
|
|
27
|
+
- State gains `summaries` (a `ReadonlyMap<string, InboxSummary>` by conversation
|
|
28
|
+
ID: `latestMessage`, `unreadCount`, `unreadCountCapped`, `readPosition`,
|
|
29
|
+
`lastReadAt`, `activityAt`) and `currentUserId` (the bound session's user;
|
|
30
|
+
`''` without a session, on the legacy path and after disposal). `conversations`,
|
|
31
|
+
filters, comparators, custom offset `pageLoader`s and the `#conversation-item`
|
|
32
|
+
slot signature are unchanged.
|
|
33
|
+
- Default rows show a one-line preview instead of the participants line when a
|
|
34
|
+
summary carries a non-empty latest message: `You: …` for the viewer's own
|
|
35
|
+
message (DMs included), `<name>: …` for a named member of a group of more
|
|
36
|
+
than two, otherwise the body alone; media-only messages read `Photo`,
|
|
37
|
+
the file name or `File`, `Location`, `Contact`. Rows show the activity time
|
|
38
|
+
in the device zone and an unread badge (`5`, `99+` above 99 or when the
|
|
39
|
+
server capped the count) with the accessible name `<count> unread`
|
|
40
|
+
(`99+ unread` when capped); the title is bold while unread. The badge uses
|
|
41
|
+
the new theme token `badge` (`--ckui-badge`, defaults to the primary color)
|
|
42
|
+
with `outgoingText` as its label color.
|
|
43
|
+
- `#conversation-item` slot props gain `summary` and `currentUserId` (present
|
|
44
|
+
when known); existing slots keep working. `ConversationListView` accepts
|
|
45
|
+
`summaries` and `currentUserId` for controlled use. The inline error's
|
|
46
|
+
`Retry` requests the next page when `hasMore` and `onLoadMore` are bound
|
|
47
|
+
(past the view's duplicate-request guard), otherwise it refreshes; it
|
|
48
|
+
renders only when one of those callbacks exists.
|
|
49
|
+
- Live updates: `inbox_changed` still refreshes immediately; the new
|
|
50
|
+
`inbox_activity` signal (message inserts/edits and read-position advances,
|
|
51
|
+
fanned out to every client of the app) is throttled by
|
|
52
|
+
`activityRefreshWindowMs` (default 500 ms, 0 = immediate) with max-wait
|
|
53
|
+
semantics: the first signal opens a window, later signals wait for it, and one
|
|
54
|
+
refresh runs when it closes. An `inbox_changed` during the window refreshes
|
|
55
|
+
at once and drops the timer. `refresh()`, topic-error reconciliation and the
|
|
56
|
+
rejoin replay stay immediate. A refresh re-walks from the head with
|
|
57
|
+
`limit = min(100, target − consumed)` where `target = max(pageSize, loaded)`,
|
|
58
|
+
continues past pages the local filter hides, and swaps rows, summaries,
|
|
59
|
+
cursor and `hasMore` atomically; it never publishes an empty list with
|
|
60
|
+
`hasMore` while more pages exist. Rooms are open with `useConversation` as
|
|
61
|
+
before; room stores ignore `inbox_activity`.
|
|
62
|
+
- Adapter additions: `ConvoKitUiClient.listInbox?({ limit, cursor, archived })`
|
|
63
|
+
and `onInboxActivity?(handler, onError?)` are optional. The default adapter
|
|
64
|
+
implements both; custom adapters without `listInbox`, and custom `pageLoader`s,
|
|
65
|
+
keep the 0.5 offset path with empty `summaries` and no activity subscription.
|
|
66
|
+
A 404 from `listInbox` (route absent on a rolled-back backend) switches the
|
|
67
|
+
store to that path for the rest of its life without evicting rows (a warning
|
|
68
|
+
is logged once); a 404 from `getConversations` still evicts, 401/403 from
|
|
69
|
+
either endpoint evict, and 400 keeps rows and reports the error.
|
|
70
|
+
|
|
71
|
+
## 0.5.0 precise read positions
|
|
72
|
+
|
|
73
|
+
This release requires JavaScript SDK 0.5.x and the coordinated backend.
|
|
74
|
+
|
|
75
|
+
- Read receipts resolve per user from a monotonic read-through position, the
|
|
76
|
+
`(createdAt, id)` of a concrete message the server resolved, and fall back to
|
|
77
|
+
the acknowledgement time only for legacy participants without a position. A
|
|
78
|
+
read request that arrives late no longer marks messages rendered after it as
|
|
79
|
+
read. `useConversation` and `Conversation` expose `readPositionByUserId`
|
|
80
|
+
beside `readAtByUserId`; both are seeded from participants and advanced by
|
|
81
|
+
server read events only, never from the device clock.
|
|
82
|
+
- Acknowledgements name the newest rendered, non-pending message
|
|
83
|
+
(`throughMessageId`). Nothing is sent while nothing is rendered, and a
|
|
84
|
+
media-only row is acknowledged only once its hydration renders it. One
|
|
85
|
+
request is in flight at a time; a follow-up is resolved at send time and
|
|
86
|
+
skipped when the newest row is already acknowledged. A target the server
|
|
87
|
+
does not know (`MESSAGE_NOT_FOUND`, for example deleted meanwhile) is
|
|
88
|
+
skipped and the next newest row is acknowledged once. Membership failures
|
|
89
|
+
still surface as errors.
|
|
90
|
+
- Automatic acknowledgements wait while the document is hidden and resume when
|
|
91
|
+
it becomes visible. The SDK-backed `Conversation` follows
|
|
92
|
+
`document.visibilityState` and `visibilitychange`; controllers gain
|
|
93
|
+
`setVisible(visible)` for host-driven surfaces (tabs, drawers, background
|
|
94
|
+
routes). Unknown, prerender and server environments count as visible.
|
|
95
|
+
`markReadOnLoad` and `markReadOnReceive` keep their meaning; with both off,
|
|
96
|
+
no request is ever sent, including on visibility changes. `markRead()` is
|
|
97
|
+
the host's decision and is not gated.
|
|
98
|
+
- Controlled views accept `readPositionByUserId` next to `readAtByUserId`;
|
|
99
|
+
`readerIdsFor(message, readAtByUserId, readPositionByUserId?)` and
|
|
100
|
+
`defaultReadersResolver` apply the unified rule. Custom `#message` and
|
|
101
|
+
`#read-receipt` slots and `readersResolver` receive the same reader IDs.
|
|
102
|
+
- Adapter change: `ConvoKitUiClient.markConversationRead(conversationId,
|
|
103
|
+
options?)` receives `{ throughMessageId }`. Custom adapters must forward it
|
|
104
|
+
to the core SDK (or their backend) and report an unknown target with
|
|
105
|
+
`code: 'MESSAGE_NOT_FOUND'` (or a 404 without a code). One-argument
|
|
106
|
+
implementations still type-check but acknowledge the server's newest message
|
|
107
|
+
instead of the rendered one.
|
|
108
|
+
- Mixed fleet: precise receipts need both the sender's and the reader's
|
|
109
|
+
clients on 0.5. 0.4 readers keep timestamp semantics and keep parsing the
|
|
110
|
+
additive payload; the dashboard shows both the read-through and the last
|
|
111
|
+
acknowledgement time.
|
|
112
|
+
|
|
14
113
|
## 0.4.0 live inbox, sending and recovery
|
|
15
114
|
|
|
16
115
|
This release requires JavaScript SDK 0.4.x and the coordinated backend. The core
|
|
@@ -45,6 +144,7 @@ membership changes; no additional customer configuration is needed.
|
|
|
45
144
|
- Read receipts use persisted participant positions and server read events,
|
|
46
145
|
monotonically. A successful mark-read request does not fabricate a timestamp
|
|
47
146
|
from the device clock. Remote typing expires and clears on disconnect.
|
|
147
|
+
(0.5.0 replaces the timestamp comparison with read positions; see above.)
|
|
48
148
|
- Pending sends are bound to their original room/session. Reconciliation uses
|
|
49
149
|
the exact clientMessageId, sender and room, never identical text or file count.
|
|
50
150
|
A matching live/history row replaces its pending bubble immediately, even
|
|
@@ -148,6 +248,11 @@ Available slots include `conversation-item`, `separator`, `header`, `message`,
|
|
|
148
248
|
Use `useConversationList` and `useConversation` when you want ConvoKit's
|
|
149
249
|
pagination, de-duplication, realtime, typing, and read state without the
|
|
150
250
|
default UI. Both return readonly Vue refs plus actions and a `dispose()` method.
|
|
251
|
+
`useConversationList` also exposes `summaries` and `currentUserId` and accepts
|
|
252
|
+
`activityRefreshWindowMs`; `ConversationList` forwards the same option.
|
|
253
|
+
`useConversation` also exposes `readPositionByUserId`, `readerIdsFor(message)`,
|
|
254
|
+
`markRead()` and `setVisible(visible)`; call `setVisible(false)` while your own
|
|
255
|
+
surface hides the room so automatic acknowledgements wait until it is shown.
|
|
151
256
|
|
|
152
257
|
Optimistic rows display `Sending…` until acknowledgement. The final server
|
|
153
258
|
timestamp is formatted in the viewer's local timezone. Custom message slots can
|
|
@@ -155,7 +260,8 @@ use `isConvoKitPendingMessage(message)` to present the same state.
|
|
|
155
260
|
|
|
156
261
|
## Appearance
|
|
157
262
|
|
|
158
|
-
Wrap any subtree with `ConvoKitThemeProvider
|
|
263
|
+
Wrap any subtree with `ConvoKitThemeProvider` (tokens include `badge` for the
|
|
264
|
+
unread counter), set `density="compact"`, or use
|
|
159
265
|
the per-part `classNames` and `styles` maps. `unstyled` removes package classes
|
|
160
266
|
from the configurable parts for a fully host-owned presentation.
|
|
161
267
|
|