@lilaquadrat/chat 0.1.6 → 0.1.9

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.
@@ -1 +0,0 @@
1
-
@@ -1 +1 @@
1
- !function(n){"function"==typeof define&&define.amd?define(n):n()}(function(){});
1
+ !function(n){"function"==typeof define&&define.amd&&define([],n)}(function(){});
@@ -1,12 +1,18 @@
1
1
  import { type Ref } from 'vue';
2
2
  /**
3
3
  * tracks whether the chat is actually visible to the user:
4
- * - the element must intersect the viewport (catches display:none / collapsed hosts)
4
+ * - the element must intersect the viewport (catches display:none, collapsed hosts, and a
5
+ * host that parks the widget off screen — the supported way to hide an embedded instance)
5
6
  * - the tab must be in the foreground
6
7
  * - in compact mode no left panel may overlay the chat (occlusion is not detectable
7
8
  * cross-browser, so our own overlay state is checked explicitly)
9
+ *
10
+ * Purely visual hiding — `opacity: 0` — is deliberately NOT detected: no observer reports it
11
+ * and probing for it means walking every ancestor's computed style on each check. Hosts hide
12
+ * the widget by moving it out of the viewport (or `display: none`) instead.
8
13
  */
9
14
  export declare function useChatVisibility(element: Ref<HTMLElement | undefined>): {
10
15
  chatVisible: import("vue").ComputedRef<boolean>;
16
+ isVisibleNow: () => boolean;
11
17
  };
12
18
  export default useChatVisibility;
@@ -0,0 +1,10 @@
1
+ /**
2
+ * fires Vue events out of a module/partial without it knowing where it is
3
+ * mounted: the component tells the parent it is done — triggerEvent('close') —
4
+ * and the parent decides how to react. The event name is the string input;
5
+ * more event types can be added later.
6
+ */
7
+ export declare function useTriggerEvent(): {
8
+ triggerEvent: (event: string) => void;
9
+ };
10
+ export default useTriggerEvent;
@@ -44,6 +44,14 @@ export interface ChatModuleConfig {
44
44
  }) => void;
45
45
  /** called when the close button in the header is clicked */
46
46
  close?: () => void;
47
+ /**
48
+ * notification sounds. On at full volume by default; `false` silences them.
49
+ * A sound is only played for remote events the user cannot currently see.
50
+ */
51
+ sound?: boolean | {
52
+ enabled?: boolean;
53
+ volume?: number;
54
+ };
47
55
  /** the host's auth token (Auth0 JWT). Identity is derived from its `sub`; sent as Bearer + WS auth. */
48
56
  token?: string;
49
57
  /**
@@ -21,5 +21,5 @@ export type Participant = string | ParticipantUser;
21
21
  export declare function participantId(participant: Participant): string;
22
22
  /** map a participant list to its ids (e.g. before sending to the backend) */
23
23
  export declare function participantIds(participants?: Participant[]): string[];
24
- /** human-readable name: prename+lastname, else host name, else the raw id */
24
+ /** human-readable name: "lastname, prename", else host name, else the raw id */
25
25
  export declare function participantName(participant: Participant): string;
@@ -0,0 +1,19 @@
1
+ export interface ConversationRightsSource {
2
+ isNew?: boolean;
3
+ participant?: {
4
+ state?: string;
5
+ rights?: string[];
6
+ };
7
+ }
8
+ type Conversation = ConversationRightsSource | null | undefined;
9
+ /**
10
+ * still a member? drafts count, every non-active backend state does not — the server
11
+ * knows 'active' | 'left' | 'removed' | 'blocked' | 'deleted' and keeps only 'active'
12
+ * participants in `conversation.participants` (see participants.service).
13
+ * A missing state means the payload does not track it — treated as a member, the
14
+ * rights check below still applies.
15
+ */
16
+ export declare function isActiveParticipant(conversation: Conversation): boolean;
17
+ /** membership plus the named right ('read' | 'write' | 'rename' | 'participants' | 'block') */
18
+ export declare function can(conversation: Conversation, right: string): boolean;
19
+ export default can;
@@ -0,0 +1,8 @@
1
+ export type SoundName = 'new-message' | 'new-conversation';
2
+ /**
3
+ * Play a notification sound. Never throws and never rejects: browsers refuse audio until
4
+ * the page has seen a user gesture, and a machine without an output device rejects too —
5
+ * neither is worth surfacing for something purely decorative.
6
+ */
7
+ export declare function playSound(name: SoundName, volume?: number): void;
8
+ export default playSound;
@@ -78,6 +78,11 @@ export default class StudioSDK {
78
78
  static handleCall<T, D = any>(call: AxiosRequestConfig<D>, options?: SDKCallOptions): Promise<SDKResponse<T>>;
79
79
  static cache<T>(url: string, response?: AxiosResponse<T>, options?: SDKCallOptions): SDKResponse<any> & SDKCache;
80
80
  static flushCache(group?: string, action?: string): void;
81
+ /**
82
+ * one id can hold several entries (one per query string, e.g. every `beforeId` page of a
83
+ * conversation), so flushing has to drop all of them — otherwise a new message would only
84
+ * invalidate the page whose url happened to match.
85
+ */
81
86
  static flushId(id: string): void;
82
87
  conversations: {
83
88
  list: () => Promise<SDKResponse<any>>;
@@ -88,6 +93,11 @@ export default class StudioSDK {
88
93
  rename: (conversationId: string, name: string) => Promise<SDKResponse<any>>;
89
94
  participants: (conversationId: string, add: string[], remove: string[]) => Promise<SDKResponse<any>>;
90
95
  leave: (conversationId: string) => Promise<SDKResponse<any>>;
96
+ /**
97
+ * POST, not DELETE: this removes the conversation for the CALLER only (their participant
98
+ * state goes to 'deleted' server-side), it does not delete the resource for everyone.
99
+ */
100
+ delete: (conversationId: string) => Promise<SDKResponse<any>>;
91
101
  listParticipants: (conversationId: string) => Promise<SDKResponse<any>>;
92
102
  rights: (conversationId: string, user: string, rights: string[]) => Promise<SDKResponse<any>>;
93
103
  block: (conversationId: string, user: string, block: boolean) => Promise<SDKResponse<any>>;
@@ -1,38 +1,67 @@
1
+ /**
2
+ * Tracks the width the chat is rendered at. Not the viewport: the module runs as a custom
3
+ * element that can sit in a sidebar, so a matchMedia/viewport based breakpoint would report a
4
+ * size the UI never has. realWidth therefore measures the host element, falling back to
5
+ * window.innerWidth only when no selector is given (or it matched nothing).
6
+ *
7
+ * Consumers watch `realWidth`. It is rounded, so sub-pixel jitter does not wake watchers, and
8
+ * it is committed at most once per animation frame — no debounce delay, because the value comes
9
+ * from a ResizeObserver that already reports post-layout sizes once per frame.
10
+ */
1
11
  declare class Resize {
2
- timeout: ReturnType<typeof setTimeout> | undefined;
3
- debounceTime: number;
4
- resizedEvent: Event;
5
- mediaEvent: Event;
6
- media: import("vue").Ref<string, string>;
7
- resized: import("vue").Ref<number, number>;
8
- /** timestamp bumped only when the tracked width actually changed */
9
- widthChanged: import("vue").Ref<number, number>;
10
- realHeight: import("vue").Ref<number, number>;
12
+ /** rounded width of the measured target; watch this to react to resizes */
11
13
  realWidth: import("vue").Ref<number, number>;
12
- /**
13
- * if true we fire an inital resized event to indicate that resizing has started without waiting for the debounce
14
- */
15
- triggerStart: import("vue").Ref<boolean, boolean>;
14
+ realHeight: import("vue").Ref<number, number>;
15
+ /** timestamp of the last commit, for consumers that need a signal rather than a value */
16
+ resized: import("vue").Ref<number, number>;
16
17
  private installed;
17
- private mediaQueries;
18
18
  /** element realWidth is measured against; null = fall back to window.innerWidth */
19
19
  private widthTarget;
20
+ /** kept so a detached target can be resolved again, see resolveTarget */
21
+ private widthSelector;
22
+ private warnedMissingTarget;
20
23
  private resizeObserver;
24
+ private frame;
21
25
  /** bound handler kept so removeEventListener can detach it */
22
26
  private onResize;
23
27
  private get safeWindow();
24
28
  /**
25
- * attach listeners and run initial detection. idempotent.
26
- * @param selector optional CSS selector; when given realWidth tracks that element's width instead of window.innerWidth
29
+ * attach listeners and take the first measurement.
30
+ *
31
+ * calling it again re-targets when the element changed: the custom element can be removed and
32
+ * re-added (or a second one mounted), and a widthTarget left pointing at a detached node
33
+ * measures 0 — which would pin the view mode to mobile forever.
27
34
  */
28
35
  init(selector?: string): void;
29
36
  /** detach listeners. call on teardown/HMR dispose to avoid leaks. */
30
37
  destroy(): void;
38
+ private queryTarget;
39
+ /**
40
+ * an element can resize without a window resize (layout/content changes) and its first laid
41
+ * out size only exists after mount — observe() delivers that initial size for us.
42
+ */
43
+ private observe;
44
+ /**
45
+ * the custom element can be detached and re-attached without configureApp (and therefore
46
+ * init) running again. A detached node measures 0, which would pin the view mode to mobile
47
+ * for good, so re-resolve the selector whenever the target went away.
48
+ */
49
+ private resolveTarget;
50
+ /**
51
+ * rounded on purpose: widths are fractional, and an unrounded value changes on virtually
52
+ * every frame of a drag — every watcher would re-run for a third of a pixel.
53
+ */
31
54
  private measureWidth;
32
- private now;
33
- trigger(isStart?: boolean): void;
34
- getMediaQuery(): void;
35
- debounce(): void;
55
+ /**
56
+ * coalesce to one commit per frame. The observer already batches per layout pass; the frame
57
+ * hop additionally keeps the commit out of the observer callback, so a view mode that changes
58
+ * the observed element's size cannot trip a ResizeObserver loop.
59
+ */
60
+ private schedule;
61
+ /** read the current size into the refs. safe to call directly for an immediate re-measure. */
62
+ measure(): void;
63
+ /** force an immediate re-read, bypassing the frame hop */
64
+ trigger(): void;
36
65
  }
37
66
  declare const resize: Resize;
38
67
  declare const plugin: {
@@ -43,9 +72,7 @@ declare const plugin: {
43
72
  declare function useResize(): {
44
73
  realHeight: import("vue").Ref<number, number>;
45
74
  realWidth: import("vue").Ref<number, number>;
46
- media: import("vue").Ref<string, string>;
47
75
  resized: import("vue").Ref<number, number>;
48
- widthChanged: import("vue").Ref<number, number>;
49
76
  plugin: Resize;
50
77
  };
51
78
  export default plugin;
@@ -3,40 +3,79 @@ declare const _default: {
3
3
  connected: string;
4
4
  disconnected: string;
5
5
  };
6
- actions: {
7
- retry: string;
8
- };
6
+ retry: string;
9
7
  'new chat': string;
10
8
  conversations: string;
11
9
  'contact support': string;
12
10
  support: string;
13
11
  options: string;
12
+ actions: string;
14
13
  mute: string;
15
14
  delete: string;
16
15
  leave: string;
17
16
  'leave now': string;
17
+ 'delete now': string;
18
18
  'select contacts': string;
19
19
  'conversation options': string;
20
20
  'save edits': string;
21
21
  'cancel edits': string;
22
- 'participant rights': string;
22
+ abandon: string;
23
+ close: string;
24
+ rights: string;
25
+ members: string;
26
+ 'update members': string;
23
27
  read: string;
24
28
  write: string;
25
29
  rename: string;
30
+ save: string;
31
+ 'conversation name': string;
32
+ 'you left this conversation': string;
26
33
  participants: string;
27
- members: string;
34
+ 'filter members': string;
35
+ 'filter contacts': string;
36
+ 'member count': string;
37
+ 'created at': string;
38
+ 'last activity': string;
39
+ messages: string;
40
+ 'no messages yet': string;
41
+ message: string;
42
+ 'abandon draft': string;
43
+ 'chat already exists': string;
44
+ 'this is a draft': string;
45
+ 'jump to chat': string;
46
+ writing: string;
28
47
  accept: string;
29
48
  decline: string;
49
+ 'confirm action': string;
30
50
  block: string;
31
51
  unblock: string;
52
+ dismiss: string;
53
+ errors: {
54
+ unknown: string;
55
+ RATE_LIMIT_EXCEEDED: string;
56
+ NOT_ALLOWED: string;
57
+ ACTION_NOT_ALLOWED: string;
58
+ NOT_A_CONTACT: string;
59
+ CONVERSATION_NOT_FOUND: string;
60
+ CONVERSATION_ALREADY_EXISTS: string;
61
+ MIN_PARTICIPANTS: string;
62
+ CONTACT_NOT_FOUND: string;
63
+ CANNOT_BLOCK_SELF: string;
64
+ UNKNOWN_MESSAGE_TYPE: string;
65
+ INVALID_LAST_READ_ID: string;
66
+ INTERNAL_ERROR: string;
67
+ };
32
68
  system: {
33
69
  renamed: string;
34
70
  created: string;
35
71
  left: string;
72
+ blocked: string;
73
+ unblocked: string;
36
74
  participants: {
37
75
  addedAndRemoved: string;
38
76
  added: string;
39
77
  removed: string;
78
+ updated: string;
40
79
  };
41
80
  };
42
81
  };
@@ -3,40 +3,79 @@ declare const _default: {
3
3
  connected: string;
4
4
  disconnected: string;
5
5
  };
6
- actions: {
7
- retry: string;
8
- };
6
+ retry: string;
9
7
  'new chat': string;
10
8
  conversations: string;
11
9
  'contact support': string;
12
10
  support: string;
13
11
  options: string;
12
+ actions: string;
14
13
  mute: string;
15
14
  delete: string;
16
15
  leave: string;
17
16
  'leave now': string;
17
+ 'delete now': string;
18
18
  'select contacts': string;
19
19
  'conversation options': string;
20
20
  'save edits': string;
21
21
  'cancel edits': string;
22
- 'participant rights': string;
22
+ abandon: string;
23
+ close: string;
24
+ rights: string;
25
+ members: string;
26
+ 'update members': string;
23
27
  read: string;
24
28
  write: string;
25
29
  rename: string;
30
+ save: string;
31
+ 'conversation name': string;
32
+ 'you left this conversation': string;
26
33
  participants: string;
27
- members: string;
34
+ 'filter members': string;
35
+ 'filter contacts': string;
36
+ 'member count': string;
37
+ 'created at': string;
38
+ 'last activity': string;
39
+ messages: string;
40
+ 'no messages yet': string;
41
+ message: string;
42
+ 'abandon draft': string;
43
+ 'chat already exists': string;
44
+ 'this is a draft': string;
45
+ 'jump to chat': string;
46
+ writing: string;
28
47
  accept: string;
29
48
  decline: string;
49
+ 'confirm action': string;
30
50
  block: string;
31
51
  unblock: string;
52
+ dismiss: string;
53
+ errors: {
54
+ unknown: string;
55
+ RATE_LIMIT_EXCEEDED: string;
56
+ NOT_ALLOWED: string;
57
+ ACTION_NOT_ALLOWED: string;
58
+ NOT_A_CONTACT: string;
59
+ CONVERSATION_NOT_FOUND: string;
60
+ CONVERSATION_ALREADY_EXISTS: string;
61
+ MIN_PARTICIPANTS: string;
62
+ CONTACT_NOT_FOUND: string;
63
+ CANNOT_BLOCK_SELF: string;
64
+ UNKNOWN_MESSAGE_TYPE: string;
65
+ INVALID_LAST_READ_ID: string;
66
+ INTERNAL_ERROR: string;
67
+ };
32
68
  system: {
33
69
  renamed: string;
34
70
  created: string;
35
71
  left: string;
72
+ blocked: string;
73
+ unblocked: string;
36
74
  participants: {
37
75
  addedAndRemoved: string;
38
76
  added: string;
39
77
  removed: string;
78
+ updated: string;
40
79
  };
41
80
  };
42
81
  };
@@ -7,40 +7,79 @@ declare const i18n: import("vue-i18n").I18n<{
7
7
  connected: string;
8
8
  disconnected: string;
9
9
  };
10
- actions: {
11
- retry: string;
12
- };
10
+ retry: string;
13
11
  'new chat': string;
14
12
  conversations: string;
15
13
  'contact support': string;
16
14
  support: string;
17
15
  options: string;
16
+ actions: string;
18
17
  mute: string;
19
18
  delete: string;
20
19
  leave: string;
21
20
  'leave now': string;
21
+ 'delete now': string;
22
22
  'select contacts': string;
23
23
  'conversation options': string;
24
24
  'save edits': string;
25
25
  'cancel edits': string;
26
- 'participant rights': string;
26
+ abandon: string;
27
+ close: string;
28
+ rights: string;
29
+ members: string;
30
+ 'update members': string;
27
31
  read: string;
28
32
  write: string;
29
33
  rename: string;
34
+ save: string;
35
+ 'conversation name': string;
36
+ 'you left this conversation': string;
30
37
  participants: string;
31
- members: string;
38
+ 'filter members': string;
39
+ 'filter contacts': string;
40
+ 'member count': string;
41
+ 'created at': string;
42
+ 'last activity': string;
43
+ messages: string;
44
+ 'no messages yet': string;
45
+ message: string;
46
+ 'abandon draft': string;
47
+ 'chat already exists': string;
48
+ 'this is a draft': string;
49
+ 'jump to chat': string;
50
+ writing: string;
32
51
  accept: string;
33
52
  decline: string;
53
+ 'confirm action': string;
34
54
  block: string;
35
55
  unblock: string;
56
+ dismiss: string;
57
+ errors: {
58
+ unknown: string;
59
+ RATE_LIMIT_EXCEEDED: string;
60
+ NOT_ALLOWED: string;
61
+ ACTION_NOT_ALLOWED: string;
62
+ NOT_A_CONTACT: string;
63
+ CONVERSATION_NOT_FOUND: string;
64
+ CONVERSATION_ALREADY_EXISTS: string;
65
+ MIN_PARTICIPANTS: string;
66
+ CONTACT_NOT_FOUND: string;
67
+ CANNOT_BLOCK_SELF: string;
68
+ UNKNOWN_MESSAGE_TYPE: string;
69
+ INVALID_LAST_READ_ID: string;
70
+ INTERNAL_ERROR: string;
71
+ };
36
72
  system: {
37
73
  renamed: string;
38
74
  created: string;
39
75
  left: string;
76
+ blocked: string;
77
+ unblocked: string;
40
78
  participants: {
41
79
  addedAndRemoved: string;
42
80
  added: string;
43
81
  removed: string;
82
+ updated: string;
44
83
  };
45
84
  };
46
85
  };
@@ -26,6 +26,10 @@ export interface StandaloneSettings {
26
26
  support?: {
27
27
  participants: string[];
28
28
  };
29
+ sound?: boolean | {
30
+ enabled?: boolean;
31
+ volume?: number;
32
+ };
29
33
  };
30
34
  /** document title of the deployment */
31
35
  title?: string;
@@ -48,7 +48,12 @@ export declare const useConversationsStore: import("pinia").StoreDefinition<"con
48
48
  executeParticipantsEdit: (conversation: string, add: string[], remove: string[]) => Promise<import("@/libs/StudioSDK").SDKResponse<any>>;
49
49
  updateConversationParticipant: (conversation: string, state: string) => void;
50
50
  leave: (conversation: string) => Promise<import("@/libs/StudioSDK").SDKResponse<any>>;
51
- }, "conversations" | "typing" | "activeConversation">, Pick<{
51
+ deleteConversation: (conversation: string) => Promise<void>;
52
+ lastActiveConversation: import("vue").Ref<any, any>;
53
+ getLatestConversation: () => ConversationEntry;
54
+ activateLastOrLatestConversation: () => void;
55
+ readLastActiveConversation: () => void;
56
+ }, "conversations" | "typing" | "activeConversation" | "lastActiveConversation">, Pick<{
52
57
  getAllConversations: () => Promise<void>;
53
58
  refreshConversations: () => Promise<void>;
54
59
  handleReconnect: () => Promise<void>;
@@ -94,6 +99,11 @@ export declare const useConversationsStore: import("pinia").StoreDefinition<"con
94
99
  executeParticipantsEdit: (conversation: string, add: string[], remove: string[]) => Promise<import("@/libs/StudioSDK").SDKResponse<any>>;
95
100
  updateConversationParticipant: (conversation: string, state: string) => void;
96
101
  leave: (conversation: string) => Promise<import("@/libs/StudioSDK").SDKResponse<any>>;
102
+ deleteConversation: (conversation: string) => Promise<void>;
103
+ lastActiveConversation: import("vue").Ref<any, any>;
104
+ getLatestConversation: () => ConversationEntry;
105
+ activateLastOrLatestConversation: () => void;
106
+ readLastActiveConversation: () => void;
97
107
  }, "unreadConversations" | "totalUnreadCount" | "totalUnreadConversations">, Pick<{
98
108
  getAllConversations: () => Promise<void>;
99
109
  refreshConversations: () => Promise<void>;
@@ -140,5 +150,10 @@ export declare const useConversationsStore: import("pinia").StoreDefinition<"con
140
150
  executeParticipantsEdit: (conversation: string, add: string[], remove: string[]) => Promise<import("@/libs/StudioSDK").SDKResponse<any>>;
141
151
  updateConversationParticipant: (conversation: string, state: string) => void;
142
152
  leave: (conversation: string) => Promise<import("@/libs/StudioSDK").SDKResponse<any>>;
143
- }, "leave" | "rename" | "getAllConversations" | "refreshConversations" | "handleReconnect" | "setTyping" | "loadParticipants" | "setRights" | "blockUser" | "updateParticipantRights" | "create" | "createNew" | "startSupport" | "activateConversation" | "convertTempToConversation" | "getMessagesFromApi" | "addMessagesToConversation" | "getMessagesForConversation" | "updateLastMessage" | "updateUnread" | "updateAllUnread" | "increaseMessageCount" | "increaseMessageCountSystem" | "setLastReadId" | "getConversation" | "addParticipant" | "removeParticipant" | "setParticipants" | "toggleParticipant" | "getConversationViaParticipantsAndName" | "cleanConversations" | "abandonConversation" | "inactivateConversation" | "conversationRenamed" | "executeParticipantsEdit" | "updateConversationParticipant">>;
153
+ deleteConversation: (conversation: string) => Promise<void>;
154
+ lastActiveConversation: import("vue").Ref<any, any>;
155
+ getLatestConversation: () => ConversationEntry;
156
+ activateLastOrLatestConversation: () => void;
157
+ readLastActiveConversation: () => void;
158
+ }, "leave" | "rename" | "getAllConversations" | "refreshConversations" | "handleReconnect" | "setTyping" | "loadParticipants" | "setRights" | "blockUser" | "updateParticipantRights" | "create" | "createNew" | "startSupport" | "activateConversation" | "convertTempToConversation" | "getMessagesFromApi" | "addMessagesToConversation" | "getMessagesForConversation" | "updateLastMessage" | "updateUnread" | "updateAllUnread" | "increaseMessageCount" | "increaseMessageCountSystem" | "setLastReadId" | "getConversation" | "addParticipant" | "removeParticipant" | "setParticipants" | "toggleParticipant" | "getConversationViaParticipantsAndName" | "cleanConversations" | "abandonConversation" | "inactivateConversation" | "conversationRenamed" | "executeParticipantsEdit" | "updateConversationParticipant" | "deleteConversation" | "getLatestConversation" | "activateLastOrLatestConversation" | "readLastActiveConversation">>;
144
159
  export default useConversationsStore;