@weavy/uikit-react 11.0.1 → 12.1.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 (242) hide show
  1. package/.github/workflows/publish.yml +1 -1
  2. package/README.md +3 -4
  3. package/changelog.md +30 -0
  4. package/dist/cjs/index.js +6 -6
  5. package/dist/cjs/index.js.map +1 -1
  6. package/dist/cjs/types/client/WeavyClient.d.ts +1 -1
  7. package/dist/cjs/types/components/Image.d.ts +2 -0
  8. package/dist/cjs/types/components/PdfViewer.d.ts +6 -0
  9. package/dist/cjs/types/components/Preview.d.ts +58 -0
  10. package/dist/cjs/types/contexts/MessengerContext.d.ts +1 -2
  11. package/dist/cjs/types/hooks/useUser.d.ts +2 -1
  12. package/dist/cjs/types/types/Messenger.d.ts +0 -1
  13. package/dist/cjs/types/types/types.d.ts +11 -6
  14. package/dist/cjs/types/utils/fileUtilities.d.ts +16 -1
  15. package/dist/css/weavy-chat.css +2684 -0
  16. package/dist/css/weavy-messenger.css +3039 -0
  17. package/dist/css/weavy.css +3039 -0
  18. package/dist/esm/index.js +6 -6
  19. package/dist/esm/index.js.map +1 -1
  20. package/dist/esm/types/client/WeavyClient.d.ts +1 -1
  21. package/dist/esm/types/components/Image.d.ts +2 -0
  22. package/dist/esm/types/components/PdfViewer.d.ts +6 -0
  23. package/dist/esm/types/components/Preview.d.ts +58 -0
  24. package/dist/esm/types/contexts/MessengerContext.d.ts +1 -2
  25. package/dist/esm/types/hooks/useUser.d.ts +2 -1
  26. package/dist/esm/types/types/Messenger.d.ts +0 -1
  27. package/dist/esm/types/types/types.d.ts +11 -6
  28. package/dist/esm/types/utils/fileUtilities.d.ts +16 -1
  29. package/dist/index.d.ts +2 -3
  30. package/package.json +14 -4
  31. package/rollup.config.js +0 -2
  32. package/src/client/WeavyClient.ts +3 -3
  33. package/src/components/Attachment.tsx +5 -6
  34. package/src/components/Avatar.tsx +2 -3
  35. package/src/components/Chat.tsx +10 -14
  36. package/src/components/Conversation.tsx +21 -30
  37. package/src/components/ConversationBadge.tsx +1 -2
  38. package/src/components/ConversationForm.tsx +11 -18
  39. package/src/components/ConversationList.tsx +4 -5
  40. package/src/components/ConversationListItem.tsx +13 -15
  41. package/src/components/FileBrowser.tsx +2 -3
  42. package/src/components/Image.tsx +39 -7
  43. package/src/components/MeetingCard.tsx +7 -8
  44. package/src/components/Message.tsx +12 -13
  45. package/src/components/Messages.tsx +19 -19
  46. package/src/components/Messenger.tsx +5 -6
  47. package/src/components/NewConversation.tsx +5 -7
  48. package/src/components/PdfViewer.tsx +271 -0
  49. package/src/components/Presence.tsx +2 -2
  50. package/src/components/Preview.tsx +294 -0
  51. package/src/components/Reactions.tsx +8 -8
  52. package/src/components/SearchUsers.tsx +18 -17
  53. package/src/components/SeenBy.tsx +1 -2
  54. package/src/components/Typing.tsx +4 -4
  55. package/src/contexts/MessengerContext.tsx +4 -12
  56. package/src/contexts/PreviewContext.tsx +4 -6
  57. package/src/contexts/WeavyContext.tsx +8 -1
  58. package/src/hooks/useBadge.ts +1 -1
  59. package/src/hooks/useChat.ts +1 -1
  60. package/src/hooks/useConversation.ts +1 -2
  61. package/src/hooks/useConversations.ts +1 -1
  62. package/src/hooks/useFileUploader.ts +5 -1
  63. package/src/hooks/useMembers.ts +1 -1
  64. package/src/hooks/useMessages.ts +1 -1
  65. package/src/hooks/useMutateChat.ts +1 -1
  66. package/src/hooks/useMutateConversation.ts +1 -1
  67. package/src/hooks/useMutateConversationName.ts +1 -1
  68. package/src/hooks/useMutateDeleteReaction.ts +1 -1
  69. package/src/hooks/useMutateExternalBlobs.ts +1 -1
  70. package/src/hooks/useMutateMeeting.ts +1 -1
  71. package/src/hooks/useMutateMembers.ts +1 -1
  72. package/src/hooks/useMutateMessage.ts +2 -1
  73. package/src/hooks/useMutatePinned.ts +1 -1
  74. package/src/hooks/useMutateReaction.ts +1 -1
  75. package/src/hooks/useMutateRead.ts +1 -1
  76. package/src/hooks/useMutateRemoveMembers.ts +1 -1
  77. package/src/hooks/useMutateTyping.ts +1 -1
  78. package/src/hooks/usePresence.ts +8 -5
  79. package/src/hooks/useReactions.ts +0 -1
  80. package/src/hooks/useSearchUsers.ts +1 -1
  81. package/src/hooks/useUser.ts +4 -3
  82. package/src/index.ts +2 -2
  83. package/src/scss/theme/_alert.scss +73 -0
  84. package/src/scss/theme/_appbar.scss +112 -0
  85. package/src/scss/theme/_attachments.scss +74 -0
  86. package/src/scss/theme/_avatar.scss +54 -0
  87. package/src/scss/theme/_badge.scss +47 -0
  88. package/src/scss/theme/_buttons.scss +96 -0
  89. package/src/scss/theme/_card.scss +7 -0
  90. package/src/scss/theme/_checkbox.scss +56 -0
  91. package/src/scss/theme/_cm-editor.scss +42 -0
  92. package/src/scss/theme/_code.scss +115 -0
  93. package/src/scss/theme/_colors.scss +520 -0
  94. package/src/scss/theme/_config.scss +6 -0
  95. package/src/scss/theme/_content.scss +15 -0
  96. package/src/scss/theme/_conversations.scss +91 -0
  97. package/src/scss/theme/_dropdown.scss +86 -0
  98. package/src/scss/theme/_emoji.scss +5 -0
  99. package/src/scss/theme/_filebrowser.scss +26 -0
  100. package/src/scss/theme/_files.scss +140 -0
  101. package/src/scss/theme/_icons.scss +62 -0
  102. package/src/scss/theme/_image-grid.scss +63 -0
  103. package/src/scss/theme/_inputs.scss +28 -0
  104. package/src/scss/theme/_message-editor.scss +90 -0
  105. package/src/scss/theme/_messages.scss +238 -0
  106. package/src/scss/theme/_nav.scss +52 -0
  107. package/src/scss/theme/_overlays.scss +157 -0
  108. package/src/scss/theme/_pager.scss +19 -0
  109. package/src/scss/theme/_palette.scss +165 -0
  110. package/src/scss/theme/_pane.scss +16 -0
  111. package/src/scss/theme/_panels.scss +137 -0
  112. package/src/scss/theme/_picker-list.scss +37 -0
  113. package/src/scss/theme/_preview-embed.scss +38 -0
  114. package/src/scss/theme/_preview-html.scss +7 -0
  115. package/src/scss/theme/_preview-icon.scss +41 -0
  116. package/src/scss/theme/_preview-image.scss +86 -0
  117. package/src/scss/theme/_preview-media.scss +28 -0
  118. package/src/scss/theme/_preview-pdf.scss +838 -0
  119. package/src/scss/theme/_preview-text.scss +5 -0
  120. package/src/scss/theme/_preview.scss +105 -0
  121. package/src/scss/theme/_reactions.scss +58 -0
  122. package/src/scss/theme/_reboot.scss +41 -0
  123. package/src/scss/theme/_root.scss +2 -0
  124. package/src/scss/theme/_scroll.scss +55 -0
  125. package/src/scss/theme/_search.scss +68 -0
  126. package/src/scss/theme/_spinner.scss +63 -0
  127. package/src/scss/theme/_tables.scss +53 -0
  128. package/src/scss/theme/_toasts.scss +47 -0
  129. package/src/scss/theme/_turbo.scss +17 -0
  130. package/src/scss/theme/_typing.scss +26 -0
  131. package/src/scss/theme/_variables.scss +139 -0
  132. package/src/scss/theme/bootstrap/_accordion.scss +146 -0
  133. package/src/scss/theme/bootstrap/_alert.scss +71 -0
  134. package/src/scss/theme/bootstrap/_badge.scss +38 -0
  135. package/src/scss/theme/bootstrap/_breadcrumb.scss +40 -0
  136. package/src/scss/theme/bootstrap/_button-group.scss +142 -0
  137. package/src/scss/theme/bootstrap/_buttons.scss +186 -0
  138. package/src/scss/theme/bootstrap/_card.scss +234 -0
  139. package/src/scss/theme/bootstrap/_carousel.scss +229 -0
  140. package/src/scss/theme/bootstrap/_close.scss +40 -0
  141. package/src/scss/theme/bootstrap/_containers.scss +41 -0
  142. package/src/scss/theme/bootstrap/_dropdown.scss +248 -0
  143. package/src/scss/theme/bootstrap/_forms.scss +9 -0
  144. package/src/scss/theme/bootstrap/_functions.scss +302 -0
  145. package/src/scss/theme/bootstrap/_grid.scss +33 -0
  146. package/src/scss/theme/bootstrap/_helpers.scss +10 -0
  147. package/src/scss/theme/bootstrap/_images.scss +42 -0
  148. package/src/scss/theme/bootstrap/_list-group.scss +191 -0
  149. package/src/scss/theme/bootstrap/_maps.scss +54 -0
  150. package/src/scss/theme/bootstrap/_mixins.scss +43 -0
  151. package/src/scss/theme/bootstrap/_modal.scss +237 -0
  152. package/src/scss/theme/bootstrap/_nav.scss +172 -0
  153. package/src/scss/theme/bootstrap/_navbar.scss +276 -0
  154. package/src/scss/theme/bootstrap/_offcanvas.scss +143 -0
  155. package/src/scss/theme/bootstrap/_pagination.scss +109 -0
  156. package/src/scss/theme/bootstrap/_placeholders.scss +51 -0
  157. package/src/scss/theme/bootstrap/_popover.scss +196 -0
  158. package/src/scss/theme/bootstrap/_progress.scss +59 -0
  159. package/src/scss/theme/bootstrap/_reboot.scss +610 -0
  160. package/src/scss/theme/bootstrap/_root.scss +73 -0
  161. package/src/scss/theme/bootstrap/_spinners.scss +85 -0
  162. package/src/scss/theme/bootstrap/_tables.scss +164 -0
  163. package/src/scss/theme/bootstrap/_toasts.scss +70 -0
  164. package/src/scss/theme/bootstrap/_tooltip.scss +120 -0
  165. package/src/scss/theme/bootstrap/_transitions.scss +27 -0
  166. package/src/scss/theme/bootstrap/_type.scss +106 -0
  167. package/src/scss/theme/bootstrap/_utilities.scss +647 -0
  168. package/src/scss/theme/bootstrap/_variables.scss +1633 -0
  169. package/src/scss/theme/bootstrap/forms/_floating-labels.scss +74 -0
  170. package/src/scss/theme/bootstrap/forms/_form-check.scss +175 -0
  171. package/src/scss/theme/bootstrap/forms/_form-control.scss +194 -0
  172. package/src/scss/theme/bootstrap/forms/_form-range.scss +91 -0
  173. package/src/scss/theme/bootstrap/forms/_form-select.scss +71 -0
  174. package/src/scss/theme/bootstrap/forms/_form-text.scss +11 -0
  175. package/src/scss/theme/bootstrap/forms/_input-group.scss +129 -0
  176. package/src/scss/theme/bootstrap/forms/_labels.scss +36 -0
  177. package/src/scss/theme/bootstrap/forms/_validation.scss +12 -0
  178. package/src/scss/theme/bootstrap/helpers/_clearfix.scss +3 -0
  179. package/src/scss/theme/bootstrap/helpers/_color-bg.scss +10 -0
  180. package/src/scss/theme/bootstrap/helpers/_colored-links.scss +12 -0
  181. package/src/scss/theme/bootstrap/helpers/_position.scss +36 -0
  182. package/src/scss/theme/bootstrap/helpers/_ratio.scss +26 -0
  183. package/src/scss/theme/bootstrap/helpers/_stacks.scss +15 -0
  184. package/src/scss/theme/bootstrap/helpers/_stretched-link.scss +15 -0
  185. package/src/scss/theme/bootstrap/helpers/_text-truncation.scss +7 -0
  186. package/src/scss/theme/bootstrap/helpers/_visually-hidden.scss +8 -0
  187. package/src/scss/theme/bootstrap/helpers/_vr.scss +8 -0
  188. package/src/scss/theme/bootstrap/mixins/_alert.scss +15 -0
  189. package/src/scss/theme/bootstrap/mixins/_backdrop.scss +14 -0
  190. package/src/scss/theme/bootstrap/mixins/_banner.scss +9 -0
  191. package/src/scss/theme/bootstrap/mixins/_border-radius.scss +78 -0
  192. package/src/scss/theme/bootstrap/mixins/_box-shadow.scss +18 -0
  193. package/src/scss/theme/bootstrap/mixins/_breakpoints.scss +127 -0
  194. package/src/scss/theme/bootstrap/mixins/_buttons.scss +70 -0
  195. package/src/scss/theme/bootstrap/mixins/_caret.scss +64 -0
  196. package/src/scss/theme/bootstrap/mixins/_clearfix.scss +9 -0
  197. package/src/scss/theme/bootstrap/mixins/_color-scheme.scss +7 -0
  198. package/src/scss/theme/bootstrap/mixins/_container.scss +11 -0
  199. package/src/scss/theme/bootstrap/mixins/_deprecate.scss +10 -0
  200. package/src/scss/theme/bootstrap/mixins/_forms.scss +152 -0
  201. package/src/scss/theme/bootstrap/mixins/_gradients.scss +47 -0
  202. package/src/scss/theme/bootstrap/mixins/_grid.scss +151 -0
  203. package/src/scss/theme/bootstrap/mixins/_image.scss +16 -0
  204. package/src/scss/theme/bootstrap/mixins/_list-group.scss +24 -0
  205. package/src/scss/theme/bootstrap/mixins/_lists.scss +7 -0
  206. package/src/scss/theme/bootstrap/mixins/_pagination.scss +10 -0
  207. package/src/scss/theme/bootstrap/mixins/_reset-text.scss +17 -0
  208. package/src/scss/theme/bootstrap/mixins/_resize.scss +6 -0
  209. package/src/scss/theme/bootstrap/mixins/_table-variants.scss +24 -0
  210. package/src/scss/theme/bootstrap/mixins/_text-truncate.scss +8 -0
  211. package/src/scss/theme/bootstrap/mixins/_transition.scss +26 -0
  212. package/src/scss/theme/bootstrap/mixins/_utilities.scss +97 -0
  213. package/src/scss/theme/bootstrap/mixins/_visually-hidden.scss +29 -0
  214. package/src/scss/theme/bootstrap/utilities/_api.scss +47 -0
  215. package/src/scss/theme/bootstrap/vendor/_rfs.scss +354 -0
  216. package/src/scss/theme/bs/_badge.scss +20 -0
  217. package/src/scss/theme/bs/_buttons.scss +185 -0
  218. package/src/scss/theme/bs/_dropdown.scss +86 -0
  219. package/src/scss/theme/bs/_forms.scss +161 -0
  220. package/src/scss/theme/bs/_list-group.scss +73 -0
  221. package/src/scss/theme/bs/_tables.scss +46 -0
  222. package/src/scss/theme/fonts/_fontmapping-roboto.scss +129 -0
  223. package/src/scss/theme/fonts/_fontmapping-segoe-ui.scss +127 -0
  224. package/src/scss/theme/fonts/_index.scss +2 -0
  225. package/src/scss/theme/mixins/_backdrop.scss +13 -0
  226. package/src/scss/theme/mixins/_palette.scss +165 -0
  227. package/src/scss/theme/mixins/_position.scss +33 -0
  228. package/src/scss/theme/mixins/_scrollbar.scss +110 -0
  229. package/src/scss/weavy-chat.scss +31 -0
  230. package/src/scss/weavy-messenger.scss +60 -0
  231. package/src/scss/weavy.scss +2 -0
  232. package/src/types/Messenger.ts +1 -1
  233. package/src/types/types.ts +14 -9
  234. package/src/ui/Button.tsx +3 -4
  235. package/src/ui/Dropdown.tsx +4 -5
  236. package/src/ui/Icon.tsx +75 -39
  237. package/src/ui/Overlay.tsx +2 -3
  238. package/src/utils/fileUtilities.ts +280 -72
  239. package/src/utils/scrollbarDetection.js +48 -0
  240. package/dist/cjs/types/utils/styles.d.ts +0 -17
  241. package/dist/esm/types/utils/styles.d.ts +0 -17
  242. package/src/utils/styles.ts +0 -42
@@ -5,7 +5,6 @@ import ConversationListItem from './ConversationListItem';
5
5
  import NewConversation from './NewConversation';
6
6
  import Avatar from './Avatar';
7
7
  import { UserContext } from '../contexts/UserContext';
8
- import { prefix as wy } from "../utils/styles";
9
8
 
10
9
  const ConversationList = () => {
11
10
  const { client } = useContext(WeavyContext);
@@ -40,19 +39,19 @@ const ConversationList = () => {
40
39
 
41
40
  return (
42
41
  <>
43
- <header className={wy('appbars')}>
44
- <nav className={wy('appbar')}>
42
+ <header className="wy-appbars">
43
+ <nav className="wy-appbar">
45
44
  <Avatar src={user.avatar_url} name={user.title} presence={user.presence} id={user.id} size={24} />
46
45
  <div>Messenger</div>
47
46
  <NewConversation />
48
47
  </nav>
49
48
  </header>
50
- <div className={wy('conversations')}>
49
+ <div className="wy-conversations">
51
50
  {data && data.data?.map((item) =>
52
51
  <ConversationListItem key={item.id} refetchConversations={refetch} item={item} />
53
52
  )}
54
53
 
55
- {/* <a className={wy('pager')}><svg className={wy('spinner spin')} width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle fill="none" cx="12" cy="12" r="11" stroke-linecap="butt" stroke-width="2"></circle></svg></a> */}
54
+ {/* <a className="wy-pager"><svg className="wy-spinner wy-spin" width="24" height="24" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><circle fill="none" cx="12" cy="12" r="11" stroke-linecap="butt" stroke-width="2"></circle></svg></a> */}
56
55
  </div>
57
56
  </>
58
57
  )
@@ -13,8 +13,7 @@ import Typing from './Typing';
13
13
  import useMutateRemoveMembers from '../hooks/useMutateRemoveMembers';
14
14
  import Avatar from './Avatar';
15
15
  import { UserContext } from '../contexts/UserContext';
16
- import { prefix as wy } from "../utils/styles";
17
-
16
+ import classNames from 'classnames';
18
17
 
19
18
  const ConversationListItem = ({ item, refetchConversations }: ConversationListItemProps) => {
20
19
 
@@ -40,10 +39,10 @@ const ConversationListItem = ({ item, refetchConversations }: ConversationListIt
40
39
  }, [item.id])
41
40
 
42
41
  useEffect(() => {
43
- client.subscribe(`a${item.id}`, "app-updated", handleAppUpdated);
42
+ client?.subscribe(`a${item.id}`, "app-updated", handleAppUpdated);
44
43
 
45
44
  return () => {
46
- client.unsubscribe(`a${item.id}`, "app-updated", handleAppUpdated);
45
+ client?.unsubscribe(`a${item.id}`, "app-updated", handleAppUpdated);
47
46
  }
48
47
  }, [item.id])
49
48
 
@@ -79,25 +78,25 @@ const ConversationListItem = ({ item, refetchConversations }: ConversationListIt
79
78
  // }
80
79
 
81
80
  return (
82
- <div className={wy('conversation' + (item.is_unread ? ' unread' : ''))} key={item.id}>
83
- <a className={wy('conversation-link' + (selectedConversationId === item.id ? ' active': ''))} href="#" onClick={(e) => handleClick(e, item.id)}>
81
+ <div className={classNames('wy-conversation', {"wy-unread": item.is_unread})} key={item.id}>
82
+ <a className={classNames('wy-conversation-link', { "wy-active": selectedConversationId === item.id})} href="#" onClick={(e) => handleClick(e, item.id)}>
84
83
  <Avatar src={item.avatar_url} id={otherId || -1} presence={item.type !== ChatRoom ? "away" : ""} name={item.display_name} />
85
84
 
86
- <div className={wy('conversation-body')}>
87
- <div className={wy('conversation-header')}>
88
- <div className={wy('conversation-title')}>{item.display_name}</div>
85
+ <div className="wy-conversation-body">
86
+ <div className="wy-conversation-header">
87
+ <div className="wy-conversation-title">{item.display_name}</div>
89
88
  {item.last_message &&
90
- <time className={wy('conversation-time')} dateTime={item.last_message.created_at.toString()} title={date.format('LLLL')}>{date.fromNow()}</time>
89
+ <time className="wy-conversation-time" dateTime={item.last_message.created_at.toString()} title={date.format('LLLL')}>{date.fromNow()}</time>
91
90
  }
92
91
  </div>
93
- <div className={wy('conversation-summary')}>
92
+ <div className="wy-conversation-summary">
94
93
  <Typing id={item.id} context="listitem">
95
94
 
96
95
  {item.last_message?.html &&
97
- <span className={wy('typing-hide')} dangerouslySetInnerHTML={{ __html: joypixels.shortnameToUnicode(item.last_message?.text) }}></span>
96
+ <span className="wy-typing-hide" dangerouslySetInnerHTML={{ __html: joypixels.shortnameToUnicode(item.last_message?.text) }}></span>
98
97
  }
99
98
  {!item.last_message?.html &&
100
- <span className={wy('typing-hide')}>
99
+ <span className="wy-typing-hide">
101
100
  {item.last_message?.attachment_ids?.length > 0 &&
102
101
  <Icon.UI name="attachment" size={1} />
103
102
  }
@@ -112,7 +111,7 @@ const ConversationListItem = ({ item, refetchConversations }: ConversationListIt
112
111
  </div>
113
112
  </a>
114
113
 
115
- <div className={wy('conversation-actions')}>
114
+ <div className="wy-conversation-actions">
116
115
  {item.is_pinned &&
117
116
  <Button.UI onClick={handleUnpin}>
118
117
  <Icon.UI name="pin" size={.75} />
@@ -120,7 +119,6 @@ const ConversationListItem = ({ item, refetchConversations }: ConversationListIt
120
119
 
121
120
  }
122
121
 
123
-
124
122
  <Dropdown.UI directionX='left'>
125
123
  <>
126
124
  {item.is_unread &&
@@ -4,7 +4,6 @@ import Button from '../ui/Button';
4
4
  import Icon from '../ui/Icon';
5
5
  import useMutateExternalBlobs from '../hooks/useMutateExternalBlobs';
6
6
  import { UserContext } from "../contexts/UserContext";
7
- import { prefix as wy } from "../utils/styles";
8
7
 
9
8
  type Props = {
10
9
  onFileAdded: Function
@@ -60,8 +59,8 @@ const FileBrowser = ({ onFileAdded }: Props) => {
60
59
  $filebrowserFrame.id = "weavy-filebrowser";
61
60
  $filebrowserFrame.name = "weavy-filebrowser";
62
61
  $filebrowserFrame.src = filebrowserSrc;
63
- $filebrowserFrame.className = wy('filebrowser-frame');
64
- $filebrowserFrame.style.cssText = "position: absolute; top: 0; left: 0; height: 100%; width: 100%; background: rgba(1,1,1,.4); z-index: 10000; display:none"
62
+ $filebrowserFrame.className = "wy-filebrowser-frame";
63
+ $filebrowserFrame.style.cssText = "position: fixed; top: 0; left: 0; height: 100%; width: 100%; background: rgba(1,1,1,.4); z-index: 10000; display:none"
65
64
 
66
65
  window.top?.document.body.appendChild($filebrowserFrame);
67
66
 
@@ -1,5 +1,4 @@
1
- import React, { useState } from "react";
2
- import { prefix as wy } from "../utils/styles";
1
+ import React, { useCallback } from "react";
3
2
 
4
3
  type ImageProps = {
5
4
  src: string,
@@ -10,6 +9,33 @@ type ImageProps = {
10
9
  onClick: (e: any) => void
11
10
  }
12
11
 
12
+ export function checkImageLoad(img: HTMLImageElement) {
13
+ var isLoaded = img.complete && img.naturalHeight !== 0;
14
+ if (isLoaded) {
15
+ if (!img.classList.contains("wy-loading")) {
16
+ console.debug("image is instantly loaded")
17
+ img.classList.add("wy-loading", "wy-loaded");
18
+ } else {
19
+ img.decode().then(() => {
20
+ console.debug("image is loaded after delay")
21
+ img.classList.add("wy-loaded");
22
+ })
23
+ }
24
+
25
+
26
+ } else {
27
+ console.debug("image is loading")
28
+ img.classList.add("wy-loading");
29
+ }
30
+ }
31
+
32
+ export function imageLoaded(event: any) {
33
+ var img = event.target;
34
+ if (img.tagName === 'IMG' && img.classList.contains("wy-loading") && !img.classList.contains("wy-loaded")) {
35
+ console.debug("load event"); img.classList.add("wy-loaded")
36
+ }
37
+ }
38
+
13
39
  export const Image = ({src, previewSrc, width, height, more, onClick}: ImageProps) => {
14
40
  let ratio = width / height;
15
41
  let baseSize = 64;
@@ -20,17 +46,23 @@ export const Image = ({src, previewSrc, width, height, more, onClick}: ImageProp
20
46
  let intrinsicWidth = width + "px"
21
47
  let maxWidth = (maxScale * width) + "px";
22
48
 
49
+ const imageRef = useCallback((element: HTMLImageElement) => {
50
+ if (element) {
51
+ checkImageLoad(element);
52
+ }
53
+ }, [])
54
+
23
55
  return (
24
- <a href={src} className={wy('image')} onClick={(e) => onClick(e)} style={{
56
+ <a href={src} className="wy-image" onClick={(e) => onClick(e)} style={{
25
57
  flexBasis: flexBasis,
26
58
  flexGrow: flexRatio,
27
59
  flexShrink: flexRatio,
28
60
  width: intrinsicWidth,
29
61
  maxWidth: maxWidth
30
62
  }}>
31
- <div className={wy('image-area')} style={{ paddingBottom: padding}}>
32
- <img src={previewSrc} alt="" loading="lazy" decoding="async" />
33
- {!!more && <span className={wy('more')}>+{more}</span>}
63
+ <div className="wy-image-area" style={{ paddingBottom: padding }}>
64
+ <img ref={imageRef} src={previewSrc} onLoad={imageLoaded} alt="" loading="lazy" decoding="async" />
65
+ {!!more && <span className="wy-more">+{more}</span>}
34
66
  </div>
35
67
  </a>
36
68
  );
@@ -57,7 +89,7 @@ export const ImageGrid = ({ children, limit = 3}: ImageGridProps) => {
57
89
  }
58
90
 
59
91
  return (
60
- <div className={wy('image-grid')}>
92
+ <div className="wy-image-grid">
61
93
  {firstImages}
62
94
  </div>
63
95
  );
@@ -1,7 +1,6 @@
1
1
  import React from "react";
2
2
  import Button from '../ui/Button';
3
3
  import Icon from '../ui/Icon';
4
- import { prefix as wy } from "../utils/styles";
5
4
 
6
5
  type Props = {
7
6
  meeting: MeetingCardType
@@ -14,13 +13,13 @@ const MeetingCard = ({ meeting }: Props) => {
14
13
  }
15
14
 
16
15
  return (
17
- <div className={wy('attachments')}>
18
- <a className={wy('attachment')} href={meeting.join_url} target="_blank">
19
- <div className={wy('attachment-icon')} title="Zoom meeting"><Icon.UI name="zoom" color="#4a8cff" size={4} /></div>
20
- <div className={wy('attachment-content')}>
21
- <div className={wy('attachment-title')}>Zoom meeting</div>
22
- <div className={wy('attachment-meta')}>Meeting ID: {`${meeting.provider_id.substring(0,3)}-${meeting.provider_id.substring(3,6)}-${meeting.provider_id.substring(6)}`}</div>
23
- <Button.UI className={wy('button-primary')}>Join meeting</Button.UI>
16
+ <div className="wy-attachments">
17
+ <a className="wy-attachment" href={meeting.join_url} target="_blank">
18
+ <div className="wy-attachment-icon" title="Zoom meeting"><Icon.UI name="zoom" color="#4a8cff" size={4} /></div>
19
+ <div className="wy-attachment-content">
20
+ <div className="wy-attachment-title">Zoom meeting</div>
21
+ <div className="wy-attachment-meta">Meeting ID: {`${meeting.provider_id.substring(0,3)}-${meeting.provider_id.substring(3,6)}-${meeting.provider_id.substring(6)}`}</div>
22
+ <Button.UI className="wy-button-primary">Join meeting</Button.UI>
24
23
  </div>
25
24
  </a>
26
25
  </div>
@@ -9,13 +9,12 @@ import SeenBy from './SeenBy';
9
9
  import Avatar from "./Avatar";
10
10
  import MeetingCard from './MeetingCard';
11
11
  import usePreview from '../hooks/usePreview';
12
- import { prefix as wy } from "../utils/styles";
12
+ import classNames from 'classnames';
13
13
 
14
14
  const Message: FC<MessageProps> = ({ id, html, temp, me, avatar, name, created_at, attachments, meeting, parentId, reactions, seenBy }) => {
15
15
 
16
16
  const { open, close } = usePreview(attachments);
17
17
 
18
- var messageClassName = wy("message" + (me ? " message-me" : ""));
19
18
  var images = attachments?.filter((a: AttachmentType) => a.kind === "image" && a.thumbnail_url);
20
19
  var files = attachments?.filter((a: AttachmentType) => a.kind !== "image" || !a.thumbnail_url);
21
20
 
@@ -28,20 +27,20 @@ const Message: FC<MessageProps> = ({ id, html, temp, me, avatar, name, created_a
28
27
 
29
28
  return (
30
29
  <>
31
- <div className={messageClassName}>
30
+ <div className={classNames("wy-message", { "wy-message-me": me })}>
32
31
  {!me && (
33
- <div className={wy('message-author')}>
32
+ <div className="wy-message-author">
34
33
  {avatar && <Avatar src={avatar} size={32} name={name} />}
35
34
  </div>
36
35
  )}
37
- <div className={wy('message-content')}>
38
- <div className={wy('message-meta')}>
36
+ <div className="wy-message-content">
37
+ <div className="wy-message-meta">
39
38
  <time dateTime={created_at} title={date.format('LLLL')}>{date.fromNow()}</time>
40
39
  </div>
41
- <div className={wy('message-content-row')}>
42
- <div className={wy('message-bubble')}>
40
+ <div className="wy-message-content-row">
41
+ <div className="wy-message-bubble">
43
42
  {temp &&
44
- <div className={wy('message-text')}>{html}</div>
43
+ <div className="wy-message-text">{html}</div>
45
44
  }
46
45
  {!temp &&
47
46
  <>
@@ -51,13 +50,13 @@ const Message: FC<MessageProps> = ({ id, html, temp, me, avatar, name, created_a
51
50
  )}
52
51
  </ImageGrid>}
53
52
 
54
- {html && <div className={wy('message-text')} dangerouslySetInnerHTML={{ __html: joypixels.shortnameToUnicode(html || "") }}></div>}
53
+ {html && <div className="wy-message-text" dangerouslySetInnerHTML={{ __html: joypixels.shortnameToUnicode(html || "") }}></div>}
55
54
 
56
55
  {meeting &&
57
56
  <MeetingCard meeting={meeting} />
58
57
  }
59
58
 
60
- {files && !!files.length && <div className={wy('attachments')}>
59
+ {files && !!files.length && <div className="wy-attachments">
61
60
  {files.map((a: AttachmentType) =>
62
61
  <Attachment key={a.id} name={a.name} previewFormat={a.kind} provider={a.provider} url={a.download_url} previewUrl={a.provider ? a.external_url : a.preview_url} mediaType={a.media_type} kind={a.kind} size={a.size} />
63
62
  )}
@@ -66,13 +65,13 @@ const Message: FC<MessageProps> = ({ id, html, temp, me, avatar, name, created_a
66
65
 
67
66
  }
68
67
  </div>
69
- <div className={wy('message-buttons')}>
68
+ <div className="wy-message-buttons">
70
69
  {!temp && <ReactionsMenu id={id} reactions={reactions} />}
71
70
  </div>
72
71
  </div>
73
72
 
74
73
  {!temp && (
75
- <div className={wy('reactions')}>
74
+ <div className="wy-reactions">
76
75
  <ReactionsList id={id} parentId={parentId} reactions={reactions} />
77
76
  </div>
78
77
  )}
@@ -11,7 +11,6 @@ import useMutateRead from '../hooks/useMutateRead';
11
11
  import useMutateMessage from '../hooks/useMutateMessage';
12
12
  import { useQueryClient } from 'react-query';
13
13
  import { WeavyContext } from '../contexts/WeavyContext';
14
- import { prefix as wy } from "../utils/styles";
15
14
  import Avatar from './Avatar';
16
15
 
17
16
  type Props = {
@@ -94,30 +93,31 @@ const Messages = ({ id, members, displayName, avatarUrl }: Props) => {
94
93
  // mark conversation as read
95
94
  readMessageMutation.mutate({ id: id, read: true })
96
95
 
97
- client.subscribe(`a${id}`, "message-inserted", handleRealtimeMessage);
98
- client.subscribe(`a${id}`, "conversation-read", handleRealtimeSeenBy);
99
- client.subscribe(`a${id}`, "reaction-inserted", handleRealtimeReactionInserted);
100
- client.subscribe(`a${id}`, "reaction-deleted", handleRealtimeReactionDeleted);
96
+ client?.subscribe(`a${id}`, "message-inserted", handleRealtimeMessage);
97
+ client?.subscribe(`a${id}`, "conversation-read", handleRealtimeSeenBy);
98
+ client?.subscribe(`a${id}`, "reaction-inserted", handleRealtimeReactionInserted);
99
+ client?.subscribe(`a${id}`, "reaction-deleted", handleRealtimeReactionDeleted);
101
100
  }
102
101
 
103
102
  return () => {
104
103
  window.removeEventListener('focus', handleFocus, false)
105
104
 
106
105
  if (id) {
107
-
108
106
  // remove additional pages in cache. Only get first page
109
107
  let qd = queryClient.getQueryData(["messages", id]);
108
+
110
109
  if (qd) {
110
+
111
111
  queryClient.setQueryData(["messages", id], (data: any) => ({
112
- pages: data?.pages.splice(0, 1),
113
- pageParams: data?.pageParams.splice(0, 1),
114
- }));
112
+ pages: data?.pages.slice(0,1),
113
+ pageParams: [undefined]
114
+ }));
115
115
  }
116
116
 
117
- client.unsubscribe(`a${id}`, "message-inserted", handleRealtimeMessage);
118
- client.unsubscribe(`a${id}`, "conversation-read", handleRealtimeSeenBy);
119
- client.unsubscribe(`a${id}`, "reaction-inserted", handleRealtimeReactionInserted);
120
- client.unsubscribe(`a${id}`, "reaction-deleted", handleRealtimeReactionDeleted);
117
+ client?.unsubscribe(`a${id}`, "message-inserted", handleRealtimeMessage);
118
+ client?.unsubscribe(`a${id}`, "conversation-read", handleRealtimeSeenBy);
119
+ client?.unsubscribe(`a${id}`, "reaction-inserted", handleRealtimeReactionInserted);
120
+ client?.unsubscribe(`a${id}`, "reaction-deleted", handleRealtimeReactionDeleted);
121
121
  }
122
122
  }
123
123
  }, [id]);
@@ -197,16 +197,16 @@ const Messages = ({ id, members, displayName, avatarUrl }: Props) => {
197
197
  readMessageMutation.mutate({ id: id, read: true })
198
198
  }, [id]);
199
199
 
200
- let messageHeader = <div className={wy('avatar-header')}>
200
+ let messageHeader = <div className="wy-avatar-header">
201
201
  {avatarUrl && displayName && <Avatar src={avatarUrl} name={displayName} id={id} size={128} /> || ''}
202
- {displayName && <div className={wy('avatar-display-name')}>{displayName}</div> || ''}
202
+ {displayName && <div className="wy-avatar-display-name">{displayName}</div> || ''}
203
203
  </div>;
204
204
 
205
- let loadMoreButton = <Button.UI onClick={() => fetchNextPage()} disabled={!hasNextPage || isFetchingNextPage} className={wy('message-readmore')}>Load more</Button.UI>;
205
+ let loadMoreButton = <Button.UI onClick={() => fetchNextPage()} disabled={!hasNextPage || isFetchingNextPage} className="wy-message-readmore">Load more</Button.UI>;
206
206
 
207
207
  let messages = (
208
208
  <>
209
- <div className={wy('message-readmore')} ref={readMoreRef}>
209
+ <div className="wy-message-readmore" ref={readMoreRef}>
210
210
  {isFetchingNextPage
211
211
  ? 'Loading more...'
212
212
  : hasNextPage
@@ -257,10 +257,10 @@ const Messages = ({ id, members, displayName, avatarUrl }: Props) => {
257
257
 
258
258
  return (
259
259
  <>
260
- <div id="container" className={wy('messages')}>
260
+ <div id="container" className="wy-messages">
261
261
  {messages}
262
262
  </div>
263
- <div className={wy('message-editor')}>
263
+ <div className="wy-message-editor">
264
264
  <ConversationForm key={id} conversationId={id} handleInsert={handleNewMessage} />
265
265
  </div>
266
266
  </>
@@ -4,9 +4,8 @@ import Conversation from './Conversation';
4
4
  import ConversationList from './ConversationList';
5
5
  import { Messenger } from '../types/Messenger';
6
6
  import { WeavyContext } from '../contexts/WeavyContext';
7
- import { prefix as wy } from "../utils/styles";
8
7
 
9
- const Messenger: FC<Messenger> = ({ options }) => {
8
+ const Messenger: FC<Messenger> = () => {
10
9
 
11
10
  const { client } = useContext(WeavyContext);
12
11
 
@@ -15,14 +14,14 @@ const Messenger: FC<Messenger> = ({ options }) => {
15
14
  }
16
15
 
17
16
  return (
18
- <MessengerProvider options={options}>
19
- <div className={wy('messenger-provider')}>
17
+ <MessengerProvider>
18
+ <div className="wy-messenger-provider">
20
19
 
21
- <div className={wy('messenger-sidebar')}>
20
+ <div className="wy-messenger-sidebar wy-scroll-y">
22
21
  <ConversationList />
23
22
  </div>
24
23
 
25
- <div className={wy('messenger-conversation')}>
24
+ <div className="wy-messenger-conversation wy-scroll-y">
26
25
  <Conversation id={null} />
27
26
  </div>
28
27
  </div>
@@ -4,7 +4,6 @@ import Icon from '../ui/Icon';
4
4
  import Overlay from '../ui/Overlay';
5
5
  import Button from '../ui/Button';
6
6
  import SearchUsers from './SearchUsers';
7
- import { prefix as wy } from "../utils/styles";
8
7
 
9
8
  const NewConversation = () => {
10
9
  const [modalOpen, setModalOpen] = useState(false);
@@ -27,18 +26,17 @@ const NewConversation = () => {
27
26
 
28
27
  return (
29
28
  <>
30
-
31
29
  <Button.UI onClick={handleOpen}><Icon.UI name="plus" /></Button.UI>
32
30
 
33
- <Overlay.UI isOpen={modalOpen} className={wy('modal')}>
34
- <header className={wy('appbars')}>
35
- <nav className={wy('appbar')}>
31
+ <Overlay.UI isOpen={modalOpen} className="wy-modal">
32
+ <header className="wy-appbars">
33
+ <nav className="wy-appbar">
36
34
  <Button.UI onClick={handleClose}><Icon.UI name='close' /></Button.UI>
37
- <div className={wy('appbar-text')}>Create conversation</div>
35
+ <div className="wy-appbar-text">Create conversation</div>
38
36
  </nav>
39
37
  </header>
40
38
 
41
- <SearchUsers handleSubmit={handleCreate} buttonTitle="Create conversation"/>
39
+ <SearchUsers handleSubmit={handleCreate} buttonTitle="Next"/>
42
40
  </Overlay.UI>
43
41
  </>
44
42