vue-parley 4.7.0 → 4.9.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.
Files changed (54) hide show
  1. package/README.md +26 -4
  2. package/dist/chat.css +77 -12
  3. package/dist/chunks/{Call-CnnA8BfZ.mjs → Call-DY7-rM16.mjs} +2 -2
  4. package/dist/chunks/{Call-CnnA8BfZ.mjs.map → Call-DY7-rM16.mjs.map} +1 -1
  5. package/dist/chunks/{Call-3S9Gy7oj.cjs → Call-RREiDkV_.cjs} +2 -2
  6. package/dist/chunks/{Call-3S9Gy7oj.cjs.map → Call-RREiDkV_.cjs.map} +1 -1
  7. package/dist/chunks/{index-BSRFIpFg.mjs → index-BoigqzSL.mjs} +373 -82
  8. package/dist/chunks/index-BoigqzSL.mjs.map +1 -0
  9. package/dist/chunks/{index-BDGJSPbp.cjs → index-CynD-QrC.cjs} +369 -78
  10. package/dist/chunks/index-CynD-QrC.cjs.map +1 -0
  11. package/dist/chunks/{session-Dmg0EaKA.cjs → session-CYuGKjIt.cjs} +14 -2
  12. package/dist/chunks/session-CYuGKjIt.cjs.map +1 -0
  13. package/dist/chunks/{session-Cw1fw6LP.mjs → session-ClK8dU3I.mjs} +14 -2
  14. package/dist/chunks/session-ClK8dU3I.mjs.map +1 -0
  15. package/dist/index.cjs +2 -1
  16. package/dist/index.cjs.map +1 -1
  17. package/dist/index.mjs +5 -4
  18. package/dist/types/app/components/ChatPage.vue.d.ts +17 -2
  19. package/dist/types/app/components/ChatPage.vue.d.ts.map +1 -1
  20. package/dist/types/app/components/chat/ChatMessages.vue.d.ts.map +1 -1
  21. package/dist/types/app/components/chat/ChatPageBar.vue.d.ts +6 -0
  22. package/dist/types/app/components/chat/ChatPageBar.vue.d.ts.map +1 -1
  23. package/dist/types/app/components/chat/ChatView.vue.d.ts +9 -1
  24. package/dist/types/app/components/chat/ChatView.vue.d.ts.map +1 -1
  25. package/dist/types/app/components/chat/contact/ChatList.vue.d.ts.map +1 -1
  26. package/dist/types/app/composables/call/session.d.ts +3 -0
  27. package/dist/types/app/composables/call/session.d.ts.map +1 -1
  28. package/dist/types/app/composables/call/signaling.d.ts +2 -0
  29. package/dist/types/app/composables/call/signaling.d.ts.map +1 -1
  30. package/dist/types/app/composables/useFlippedVirtualScroll.d.ts +1 -0
  31. package/dist/types/app/composables/useFlippedVirtualScroll.d.ts.map +1 -1
  32. package/dist/types/app/index.d.ts +9 -0
  33. package/dist/types/app/index.d.ts.map +1 -1
  34. package/dist/types/app/stores/callStore.d.ts +23 -2
  35. package/dist/types/app/stores/callStore.d.ts.map +1 -1
  36. package/dist/types/app/stores/chatStore.d.ts +5 -1
  37. package/dist/types/app/stores/chatStore.d.ts.map +1 -1
  38. package/dist/types/app/stores/mediaStore.d.ts +4 -1
  39. package/dist/types/app/stores/mediaStore.d.ts.map +1 -1
  40. package/dist/types/app/stores/messageStores.d.ts +8 -2
  41. package/dist/types/app/stores/messageStores.d.ts.map +1 -1
  42. package/dist/types/app/stores/profileStore.d.ts +4 -1
  43. package/dist/types/app/stores/profileStore.d.ts.map +1 -1
  44. package/dist/types/app/types/components/menu-options.d.ts +7 -1
  45. package/dist/types/app/types/components/menu-options.d.ts.map +1 -1
  46. package/dist/types/app/types/index.d.ts +14 -0
  47. package/dist/types/app/types/index.d.ts.map +1 -1
  48. package/dist/types/i18n/locales/index.d.ts +6 -0
  49. package/dist/types/i18n/locales/index.d.ts.map +1 -1
  50. package/package.json +5 -4
  51. package/dist/chunks/index-BDGJSPbp.cjs.map +0 -1
  52. package/dist/chunks/index-BSRFIpFg.mjs.map +0 -1
  53. package/dist/chunks/session-Cw1fw6LP.mjs.map +0 -1
  54. package/dist/chunks/session-Dmg0EaKA.cjs.map +0 -1
package/README.md CHANGED
@@ -2,8 +2,6 @@
2
2
 
3
3
  A drop-in Vue 3 chat and video-call UI. You supply the backend through a few handler objects; the package brings the screens, the state (Pinia stores), the translations and the styles.
4
4
 
5
- Formerly `@yonus_amire01/chat`. To switch, replace that name with `vue-parley` in `package.json` and in imports; nothing else changed.
6
-
7
5
  - Contact list with search, filters and infinite scroll
8
6
  - Virtualised message list with text, image, file, voice and video messages, replies, edits, deletes, drafts and retries on failed sends
9
7
  - Voice and video calls with screen sharing over plain browser WebRTC
@@ -21,6 +19,7 @@ Formerly `@yonus_amire01/chat`. To switch, replace that name with `vue-parley` i
21
19
  - [Photos and videos](#photos-and-videos)
22
20
  - [Read receipts](#read-receipts)
23
21
  - [Calls outside the chat page](#calls-outside-the-chat-page)
22
+ - [Joining a call in progress](#joining-a-call-in-progress)
24
23
  - [Fake backend](#fake-backend)
25
24
  - [What `createChat()` does](#what-createchat-does)
26
25
  - [Exports](#exports)
@@ -111,10 +110,20 @@ Render the chat inside `<ClientOnly>`: its handlers are only installed in the br
111
110
  | Slot | Where | Slot props |
112
111
  | ------------------ | -------------------------------------------------- | ------------------------------- |
113
112
  | `empty` | Replaces the "no conversation selected" placeholder | none |
114
- | `header-actions` | Conversation header, beside the call button | `{ contact }` |
113
+ | `header-actions` | Conversation header, beside the call button | `{ contact, compact }` |
115
114
  | `conversation-top` | Between the header and the messages | `{ conversationId, contact }` |
116
115
  | `above-input` | Above the input, while the conversation is active | `{ conversationId, contact }` |
117
116
 
117
+ The header folds by its own width (under 640px), not the screen's, since the list and the contact panel take from it. Folded, it keeps the voice call (or Join) and moves the video call into its "more options" menu, and `compact` is true. A host then hides its `header-actions` buttons; the menu lists the `headerOptions` prop in their place (`MenuOption[]`; `icon` is a Phosphor name or any component, `command` runs on select). The header is also a size container named `chat-header`, so host buttons can drop their labels with container queries (`@3xl/chat-header:inline`).
118
+
119
+ ```vue
120
+ <ChatPage :header-options="[{ key: 'members', label: 'Members', icon: UsersIcon, command: openMembers }]">
121
+ <template #header-actions="{ compact }">
122
+ <MembersButton v-if="!compact" />
123
+ </template>
124
+ </ChatPage>
125
+ ```
126
+
118
127
  To build a different layout, use the exported building blocks instead: `ChatList`, `ChatConversation`, `ChatHeader`, `ChatMessages`, `ChatInput` and `ChatBubble`. They read the same stores, so they work together once `createChat()` is installed.
119
128
 
120
129
  ### Photos and videos
@@ -178,6 +187,18 @@ Calls use the browser's WebRTC API directly (no `simple-peer`, no Node polyfills
178
187
 
179
188
  Call handlers also accept `iceTransportPolicy` (default `"relay"`; `"all"` allows direct connections without TURN) and `debug` (logs signalling to the console).
180
189
 
190
+ ### Joining a call in progress
191
+
192
+ When others are in a call on a conversation, its header shows **Join** in place of the call buttons. It joins with the camera on only if the call was started as a video call. Everyone in a call publishes a `presence` message when they join and every 15 seconds after. A call counts as running until its last participant hangs up or goes 45 seconds without being heard from. A closed tab sends no hangup, so that timeout is what ends its call.
193
+
194
+ The call's own subscriber only hears the conversation it is on, so the host has to pass along what it hears on all of them. Hand every call message (`signal`, `join`, `track_type`, `call`, `hangup`, `presence`) from every conversation's channel to the store:
195
+
196
+ ```ts
197
+ callStore.observeCall(message, conversationId);
198
+ ```
199
+
200
+ `conversationId` can be left out for messages that carry `payload.channel`. Messages from the signed-in user are ignored. A host that never calls `observeCall` keeps the start-call buttons.
201
+
181
202
  ### Fake backend
182
203
 
183
204
  `vue-parley/fakes` is an in-memory implementation of every handler, for demos, playgrounds and tests. It is a separate entry, so apps that don't import it don't ship it.
@@ -226,6 +247,7 @@ Every component and directive the chat uses is imported by the component itself,
226
247
  | `BIcon`, `BEmojiPicker`, `BVirtualVerticalList` | A Phosphor icon by name, the emoji picker and the virtualised list the chat uses. Every other control is a PrimeVue component. |
227
248
  | `useChatStore`, `useMessagesStore`, `useMediaStore`, `useProfileStore`, `useCallStore` | The Pinia stores. |
228
249
  | `messageMedia(message)` | A message's photo and video album: its `media`, or its `imageUrl` as photos. |
250
+ | `resetChat()` | Forgets everything the chat loaded for the signed-in user (conversations, threads, drafts, shared media, the downloaded-file cache) and ends a running call. Call it on sign-out or an account switch, before the next user's chat mounts; the handlers stay. Each store also has its own `reset()` (`clearCache()` on the media store). |
229
251
  | Types | Handler interfaces, `Contact`, `Message`, `MediaItem`, `SignalData`, `ChatOptions`, `ChatUser` and the rest of `app/types`. |
230
252
  | `vue-parley/fakes` | `createFakeBackend`, `createBroadcastCallHandlers`, `demoData`, `e2eData`: see [Fake backend](#fake-backend). |
231
253
 
@@ -320,4 +342,4 @@ e2e/ Playwright tests and harness
320
342
 
321
343
  [MIT](LICENSE)
322
344
 
323
- Repository: [github.com/yonus-a/vue-chat](https://github.com/yonus-a/vue-chat)
345
+ Repository: [github.com/SaeedP11/vue-parley](https://github.com/SaeedP11/vue-parley)
package/dist/chat.css CHANGED
@@ -403,6 +403,10 @@
403
403
  @layer components;
404
404
 
405
405
  @layer utilities {
406
+ :where(.vue-chat, .vue-chat *).\@container\/chat-header {
407
+ container: chat-header / inline-size;
408
+ }
409
+
406
410
  :where(.vue-chat, .vue-chat *).\!pointer-events-none {
407
411
  pointer-events: none !important;
408
412
  }
@@ -804,6 +808,11 @@
804
808
  aspect-ratio: var(--aspect-video);
805
809
  }
806
810
 
811
+ :where(.vue-chat, .vue-chat *).size-2 {
812
+ width: calc(var(--spacing) * 2);
813
+ height: calc(var(--spacing) * 2);
814
+ }
815
+
807
816
  :where(.vue-chat, .vue-chat *).size-2\.5 {
808
817
  width: calc(var(--spacing) * 2.5);
809
818
  height: calc(var(--spacing) * 2.5);
@@ -1084,6 +1093,10 @@
1084
1093
  min-height: calc(var(--spacing) * 9);
1085
1094
  }
1086
1095
 
1096
+ :where(.vue-chat, .vue-chat *).min-h-10 {
1097
+ min-height: calc(var(--spacing) * 10);
1098
+ }
1099
+
1087
1100
  :where(.vue-chat, .vue-chat *).min-h-11 {
1088
1101
  min-height: calc(var(--spacing) * 11);
1089
1102
  }
@@ -1184,6 +1197,10 @@
1184
1197
  width: calc(var(--spacing) * 64);
1185
1198
  }
1186
1199
 
1200
+ :where(.vue-chat, .vue-chat *).w-64\! {
1201
+ width: calc(var(--spacing) * 64) !important;
1202
+ }
1203
+
1187
1204
  :where(.vue-chat, .vue-chat *).w-70 {
1188
1205
  width: calc(var(--spacing) * 70);
1189
1206
  }
@@ -1236,6 +1253,10 @@
1236
1253
  max-width: 60%;
1237
1254
  }
1238
1255
 
1256
+ :where(.vue-chat, .vue-chat *).max-w-\[calc\(100vw-1\.5rem\)\]\! {
1257
+ max-width: calc(100vw - 1.5rem) !important;
1258
+ }
1259
+
1239
1260
  :where(.vue-chat, .vue-chat *).max-w-\[calc\(100vw-2rem\)\] {
1240
1261
  max-width: calc(100vw - 2rem);
1241
1262
  }
@@ -1304,6 +1325,10 @@
1304
1325
  transform-origin: 0 0;
1305
1326
  }
1306
1327
 
1328
+ :where(.vue-chat, .vue-chat *).origin-top-right {
1329
+ transform-origin: 100% 0;
1330
+ }
1331
+
1307
1332
  :where(.vue-chat, .vue-chat *).-translate-1\/2 {
1308
1333
  --tw-translate-x: calc(calc(1 / 2 * 100%) * -1);
1309
1334
  --tw-translate-y: calc(calc(1 / 2 * 100%) * -1);
@@ -1529,6 +1554,10 @@
1529
1554
  column-gap: calc(var(--spacing) * 2);
1530
1555
  }
1531
1556
 
1557
+ :where(.vue-chat, .vue-chat *).gap-x-2\! {
1558
+ column-gap: calc(var(--spacing) * 2) !important;
1559
+ }
1560
+
1532
1561
  :where(.vue-chat, .vue-chat *).gap-x-2\.5 {
1533
1562
  column-gap: calc(var(--spacing) * 2.5);
1534
1563
  }
@@ -1563,6 +1592,10 @@
1563
1592
  row-gap: calc(var(--spacing) * .5);
1564
1593
  }
1565
1594
 
1595
+ :where(.vue-chat, .vue-chat *).gap-y-0\.5\! {
1596
+ row-gap: calc(var(--spacing) * .5) !important;
1597
+ }
1598
+
1566
1599
  :where(.vue-chat, .vue-chat *).gap-y-1 {
1567
1600
  row-gap: var(--spacing);
1568
1601
  }
@@ -1794,6 +1827,16 @@
1794
1827
  }
1795
1828
  }
1796
1829
 
1830
+ :where(.vue-chat, .vue-chat *).border-chat-outline-variant\/70\! {
1831
+ border-color: #f0f0f0b3 !important;
1832
+ }
1833
+
1834
+ @supports (color: color-mix(in lab, red, red)) {
1835
+ :where(.vue-chat, .vue-chat *).border-chat-outline-variant\/70\! {
1836
+ border-color: color-mix(in oklab, var(--color-chat-outline-variant) 70%, transparent) !important;
1837
+ }
1838
+ }
1839
+
1797
1840
  :where(.vue-chat, .vue-chat *).border-chat-primary {
1798
1841
  border-color: var(--color-chat-primary);
1799
1842
  }
@@ -2058,6 +2101,10 @@
2058
2101
  }
2059
2102
  }
2060
2103
 
2104
+ :where(.vue-chat, .vue-chat *).bg-current {
2105
+ background-color: currentColor;
2106
+ }
2107
+
2061
2108
  :where(.vue-chat, .vue-chat *).bg-error {
2062
2109
  background-color: var(--color-error);
2063
2110
  }
@@ -2437,6 +2484,10 @@
2437
2484
  padding-inline: calc(var(--spacing) * 3.5);
2438
2485
  }
2439
2486
 
2487
+ :where(.vue-chat, .vue-chat *).px-3\.5\! {
2488
+ padding-inline: calc(var(--spacing) * 3.5) !important;
2489
+ }
2490
+
2440
2491
  :where(.vue-chat, .vue-chat *).px-4 {
2441
2492
  padding-inline: calc(var(--spacing) * 4);
2442
2493
  }
@@ -2919,6 +2970,10 @@
2919
2970
  opacity: .6;
2920
2971
  }
2921
2972
 
2973
+ :where(.vue-chat, .vue-chat *).opacity-75 {
2974
+ opacity: .75;
2975
+ }
2976
+
2922
2977
  :where(.vue-chat, .vue-chat *).opacity-100 {
2923
2978
  opacity: 1;
2924
2979
  }
@@ -3547,6 +3602,12 @@
3547
3602
  }
3548
3603
  }
3549
3604
 
3605
+ @container chat-header (min-width: 48rem) {
3606
+ :where(.vue-chat, .vue-chat *).\@3xl\/chat-header\:inline {
3607
+ display: inline;
3608
+ }
3609
+ }
3610
+
3550
3611
  :where(.vue-chat, .vue-chat *).ltr\:-scale-x-100:where(:dir(ltr), [dir="ltr"], [dir="ltr"] *) {
3551
3612
  --tw-scale-x: calc(100% * -1);
3552
3613
  scale: var(--tw-scale-x) var(--tw-scale-y);
@@ -3577,6 +3638,10 @@
3577
3638
  left: auto !important;
3578
3639
  }
3579
3640
 
3641
+ :where(.vue-chat, .vue-chat *).rtl\:origin-top-left:where(:dir(rtl), [dir="rtl"], [dir="rtl"] *) {
3642
+ transform-origin: 0 0;
3643
+ }
3644
+
3580
3645
  :where(.vue-chat, .vue-chat *).rtl\:origin-top-right:where(:dir(rtl), [dir="rtl"], [dir="rtl"] *) {
3581
3646
  transform-origin: 100% 0;
3582
3647
  }
@@ -4162,15 +4227,15 @@
4162
4227
  }
4163
4228
 
4164
4229
  /* Styles remain exactly the same */
4165
- :where(.vue-chat, .vue-chat *).flip-vertical[data-v-cb7cc93f] {
4230
+ :where(.vue-chat, .vue-chat *).flip-vertical[data-v-c38cc418] {
4166
4231
  transform: scaleY(-1);
4167
4232
  will-change: transform;
4168
4233
  }
4169
- :where(.vue-chat, .vue-chat *)[data-index][data-v-cb7cc93f] {
4234
+ :where(.vue-chat, .vue-chat *)[data-index][data-v-c38cc418] {
4170
4235
  will-change: transform;
4171
4236
  backface-visibility: hidden;
4172
4237
  }
4173
- @keyframes slide-in-right-cb7cc93f {
4238
+ @keyframes slide-in-right-c38cc418 {
4174
4239
  0% {
4175
4240
  opacity: 0;
4176
4241
  transform: scaleY(-1) translateX(30px);
@@ -4180,7 +4245,7 @@
4180
4245
  transform: scaleY(-1) translateX(0);
4181
4246
  }
4182
4247
  }
4183
- @keyframes slide-in-left-cb7cc93f {
4248
+ @keyframes slide-in-left-c38cc418 {
4184
4249
  0% {
4185
4250
  opacity: 0;
4186
4251
  transform: scaleY(-1) translateX(-30px);
@@ -4190,23 +4255,23 @@
4190
4255
  transform: scaleY(-1) translateX(0);
4191
4256
  }
4192
4257
  }
4193
- :where(.vue-chat, .vue-chat *).animate-slide-right[data-v-cb7cc93f] {
4194
- animation: slide-in-right-cb7cc93f 300ms ease-out forwards;
4258
+ :where(.vue-chat, .vue-chat *).animate-slide-right[data-v-c38cc418] {
4259
+ animation: slide-in-right-c38cc418 300ms ease-out forwards;
4195
4260
  will-change: transform, opacity;
4196
4261
  }
4197
- :where(.vue-chat, .vue-chat *).animate-slide-left[data-v-cb7cc93f] {
4198
- animation: slide-in-left-cb7cc93f 300ms ease-out forwards;
4262
+ :where(.vue-chat, .vue-chat *).animate-slide-left[data-v-c38cc418] {
4263
+ animation: slide-in-left-c38cc418 300ms ease-out forwards;
4199
4264
  will-change: transform, opacity;
4200
4265
  }
4201
- :where(.vue-chat, .vue-chat *)#list[data-v-cb7cc93f] {
4266
+ :where(.vue-chat, .vue-chat *)#list[data-v-c38cc418] {
4202
4267
  will-change: padding-top;
4203
4268
  }
4204
- :where(.vue-chat, .vue-chat *).animate-request-in[data-v-cb7cc93f] {
4205
- animation: request-in-cb7cc93f 0.4s ease-out forwards;
4269
+ :where(.vue-chat, .vue-chat *).animate-request-in[data-v-c38cc418] {
4270
+ animation: request-in-c38cc418 0.4s ease-out forwards;
4206
4271
  overflow: hidden;
4207
4272
  transform: scaleY(-1);
4208
4273
  }
4209
- @keyframes request-in-cb7cc93f {
4274
+ @keyframes request-in-c38cc418 {
4210
4275
  0% {
4211
4276
  opacity: 0;
4212
4277
  max-height: 0;
@@ -1,5 +1,5 @@
1
1
  import { ref, onMounted, onUnmounted, watch, nextTick, reactive, onBeforeUnmount, defineComponent, openBlock, createElementBlock, createBlock, unref, mergeProps, withCtx, createVNode, normalizeClass, computed, Fragment, normalizeStyle, createElementVNode, toDisplayString, withModifiers, createCommentVNode, withDirectives, vShow, renderList } from "vue";
2
- import { u as useCallStore, a as useLocalI18n, c as chat, b as useDirection, d as useChatStore, f as formatDuration } from "./index-BSRFIpFg.mjs";
2
+ import { u as useCallStore, a as useLocalI18n, c as chat, b as useDirection, d as useChatStore, f as formatDuration } from "./index-BoigqzSL.mjs";
3
3
  import { useEventListener, useWindowSize, useDraggable } from "@vueuse/core";
4
4
  import Avatar from "primevue/avatar";
5
5
  import Button from "primevue/button";
@@ -1152,4 +1152,4 @@ const _sfc_main = /* @__PURE__ */ defineComponent({
1152
1152
  export {
1153
1153
  _sfc_main as default
1154
1154
  };
1155
- //# sourceMappingURL=Call-CnnA8BfZ.mjs.map
1155
+ //# sourceMappingURL=Call-DY7-rM16.mjs.map