@weavy/uikit-react 11.1.0 → 13.0.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 (256) hide show
  1. package/.github/workflows/publish.yml +1 -1
  2. package/README.md +3 -4
  3. package/changelog.md +57 -0
  4. package/dist/cjs/index.js +28 -6
  5. package/dist/cjs/index.js.map +1 -1
  6. package/dist/cjs/types/client/WeavyClient.d.ts +8 -1
  7. package/dist/cjs/types/components/Attachment.d.ts +2 -1
  8. package/dist/cjs/types/components/Chat.d.ts +1 -1
  9. package/dist/cjs/types/components/Image.d.ts +2 -0
  10. package/dist/cjs/types/components/PdfViewer.d.ts +8 -0
  11. package/dist/cjs/types/components/Preview.d.ts +56 -0
  12. package/dist/cjs/types/contexts/MessengerContext.d.ts +1 -2
  13. package/dist/cjs/types/contexts/PreviewContext.d.ts +2 -1
  14. package/dist/cjs/types/contexts/WeavyContext.d.ts +2 -3
  15. package/dist/cjs/types/types/Chat.d.ts +1 -1
  16. package/dist/cjs/types/types/Messenger.d.ts +0 -1
  17. package/dist/cjs/types/types/types.d.ts +18 -8
  18. package/dist/cjs/types/ui/Spinner.d.ts +9 -0
  19. package/dist/cjs/types/utils/fileUtilities.d.ts +13 -1
  20. package/dist/css/weavy-chat.css +2860 -0
  21. package/dist/css/weavy-messenger.css +3217 -0
  22. package/dist/css/weavy.css +3217 -0
  23. package/dist/esm/index.js +28 -6
  24. package/dist/esm/index.js.map +1 -1
  25. package/dist/esm/types/client/WeavyClient.d.ts +8 -1
  26. package/dist/esm/types/components/Attachment.d.ts +2 -1
  27. package/dist/esm/types/components/Chat.d.ts +1 -1
  28. package/dist/esm/types/components/Image.d.ts +2 -0
  29. package/dist/esm/types/components/PdfViewer.d.ts +8 -0
  30. package/dist/esm/types/components/Preview.d.ts +56 -0
  31. package/dist/esm/types/contexts/MessengerContext.d.ts +1 -2
  32. package/dist/esm/types/contexts/PreviewContext.d.ts +2 -1
  33. package/dist/esm/types/contexts/WeavyContext.d.ts +2 -3
  34. package/dist/esm/types/types/Chat.d.ts +1 -1
  35. package/dist/esm/types/types/Messenger.d.ts +0 -1
  36. package/dist/esm/types/types/types.d.ts +18 -8
  37. package/dist/esm/types/ui/Spinner.d.ts +9 -0
  38. package/dist/esm/types/utils/fileUtilities.d.ts +13 -1
  39. package/dist/index.d.ts +15 -9
  40. package/package.json +14 -4
  41. package/rollup.config.js +3 -3
  42. package/src/client/WeavyClient.ts +105 -24
  43. package/src/components/Attachment.tsx +8 -8
  44. package/src/components/Avatar.tsx +2 -3
  45. package/src/components/Chat.tsx +13 -17
  46. package/src/components/Conversation.tsx +23 -32
  47. package/src/components/ConversationBadge.tsx +1 -2
  48. package/src/components/ConversationForm.tsx +11 -18
  49. package/src/components/ConversationList.tsx +4 -5
  50. package/src/components/ConversationListItem.tsx +11 -13
  51. package/src/components/FileBrowser.tsx +2 -3
  52. package/src/components/Image.tsx +39 -7
  53. package/src/components/MeetingCard.tsx +7 -8
  54. package/src/components/Message.tsx +13 -14
  55. package/src/components/Messages.tsx +7 -8
  56. package/src/components/Messenger.tsx +5 -6
  57. package/src/components/NewConversation.tsx +5 -7
  58. package/src/components/PdfViewer.tsx +276 -0
  59. package/src/components/Presence.tsx +2 -2
  60. package/src/components/Preview.tsx +355 -0
  61. package/src/components/Reactions.tsx +8 -8
  62. package/src/components/SearchUsers.tsx +19 -18
  63. package/src/components/SeenBy.tsx +1 -2
  64. package/src/contexts/MessengerContext.tsx +4 -12
  65. package/src/contexts/PreviewContext.tsx +89 -17
  66. package/src/contexts/WeavyContext.tsx +15 -5
  67. package/src/hooks/useBadge.ts +2 -6
  68. package/src/hooks/useChat.ts +3 -14
  69. package/src/hooks/useConversation.ts +1 -8
  70. package/src/hooks/useConversations.ts +1 -7
  71. package/src/hooks/useFileUploader.ts +6 -8
  72. package/src/hooks/useMembers.ts +1 -7
  73. package/src/hooks/useMessages.ts +1 -7
  74. package/src/hooks/useMutateChat.ts +6 -11
  75. package/src/hooks/useMutateConversation.ts +7 -10
  76. package/src/hooks/useMutateConversationName.ts +10 -12
  77. package/src/hooks/useMutateDeleteReaction.ts +3 -8
  78. package/src/hooks/useMutateExternalBlobs.ts +6 -11
  79. package/src/hooks/useMutateMeeting.ts +6 -11
  80. package/src/hooks/useMutateMembers.ts +8 -13
  81. package/src/hooks/useMutateMessage.ts +10 -15
  82. package/src/hooks/useMutatePinned.ts +3 -8
  83. package/src/hooks/useMutateReaction.ts +6 -12
  84. package/src/hooks/useMutateRead.ts +1 -10
  85. package/src/hooks/useMutateRemoveMembers.ts +7 -12
  86. package/src/hooks/useMutateTyping.ts +6 -11
  87. package/src/hooks/usePresence.ts +4 -5
  88. package/src/hooks/useReactions.ts +0 -1
  89. package/src/hooks/useSearchUsers.ts +1 -6
  90. package/src/hooks/useUser.ts +3 -14
  91. package/src/index.ts +2 -2
  92. package/src/scss/theme/_alert.scss +73 -0
  93. package/src/scss/theme/_appbar.scss +114 -0
  94. package/src/scss/theme/_attachments.scss +74 -0
  95. package/src/scss/theme/_avatar.scss +54 -0
  96. package/src/scss/theme/_badge.scss +47 -0
  97. package/src/scss/theme/_buttons.scss +96 -0
  98. package/src/scss/theme/_card.scss +7 -0
  99. package/src/scss/theme/_checkbox.scss +56 -0
  100. package/src/scss/theme/_cm-editor.scss +42 -0
  101. package/src/scss/theme/_code-vscode-dark.scss +184 -0
  102. package/src/scss/theme/_code-vscode-light.scss +179 -0
  103. package/src/scss/theme/_code.scss +12 -0
  104. package/src/scss/theme/_colors.scss +520 -0
  105. package/src/scss/theme/_config.scss +6 -0
  106. package/src/scss/theme/_content.scss +15 -0
  107. package/src/scss/theme/_conversations.scss +91 -0
  108. package/src/scss/theme/_dropdown.scss +86 -0
  109. package/src/scss/theme/_emoji.scss +5 -0
  110. package/src/scss/theme/_filebrowser.scss +26 -0
  111. package/src/scss/theme/_files.scss +140 -0
  112. package/src/scss/theme/_icons.scss +62 -0
  113. package/src/scss/theme/_image-grid.scss +63 -0
  114. package/src/scss/theme/_inputs.scss +28 -0
  115. package/src/scss/theme/_message-editor.scss +90 -0
  116. package/src/scss/theme/_messages.scss +238 -0
  117. package/src/scss/theme/_nav.scss +52 -0
  118. package/src/scss/theme/_overlays.scss +157 -0
  119. package/src/scss/theme/_pager.scss +19 -0
  120. package/src/scss/theme/_palette.scss +165 -0
  121. package/src/scss/theme/_pane.scss +16 -0
  122. package/src/scss/theme/_panels.scss +141 -0
  123. package/src/scss/theme/_picker-list.scss +37 -0
  124. package/src/scss/theme/_preview-code.scss +5 -0
  125. package/src/scss/theme/_preview-embed.scss +38 -0
  126. package/src/scss/theme/_preview-html.scss +7 -0
  127. package/src/scss/theme/_preview-icon.scss +41 -0
  128. package/src/scss/theme/_preview-image.scss +86 -0
  129. package/src/scss/theme/_preview-media.scss +28 -0
  130. package/src/scss/theme/_preview-pdf.scss +838 -0
  131. package/src/scss/theme/_preview-text.scss +5 -0
  132. package/src/scss/theme/_preview.scss +110 -0
  133. package/src/scss/theme/_reactions.scss +58 -0
  134. package/src/scss/theme/_reboot.scss +41 -0
  135. package/src/scss/theme/_root.scss +2 -0
  136. package/src/scss/theme/_scroll.scss +55 -0
  137. package/src/scss/theme/_search.scss +68 -0
  138. package/src/scss/theme/_spinner.scss +63 -0
  139. package/src/scss/theme/_tables.scss +53 -0
  140. package/src/scss/theme/_toasts.scss +47 -0
  141. package/src/scss/theme/_turbo.scss +17 -0
  142. package/src/scss/theme/_typing.scss +26 -0
  143. package/src/scss/theme/_variables.scss +139 -0
  144. package/src/scss/theme/bootstrap/_accordion.scss +146 -0
  145. package/src/scss/theme/bootstrap/_alert.scss +71 -0
  146. package/src/scss/theme/bootstrap/_badge.scss +38 -0
  147. package/src/scss/theme/bootstrap/_breadcrumb.scss +40 -0
  148. package/src/scss/theme/bootstrap/_button-group.scss +142 -0
  149. package/src/scss/theme/bootstrap/_buttons.scss +186 -0
  150. package/src/scss/theme/bootstrap/_card.scss +234 -0
  151. package/src/scss/theme/bootstrap/_carousel.scss +229 -0
  152. package/src/scss/theme/bootstrap/_close.scss +40 -0
  153. package/src/scss/theme/bootstrap/_containers.scss +41 -0
  154. package/src/scss/theme/bootstrap/_dropdown.scss +248 -0
  155. package/src/scss/theme/bootstrap/_forms.scss +9 -0
  156. package/src/scss/theme/bootstrap/_functions.scss +302 -0
  157. package/src/scss/theme/bootstrap/_grid.scss +33 -0
  158. package/src/scss/theme/bootstrap/_helpers.scss +10 -0
  159. package/src/scss/theme/bootstrap/_images.scss +42 -0
  160. package/src/scss/theme/bootstrap/_list-group.scss +191 -0
  161. package/src/scss/theme/bootstrap/_maps.scss +54 -0
  162. package/src/scss/theme/bootstrap/_mixins.scss +43 -0
  163. package/src/scss/theme/bootstrap/_modal.scss +237 -0
  164. package/src/scss/theme/bootstrap/_nav.scss +172 -0
  165. package/src/scss/theme/bootstrap/_navbar.scss +276 -0
  166. package/src/scss/theme/bootstrap/_offcanvas.scss +143 -0
  167. package/src/scss/theme/bootstrap/_pagination.scss +109 -0
  168. package/src/scss/theme/bootstrap/_placeholders.scss +51 -0
  169. package/src/scss/theme/bootstrap/_popover.scss +196 -0
  170. package/src/scss/theme/bootstrap/_progress.scss +59 -0
  171. package/src/scss/theme/bootstrap/_reboot.scss +610 -0
  172. package/src/scss/theme/bootstrap/_root.scss +73 -0
  173. package/src/scss/theme/bootstrap/_spinners.scss +85 -0
  174. package/src/scss/theme/bootstrap/_tables.scss +164 -0
  175. package/src/scss/theme/bootstrap/_toasts.scss +70 -0
  176. package/src/scss/theme/bootstrap/_tooltip.scss +120 -0
  177. package/src/scss/theme/bootstrap/_transitions.scss +27 -0
  178. package/src/scss/theme/bootstrap/_type.scss +106 -0
  179. package/src/scss/theme/bootstrap/_utilities.scss +647 -0
  180. package/src/scss/theme/bootstrap/_variables.scss +1633 -0
  181. package/src/scss/theme/bootstrap/forms/_floating-labels.scss +74 -0
  182. package/src/scss/theme/bootstrap/forms/_form-check.scss +175 -0
  183. package/src/scss/theme/bootstrap/forms/_form-control.scss +194 -0
  184. package/src/scss/theme/bootstrap/forms/_form-range.scss +91 -0
  185. package/src/scss/theme/bootstrap/forms/_form-select.scss +71 -0
  186. package/src/scss/theme/bootstrap/forms/_form-text.scss +11 -0
  187. package/src/scss/theme/bootstrap/forms/_input-group.scss +129 -0
  188. package/src/scss/theme/bootstrap/forms/_labels.scss +36 -0
  189. package/src/scss/theme/bootstrap/forms/_validation.scss +12 -0
  190. package/src/scss/theme/bootstrap/helpers/_clearfix.scss +3 -0
  191. package/src/scss/theme/bootstrap/helpers/_color-bg.scss +10 -0
  192. package/src/scss/theme/bootstrap/helpers/_colored-links.scss +12 -0
  193. package/src/scss/theme/bootstrap/helpers/_position.scss +36 -0
  194. package/src/scss/theme/bootstrap/helpers/_ratio.scss +26 -0
  195. package/src/scss/theme/bootstrap/helpers/_stacks.scss +15 -0
  196. package/src/scss/theme/bootstrap/helpers/_stretched-link.scss +15 -0
  197. package/src/scss/theme/bootstrap/helpers/_text-truncation.scss +7 -0
  198. package/src/scss/theme/bootstrap/helpers/_visually-hidden.scss +8 -0
  199. package/src/scss/theme/bootstrap/helpers/_vr.scss +8 -0
  200. package/src/scss/theme/bootstrap/mixins/_alert.scss +15 -0
  201. package/src/scss/theme/bootstrap/mixins/_backdrop.scss +14 -0
  202. package/src/scss/theme/bootstrap/mixins/_banner.scss +9 -0
  203. package/src/scss/theme/bootstrap/mixins/_border-radius.scss +78 -0
  204. package/src/scss/theme/bootstrap/mixins/_box-shadow.scss +18 -0
  205. package/src/scss/theme/bootstrap/mixins/_breakpoints.scss +127 -0
  206. package/src/scss/theme/bootstrap/mixins/_buttons.scss +70 -0
  207. package/src/scss/theme/bootstrap/mixins/_caret.scss +64 -0
  208. package/src/scss/theme/bootstrap/mixins/_clearfix.scss +9 -0
  209. package/src/scss/theme/bootstrap/mixins/_color-scheme.scss +7 -0
  210. package/src/scss/theme/bootstrap/mixins/_container.scss +11 -0
  211. package/src/scss/theme/bootstrap/mixins/_deprecate.scss +10 -0
  212. package/src/scss/theme/bootstrap/mixins/_forms.scss +152 -0
  213. package/src/scss/theme/bootstrap/mixins/_gradients.scss +47 -0
  214. package/src/scss/theme/bootstrap/mixins/_grid.scss +151 -0
  215. package/src/scss/theme/bootstrap/mixins/_image.scss +16 -0
  216. package/src/scss/theme/bootstrap/mixins/_list-group.scss +24 -0
  217. package/src/scss/theme/bootstrap/mixins/_lists.scss +7 -0
  218. package/src/scss/theme/bootstrap/mixins/_pagination.scss +10 -0
  219. package/src/scss/theme/bootstrap/mixins/_reset-text.scss +17 -0
  220. package/src/scss/theme/bootstrap/mixins/_resize.scss +6 -0
  221. package/src/scss/theme/bootstrap/mixins/_table-variants.scss +24 -0
  222. package/src/scss/theme/bootstrap/mixins/_text-truncate.scss +8 -0
  223. package/src/scss/theme/bootstrap/mixins/_transition.scss +26 -0
  224. package/src/scss/theme/bootstrap/mixins/_utilities.scss +97 -0
  225. package/src/scss/theme/bootstrap/mixins/_visually-hidden.scss +29 -0
  226. package/src/scss/theme/bootstrap/utilities/_api.scss +47 -0
  227. package/src/scss/theme/bootstrap/vendor/_rfs.scss +354 -0
  228. package/src/scss/theme/bs/_badge.scss +20 -0
  229. package/src/scss/theme/bs/_buttons.scss +185 -0
  230. package/src/scss/theme/bs/_dropdown.scss +86 -0
  231. package/src/scss/theme/bs/_forms.scss +161 -0
  232. package/src/scss/theme/bs/_list-group.scss +73 -0
  233. package/src/scss/theme/bs/_tables.scss +46 -0
  234. package/src/scss/theme/fonts/_fontmapping-roboto.scss +129 -0
  235. package/src/scss/theme/fonts/_fontmapping-segoe-ui.scss +127 -0
  236. package/src/scss/theme/fonts/_index.scss +2 -0
  237. package/src/scss/theme/mixins/_backdrop.scss +13 -0
  238. package/src/scss/theme/mixins/_palette.scss +165 -0
  239. package/src/scss/theme/mixins/_position.scss +33 -0
  240. package/src/scss/theme/mixins/_scrollbar.scss +110 -0
  241. package/src/scss/weavy-chat.scss +32 -0
  242. package/src/scss/weavy-messenger.scss +61 -0
  243. package/src/scss/weavy.scss +2 -0
  244. package/src/types/Chat.ts +1 -1
  245. package/src/types/Messenger.ts +1 -1
  246. package/src/types/types.ts +20 -11
  247. package/src/ui/Button.tsx +3 -4
  248. package/src/ui/Dropdown.tsx +4 -5
  249. package/src/ui/Icon.tsx +75 -39
  250. package/src/ui/Overlay.tsx +2 -3
  251. package/src/ui/Spinner.tsx +18 -0
  252. package/src/utils/fileUtilities.ts +166 -72
  253. package/src/utils/scrollbarDetection.js +48 -0
  254. package/dist/cjs/types/utils/styles.d.ts +0 -17
  255. package/dist/esm/types/utils/styles.d.ts +0 -17
  256. package/src/utils/styles.ts +0 -42
@@ -6,9 +6,8 @@ import Messages from './Messages';
6
6
  import useMembers from '../hooks/useMembers';
7
7
  import Typing from './Typing';
8
8
  import useConversation from '../hooks/useConversation';
9
- import { prefix as wy } from "../utils/styles";
10
9
 
11
- const Chat = ({ id }: ChatProps) => {
10
+ const Chat = ({ uid }: ChatProps) => {
12
11
  const { client } = useContext(WeavyContext);
13
12
  const [selectedId, setSelectedId] = useState<number | null>(null)
14
13
 
@@ -16,7 +15,7 @@ const Chat = ({ id }: ChatProps) => {
16
15
  throw new Error('Weavy Chat component must be used within an WeavyProvider');
17
16
  }
18
17
 
19
- const { isLoading: isLoadingChat, data: dataChat } = useChat(id, {});
18
+ const { isLoading: isLoadingChat, data: dataChat } = useChat(uid, {});
20
19
 
21
20
  const { isLoading: isLoadingMembers, data: dataMembers } = useMembers(selectedId, {
22
21
  // The query will not execute until the activeConversation exists
@@ -37,31 +36,28 @@ const Chat = ({ id }: ChatProps) => {
37
36
  }, [dataChat]);
38
37
 
39
38
  return (
40
- <>
41
- <header className={wy('appbars')}>
42
- <nav className={wy('appbar')}>
43
-
39
+ <div className="wy-messenger-conversation wy-scroll-y">
40
+ <header className="wy-appbars">
41
+ <nav className="wy-appbar">
42
+ <div></div>
44
43
  {selectedId && dataConversation &&
45
-
46
- <>
47
- <div>
48
- <Typing id={selectedId} context="conversation">
49
- {dataConversation.display_name}
50
- </Typing>
51
- </div>
52
- </>
44
+ <div className="wy-appbar-text">
45
+ <Typing id={selectedId} context="conversation">
46
+ {dataConversation.display_name}
47
+ </Typing>
48
+ </div>
53
49
  }
54
50
  </nav>
55
51
  </header>
56
52
 
57
53
  {!isLoadingChat && !dataChat &&
58
- <div>No chat with the contextual id <strong>{id}</strong></div>
54
+ <div>No chat with the contextual id <strong>{uid}</strong></div>
59
55
  }
60
56
 
61
57
  {selectedId && dataMembers &&
62
58
  <Messages id={selectedId} members={dataMembers} />
63
59
  }
64
- </>
60
+ </div>
65
61
  )
66
62
  }
67
63
 
@@ -13,7 +13,6 @@ import SearchUsers from './SearchUsers';
13
13
  import useMutateMembers from '../hooks/useMutateMembers';
14
14
  import useConversation from '../hooks/useConversation';
15
15
  import useMutateConversationName from '../hooks/useMutateConversationName';
16
- import { prefix as wy } from "../utils/styles";
17
16
  import useMutateRemoveMembers from '../hooks/useMutateRemoveMembers';
18
17
  import Avatar from './Avatar';
19
18
  import { UserContext } from '../contexts/UserContext';
@@ -21,13 +20,12 @@ import Messages from './Messages';
21
20
 
22
21
  const Conversation = ({ id, showBackButton }: ConversationProps) => {
23
22
 
24
-
25
23
  const queryClient = useQueryClient();
26
24
  const { client } = useContext(WeavyContext);
27
25
  const { selectedConversationId, setSelectedConversationId } = useContext(MessengerContext);
28
26
  const { user } = useContext(UserContext);
29
27
  const [modalAddOpen, setModalAddOpen] = useState(false);
30
- const [modalDetailsOpen, setModalDetailsOpen] = useState(false);
28
+ const [modalDetailsOpen, setModalDetailsOpen] = useState(false);
31
29
  const [title, setTitle] = useState<string>("");
32
30
 
33
31
  const ChatRoom = "edb400ac-839b-45a7-b2a8-6a01820d1c44";
@@ -85,10 +83,6 @@ const Conversation = ({ id, showBackButton }: ConversationProps) => {
85
83
  setSelectedConversationId(null);
86
84
  }
87
85
 
88
-
89
-
90
-
91
-
92
86
  // set selected conversation id if id is supplied to component
93
87
  useEffect(() => {
94
88
  if (id) {
@@ -117,13 +111,10 @@ const Conversation = ({ id, showBackButton }: ConversationProps) => {
117
111
  }
118
112
  }, [dataConversation]);
119
113
 
120
-
121
-
122
-
123
114
  return (
124
115
  <>
125
- <header className={wy('appbars')}>
126
- <nav className={wy('appbar')}>
116
+ <header className="wy-appbars">
117
+ <nav className="wy-appbar">
127
118
  <div>
128
119
  {showBackButton &&
129
120
  <Button.UI onClick={handleBack}><Icon.UI name="back" /></Button.UI>
@@ -131,7 +122,7 @@ const Conversation = ({ id, showBackButton }: ConversationProps) => {
131
122
  {selectedConversationId && dataConversation &&
132
123
 
133
124
  <>
134
- <div>
125
+ <div className="wy-appbar-text">
135
126
  <Typing id={selectedConversationId} context="conversation">
136
127
  {dataConversation.display_name}
137
128
  </Typing>
@@ -154,7 +145,7 @@ const Conversation = ({ id, showBackButton }: ConversationProps) => {
154
145
  </header>
155
146
 
156
147
  {!selectedConversationId &&
157
- <div className={wy('avatar-header')}>
148
+ <div className="wy-avatar-header">
158
149
  <Avatar src={user.avatar_url} name={user.title} presence={user.presence} id={user.id} size={256} />
159
150
  <h2>Welcome {user.name}!</h2>
160
151
  Create or select a conversation to get started
@@ -164,41 +155,41 @@ const Conversation = ({ id, showBackButton }: ConversationProps) => {
164
155
  <Messages id={selectedConversationId} members={dataMembers} displayName={dataConversation?.display_name} avatarUrl={dataConversation?.avatar_url} />
165
156
  }
166
157
 
167
- <Overlay.UI isOpen={modalAddOpen} className={wy('modal')}>
168
- <header className={wy('appbars')}>
169
- <nav className={wy('appbar')}>
158
+ <Overlay.UI isOpen={modalAddOpen} className="wy-modal">
159
+ <header className="wy-appbars">
160
+ <nav className="wy-appbar">
170
161
  <Button.UI onClick={() => toggleAddModal(false)}><Icon.UI name='close' /></Button.UI>
171
- <div className={wy('appbar-text')}>Add people</div>
162
+ <div className="wy-appbar-text">Add people</div>
172
163
  </nav>
173
164
  </header>
174
165
  <SearchUsers handleSubmit={handleAdd} buttonTitle="Add selected" />
175
166
  </Overlay.UI>
176
167
 
177
- <Overlay.UI isOpen={modalDetailsOpen} className={wy('modal')}>
178
- <header className={wy('appbars')}>
179
- <nav className={wy('appbar')}>
168
+ <Overlay.UI isOpen={modalDetailsOpen} className="wy-modal">
169
+ <header className="wy-appbars">
170
+ <nav className="wy-appbar">
180
171
  <Button.UI onClick={() => toggleDetailsModal(false)}><Icon.UI name='close' /></Button.UI>
181
- <div className={wy('appbar-text')}>Conversation details</div>
172
+ <div className="wy-appbar-text">Conversation details</div>
182
173
  </nav>
183
174
  </header>
184
175
  <div>
185
- {dataConversation && <div className={wy('avatar-header')}><Avatar src={dataConversation?.avatar_url} name={title} size={128} /></div>}
176
+ {dataConversation && <div className="wy-avatar-header"><Avatar src={dataConversation?.avatar_url} name={title} size={128} /></div>}
186
177
  {dataConversation?.type !== ChatRoom &&
187
- <h4 className={wy('avatar-display-name')}>{dataConversation?.display_name}</h4>
178
+ <h4 className="wy-avatar-display-name">{dataConversation?.display_name}</h4>
188
179
  }
189
180
 
190
181
  {dataConversation?.type === ChatRoom && (
191
182
  <>
192
- <div className={wy('pane-group')}>
193
- <input className={wy('input')} value={title} onChange={(e) => handleUpdateTitle(e)} />
183
+ <div className="wy-pane-group">
184
+ <input className="wy-input" value={title} onChange={(e) => handleUpdateTitle(e)} />
194
185
  </div>
195
- <div className={wy('pane-group')}>
196
- <table className={wy('search-result-table')}>
186
+ <div className="wy-pane-group">
187
+ <table className="wy-search-result-table">
197
188
  <tbody>
198
- {dataMembers?.data.map((m: MemberType) => {
189
+ {dataMembers && dataMembers.data && dataMembers.data.map((m: MemberType) => {
199
190
  return (
200
- <tr key={m.id} className={wy('search-result-table-checkbox')}>
201
- <td className={wy('search-result-table-icon')}><Avatar src={m.avatar_url} name={m.display_name} id={m.id} size={24} presence={m.presence} /></td>
191
+ <tr key={m.id} className="wy-search-result-table-checkbox">
192
+ <td className="wy-search-result-table-icon"><Avatar src={m.avatar_url} name={m.display_name} id={m.id} size={24} presence={m.presence} /></td>
202
193
  <td>{m.display_name}</td>
203
194
  <td></td>
204
195
  </tr>
@@ -212,7 +203,7 @@ const Conversation = ({ id, showBackButton }: ConversationProps) => {
212
203
  </div>
213
204
  </Overlay.UI>
214
205
 
215
-
206
+
216
207
  </>
217
208
  )
218
209
  }
@@ -1,7 +1,6 @@
1
1
  import React, { useContext, useEffect, useState } from "react";
2
2
  import { WeavyContext } from "../contexts/WeavyContext";
3
3
  import useBadge from "../hooks/useBadge";
4
- import { prefix as wy } from "../utils/styles";
5
4
 
6
5
  const ConversationBadge = () => {
7
6
  const { client } = useContext(WeavyContext);
@@ -34,7 +33,7 @@ const ConversationBadge = () => {
34
33
  return (
35
34
  <>
36
35
  {!isLoading && badge > 0 &&
37
- <span className={wy('badge badge-danger')}>{badge}</span>
36
+ <span className="wy-badge wy-badge-danger">{badge}</span>
38
37
  }
39
38
  </>
40
39
 
@@ -11,8 +11,6 @@ import Meetings from './Meetings';
11
11
  import Meeting from './Meeting';
12
12
  import FileBrowser from './FileBrowser';
13
13
  import { getIcon } from '../utils/fileUtilities';
14
- import { prefix as wy } from "../utils/styles";
15
-
16
14
 
17
15
  type Props = {
18
16
  conversationId: number,
@@ -46,13 +44,10 @@ const ConversationForm = ({ conversationId, handleInsert }: Props) => {
46
44
  setAttachments([...attachments, attachment[0]]);
47
45
  }
48
46
  })
49
-
50
-
51
47
  }
52
48
 
53
49
  const { mutateAsync: uploadFile, isSuccess: uploadSuccess } = useFileUploader(handleUploaded);
54
50
 
55
-
56
51
  useEffect(() => {
57
52
  // set stored text and attachments if available
58
53
  let textValue: any = queryClient.getQueryData(["form-text", conversationId]) || "";
@@ -71,8 +66,6 @@ const ConversationForm = ({ conversationId, handleInsert }: Props) => {
71
66
  handleAutoGrow();
72
67
  }, [text])
73
68
 
74
-
75
-
76
69
  const handleInsertMessage = (e: React.KeyboardEvent<EventTarget>) => {
77
70
 
78
71
  if(e.type === 'keydown' && !(e.key === "Enter" && e.ctrlKey )) return;
@@ -159,7 +152,7 @@ const ConversationForm = ({ conversationId, handleInsert }: Props) => {
159
152
 
160
153
 
161
154
  return (
162
- <form className={wy('message-form')}>
155
+ <form className="wy-message-form">
163
156
  {uploadError &&
164
157
  <div>{uploadError}</div>
165
158
  }
@@ -169,12 +162,12 @@ const ConversationForm = ({ conversationId, handleInsert }: Props) => {
169
162
  {working &&
170
163
  <div>Now uploading ({currentUploadCount} of {fileCount}) selected files</div>
171
164
  }
172
- <div className={wy('picker-list')}>
165
+ <div className="wy-picker-list">
173
166
  {attachments.map((a: FileType) => {
174
167
  let { icon } = getIcon(a.name);
175
168
  return (
176
- <div key={a.id} className={wy('picker-list-item')}>
177
- <File id={a.id} name={a.name} className={wy('picker-list-item-title')} icon={ icon } />
169
+ <div key={a.id} className="wy-picker-list-item">
170
+ <File id={a.id} name={a.name} className="wy-picker-list-item-title" icon={ icon } />
178
171
  <Button.UI onClick={handleRemoveFile.bind(ConversationForm, a.id)}><Icon.UI name='close-circle' /></Button.UI>
179
172
  </div>
180
173
 
@@ -183,8 +176,8 @@ const ConversationForm = ({ conversationId, handleInsert }: Props) => {
183
176
 
184
177
  {meetings.map((m: MeetingType) => {
185
178
  return (
186
- <div key={m.id} className={wy('picker-list-item')}>
187
- <Meeting id={m.id} title={m.provider} className={wy('picker-list-item-title')} />
179
+ <div key={m.id} className="wy-picker-list-item">
180
+ <Meeting id={m.id} title={m.provider} className="wy-picker-list-item-title" />
188
181
  <Button.UI onClick={handleRemoveMeeting.bind(ConversationForm, m.id)}><Icon.UI name='close-circle' /></Button.UI>
189
182
  </div>
190
183
 
@@ -193,19 +186,19 @@ const ConversationForm = ({ conversationId, handleInsert }: Props) => {
193
186
  </div>
194
187
  </div>
195
188
  }
196
- <div className={wy('message-editor-inputs')}>
189
+ <div className="wy-message-editor-inputs">
197
190
 
198
- <div className={wy('message-editor-buttons')}>
191
+ <div className="wy-message-editor-buttons">
199
192
  <input type="file" ref={input => fileInput = input} value={files} onChange={handleFileUpload} multiple hidden tabIndex={-1} />
200
193
  <Button.UI title="Upload attachment" onClick={openFileInput}><Icon.UI name="attachment" /></Button.UI>
201
194
  <Meetings onMeetingAdded={handleAddMeeting} />
202
195
  <FileBrowser onFileAdded={handleExternalFileAdded} />
203
196
  </div>
204
197
 
205
- <div className={wy('message-editor-text message-editor-grow')}>
206
- <textarea rows={1} ref={textInput} className={wy('message-editor-textfield message-editor-textcontent')} value={text} onChange={handleChange} onKeyDown={handleInsertMessage} onKeyPress={useThrottle(handleKeyPress, 4000)}></textarea>
198
+ <div className="wy-message-editor-text wy-message-editor-grow">
199
+ <textarea rows={1} ref={textInput} className="wy-message-editor-textfield wy-message-editor-textcontent" value={text} onChange={handleChange} onKeyDown={handleInsertMessage} onKeyPress={useThrottle(handleKeyPress, 4000)}></textarea>
207
200
  </div>
208
- <div className={wy('message-editor-buttons')}>
201
+ <div className="wy-message-editor-buttons">
209
202
  <Button.UI type="button" onClick={handleInsertMessage} ><Icon.UI name="send"/></Button.UI>
210
203
  </div>
211
204
  </div>
@@ -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
 
@@ -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,28 +50,28 @@ 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
- <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} />
61
+ <Attachment key={a.id} onClick={(e) => handlePreviewClick(e, 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
  )}
64
63
  </div>}
65
64
  </>
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
  )}