@weavy/uikit-react 11.2.0 → 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 (205) hide show
  1. package/.github/workflows/publish.yml +1 -1
  2. package/changelog.md +15 -0
  3. package/dist/cjs/index.js +6 -6
  4. package/dist/cjs/index.js.map +1 -1
  5. package/dist/cjs/types/components/Image.d.ts +2 -0
  6. package/dist/cjs/types/components/PdfViewer.d.ts +6 -0
  7. package/dist/cjs/types/components/Preview.d.ts +58 -0
  8. package/dist/cjs/types/types/types.d.ts +1 -0
  9. package/dist/cjs/types/utils/fileUtilities.d.ts +16 -1
  10. package/dist/css/weavy-chat.css +2684 -0
  11. package/dist/css/weavy-messenger.css +3039 -0
  12. package/dist/css/weavy.css +3039 -0
  13. package/dist/esm/index.js +6 -6
  14. package/dist/esm/index.js.map +1 -1
  15. package/dist/esm/types/components/Image.d.ts +2 -0
  16. package/dist/esm/types/components/PdfViewer.d.ts +6 -0
  17. package/dist/esm/types/components/Preview.d.ts +58 -0
  18. package/dist/esm/types/types/types.d.ts +1 -0
  19. package/dist/esm/types/utils/fileUtilities.d.ts +16 -1
  20. package/package.json +14 -4
  21. package/rollup.config.js +0 -2
  22. package/src/components/Attachment.tsx +5 -6
  23. package/src/components/Avatar.tsx +2 -3
  24. package/src/components/Chat.tsx +3 -4
  25. package/src/components/Conversation.tsx +20 -29
  26. package/src/components/ConversationBadge.tsx +1 -2
  27. package/src/components/ConversationForm.tsx +11 -18
  28. package/src/components/ConversationList.tsx +4 -5
  29. package/src/components/ConversationListItem.tsx +11 -13
  30. package/src/components/FileBrowser.tsx +1 -2
  31. package/src/components/Image.tsx +39 -7
  32. package/src/components/MeetingCard.tsx +7 -8
  33. package/src/components/Message.tsx +12 -13
  34. package/src/components/Messages.tsx +6 -7
  35. package/src/components/Messenger.tsx +3 -4
  36. package/src/components/NewConversation.tsx +5 -7
  37. package/src/components/PdfViewer.tsx +271 -0
  38. package/src/components/Presence.tsx +2 -2
  39. package/src/components/Preview.tsx +294 -0
  40. package/src/components/Reactions.tsx +6 -7
  41. package/src/components/SearchUsers.tsx +17 -16
  42. package/src/components/SeenBy.tsx +1 -2
  43. package/src/contexts/PreviewContext.tsx +4 -6
  44. package/src/hooks/useConversation.ts +0 -1
  45. package/src/hooks/usePresence.ts +4 -5
  46. package/src/hooks/useReactions.ts +0 -1
  47. package/src/scss/theme/_alert.scss +73 -0
  48. package/src/scss/theme/_appbar.scss +112 -0
  49. package/src/scss/theme/_attachments.scss +74 -0
  50. package/src/scss/theme/_avatar.scss +54 -0
  51. package/src/scss/theme/_badge.scss +47 -0
  52. package/src/scss/theme/_buttons.scss +96 -0
  53. package/src/scss/theme/_card.scss +7 -0
  54. package/src/scss/theme/_checkbox.scss +56 -0
  55. package/src/scss/theme/_cm-editor.scss +42 -0
  56. package/src/scss/theme/_code.scss +115 -0
  57. package/src/scss/theme/_colors.scss +520 -0
  58. package/src/scss/theme/_config.scss +6 -0
  59. package/src/scss/theme/_content.scss +15 -0
  60. package/src/scss/theme/_conversations.scss +91 -0
  61. package/src/scss/theme/_dropdown.scss +86 -0
  62. package/src/scss/theme/_emoji.scss +5 -0
  63. package/src/scss/theme/_filebrowser.scss +26 -0
  64. package/src/scss/theme/_files.scss +140 -0
  65. package/src/scss/theme/_icons.scss +62 -0
  66. package/src/scss/theme/_image-grid.scss +63 -0
  67. package/src/scss/theme/_inputs.scss +28 -0
  68. package/src/scss/theme/_message-editor.scss +90 -0
  69. package/src/scss/theme/_messages.scss +238 -0
  70. package/src/scss/theme/_nav.scss +52 -0
  71. package/src/scss/theme/_overlays.scss +157 -0
  72. package/src/scss/theme/_pager.scss +19 -0
  73. package/src/scss/theme/_palette.scss +165 -0
  74. package/src/scss/theme/_pane.scss +16 -0
  75. package/src/scss/theme/_panels.scss +137 -0
  76. package/src/scss/theme/_picker-list.scss +37 -0
  77. package/src/scss/theme/_preview-embed.scss +38 -0
  78. package/src/scss/theme/_preview-html.scss +7 -0
  79. package/src/scss/theme/_preview-icon.scss +41 -0
  80. package/src/scss/theme/_preview-image.scss +86 -0
  81. package/src/scss/theme/_preview-media.scss +28 -0
  82. package/src/scss/theme/_preview-pdf.scss +838 -0
  83. package/src/scss/theme/_preview-text.scss +5 -0
  84. package/src/scss/theme/_preview.scss +105 -0
  85. package/src/scss/theme/_reactions.scss +58 -0
  86. package/src/scss/theme/_reboot.scss +41 -0
  87. package/src/scss/theme/_root.scss +2 -0
  88. package/src/scss/theme/_scroll.scss +55 -0
  89. package/src/scss/theme/_search.scss +68 -0
  90. package/src/scss/theme/_spinner.scss +63 -0
  91. package/src/scss/theme/_tables.scss +53 -0
  92. package/src/scss/theme/_toasts.scss +47 -0
  93. package/src/scss/theme/_turbo.scss +17 -0
  94. package/src/scss/theme/_typing.scss +26 -0
  95. package/src/scss/theme/_variables.scss +139 -0
  96. package/src/scss/theme/bootstrap/_accordion.scss +146 -0
  97. package/src/scss/theme/bootstrap/_alert.scss +71 -0
  98. package/src/scss/theme/bootstrap/_badge.scss +38 -0
  99. package/src/scss/theme/bootstrap/_breadcrumb.scss +40 -0
  100. package/src/scss/theme/bootstrap/_button-group.scss +142 -0
  101. package/src/scss/theme/bootstrap/_buttons.scss +186 -0
  102. package/src/scss/theme/bootstrap/_card.scss +234 -0
  103. package/src/scss/theme/bootstrap/_carousel.scss +229 -0
  104. package/src/scss/theme/bootstrap/_close.scss +40 -0
  105. package/src/scss/theme/bootstrap/_containers.scss +41 -0
  106. package/src/scss/theme/bootstrap/_dropdown.scss +248 -0
  107. package/src/scss/theme/bootstrap/_forms.scss +9 -0
  108. package/src/scss/theme/bootstrap/_functions.scss +302 -0
  109. package/src/scss/theme/bootstrap/_grid.scss +33 -0
  110. package/src/scss/theme/bootstrap/_helpers.scss +10 -0
  111. package/src/scss/theme/bootstrap/_images.scss +42 -0
  112. package/src/scss/theme/bootstrap/_list-group.scss +191 -0
  113. package/src/scss/theme/bootstrap/_maps.scss +54 -0
  114. package/src/scss/theme/bootstrap/_mixins.scss +43 -0
  115. package/src/scss/theme/bootstrap/_modal.scss +237 -0
  116. package/src/scss/theme/bootstrap/_nav.scss +172 -0
  117. package/src/scss/theme/bootstrap/_navbar.scss +276 -0
  118. package/src/scss/theme/bootstrap/_offcanvas.scss +143 -0
  119. package/src/scss/theme/bootstrap/_pagination.scss +109 -0
  120. package/src/scss/theme/bootstrap/_placeholders.scss +51 -0
  121. package/src/scss/theme/bootstrap/_popover.scss +196 -0
  122. package/src/scss/theme/bootstrap/_progress.scss +59 -0
  123. package/src/scss/theme/bootstrap/_reboot.scss +610 -0
  124. package/src/scss/theme/bootstrap/_root.scss +73 -0
  125. package/src/scss/theme/bootstrap/_spinners.scss +85 -0
  126. package/src/scss/theme/bootstrap/_tables.scss +164 -0
  127. package/src/scss/theme/bootstrap/_toasts.scss +70 -0
  128. package/src/scss/theme/bootstrap/_tooltip.scss +120 -0
  129. package/src/scss/theme/bootstrap/_transitions.scss +27 -0
  130. package/src/scss/theme/bootstrap/_type.scss +106 -0
  131. package/src/scss/theme/bootstrap/_utilities.scss +647 -0
  132. package/src/scss/theme/bootstrap/_variables.scss +1633 -0
  133. package/src/scss/theme/bootstrap/forms/_floating-labels.scss +74 -0
  134. package/src/scss/theme/bootstrap/forms/_form-check.scss +175 -0
  135. package/src/scss/theme/bootstrap/forms/_form-control.scss +194 -0
  136. package/src/scss/theme/bootstrap/forms/_form-range.scss +91 -0
  137. package/src/scss/theme/bootstrap/forms/_form-select.scss +71 -0
  138. package/src/scss/theme/bootstrap/forms/_form-text.scss +11 -0
  139. package/src/scss/theme/bootstrap/forms/_input-group.scss +129 -0
  140. package/src/scss/theme/bootstrap/forms/_labels.scss +36 -0
  141. package/src/scss/theme/bootstrap/forms/_validation.scss +12 -0
  142. package/src/scss/theme/bootstrap/helpers/_clearfix.scss +3 -0
  143. package/src/scss/theme/bootstrap/helpers/_color-bg.scss +10 -0
  144. package/src/scss/theme/bootstrap/helpers/_colored-links.scss +12 -0
  145. package/src/scss/theme/bootstrap/helpers/_position.scss +36 -0
  146. package/src/scss/theme/bootstrap/helpers/_ratio.scss +26 -0
  147. package/src/scss/theme/bootstrap/helpers/_stacks.scss +15 -0
  148. package/src/scss/theme/bootstrap/helpers/_stretched-link.scss +15 -0
  149. package/src/scss/theme/bootstrap/helpers/_text-truncation.scss +7 -0
  150. package/src/scss/theme/bootstrap/helpers/_visually-hidden.scss +8 -0
  151. package/src/scss/theme/bootstrap/helpers/_vr.scss +8 -0
  152. package/src/scss/theme/bootstrap/mixins/_alert.scss +15 -0
  153. package/src/scss/theme/bootstrap/mixins/_backdrop.scss +14 -0
  154. package/src/scss/theme/bootstrap/mixins/_banner.scss +9 -0
  155. package/src/scss/theme/bootstrap/mixins/_border-radius.scss +78 -0
  156. package/src/scss/theme/bootstrap/mixins/_box-shadow.scss +18 -0
  157. package/src/scss/theme/bootstrap/mixins/_breakpoints.scss +127 -0
  158. package/src/scss/theme/bootstrap/mixins/_buttons.scss +70 -0
  159. package/src/scss/theme/bootstrap/mixins/_caret.scss +64 -0
  160. package/src/scss/theme/bootstrap/mixins/_clearfix.scss +9 -0
  161. package/src/scss/theme/bootstrap/mixins/_color-scheme.scss +7 -0
  162. package/src/scss/theme/bootstrap/mixins/_container.scss +11 -0
  163. package/src/scss/theme/bootstrap/mixins/_deprecate.scss +10 -0
  164. package/src/scss/theme/bootstrap/mixins/_forms.scss +152 -0
  165. package/src/scss/theme/bootstrap/mixins/_gradients.scss +47 -0
  166. package/src/scss/theme/bootstrap/mixins/_grid.scss +151 -0
  167. package/src/scss/theme/bootstrap/mixins/_image.scss +16 -0
  168. package/src/scss/theme/bootstrap/mixins/_list-group.scss +24 -0
  169. package/src/scss/theme/bootstrap/mixins/_lists.scss +7 -0
  170. package/src/scss/theme/bootstrap/mixins/_pagination.scss +10 -0
  171. package/src/scss/theme/bootstrap/mixins/_reset-text.scss +17 -0
  172. package/src/scss/theme/bootstrap/mixins/_resize.scss +6 -0
  173. package/src/scss/theme/bootstrap/mixins/_table-variants.scss +24 -0
  174. package/src/scss/theme/bootstrap/mixins/_text-truncate.scss +8 -0
  175. package/src/scss/theme/bootstrap/mixins/_transition.scss +26 -0
  176. package/src/scss/theme/bootstrap/mixins/_utilities.scss +97 -0
  177. package/src/scss/theme/bootstrap/mixins/_visually-hidden.scss +29 -0
  178. package/src/scss/theme/bootstrap/utilities/_api.scss +47 -0
  179. package/src/scss/theme/bootstrap/vendor/_rfs.scss +354 -0
  180. package/src/scss/theme/bs/_badge.scss +20 -0
  181. package/src/scss/theme/bs/_buttons.scss +185 -0
  182. package/src/scss/theme/bs/_dropdown.scss +86 -0
  183. package/src/scss/theme/bs/_forms.scss +161 -0
  184. package/src/scss/theme/bs/_list-group.scss +73 -0
  185. package/src/scss/theme/bs/_tables.scss +46 -0
  186. package/src/scss/theme/fonts/_fontmapping-roboto.scss +129 -0
  187. package/src/scss/theme/fonts/_fontmapping-segoe-ui.scss +127 -0
  188. package/src/scss/theme/fonts/_index.scss +2 -0
  189. package/src/scss/theme/mixins/_backdrop.scss +13 -0
  190. package/src/scss/theme/mixins/_palette.scss +165 -0
  191. package/src/scss/theme/mixins/_position.scss +33 -0
  192. package/src/scss/theme/mixins/_scrollbar.scss +110 -0
  193. package/src/scss/weavy-chat.scss +31 -0
  194. package/src/scss/weavy-messenger.scss +60 -0
  195. package/src/scss/weavy.scss +2 -0
  196. package/src/types/types.ts +2 -0
  197. package/src/ui/Button.tsx +3 -4
  198. package/src/ui/Dropdown.tsx +4 -5
  199. package/src/ui/Icon.tsx +75 -39
  200. package/src/ui/Overlay.tsx +2 -3
  201. package/src/utils/fileUtilities.ts +280 -72
  202. package/src/utils/scrollbarDetection.js +5 -7
  203. package/dist/cjs/types/utils/styles.d.ts +0 -17
  204. package/dist/esm/types/utils/styles.d.ts +0 -17
  205. package/src/utils/styles.ts +0 -57
@@ -0,0 +1,294 @@
1
+ import React, { useEffect, useState, useCallback } from "react";
2
+ import Icon from "../ui/Icon";
3
+ import classNames from "classnames";
4
+ import PdfViewer from "./PdfViewer";
5
+ import { checkImageLoad, imageLoaded } from "./Image";
6
+
7
+ const getStream = (response: Response) => {
8
+ if (response && response.ok && response.body) {
9
+ const reader = response.body.getReader();
10
+ return new ReadableStream({
11
+ start(controller) {
12
+ let pump: any = () => {
13
+ return reader.read().then(({ done, value }) => {
14
+ // When no more data needs to be consumed, close the stream
15
+ if (done) {
16
+ controller.close();
17
+ return;
18
+ }
19
+ // Enqueue the next data chunk into our target stream
20
+ controller.enqueue(value);
21
+ return pump();
22
+ });
23
+ }
24
+
25
+ return pump();
26
+ }
27
+ })
28
+ }
29
+ };
30
+
31
+ type ImageProps = {
32
+ src: string,
33
+ width?: number,
34
+ height?: number
35
+ }
36
+
37
+ export const PreviewImage = ({ src, width, height }: ImageProps) => {
38
+ const imageRef = useCallback((element: HTMLImageElement) => {
39
+ if (element) {
40
+ checkImageLoad(element);
41
+ }
42
+ }, [])
43
+
44
+ return (
45
+ <>
46
+ {width && height ?
47
+ <div className="wy-content-image wy-responsive-image" style={{ ["--width" as any]: width, ["--height" as any]: height }}>
48
+ <img ref={imageRef} src={src} onLoad={imageLoaded} width={width} height={height} decoding="async" />
49
+ {/* TODO: spinner here */}
50
+ </div>
51
+ :
52
+ <div className="wy-content-image wy-responsive-image wy-intrinsic-image">
53
+ <img ref={imageRef} src={src} onLoad={imageLoaded} decoding="async" />
54
+ </div>
55
+ }
56
+ </>
57
+ );
58
+ }
59
+
60
+ type DocumentProps = {
61
+ src: string
62
+ }
63
+
64
+ export const PreviewDocument = ({ src }: DocumentProps) => {
65
+ return (
66
+ <PdfViewer src={src} />
67
+ );
68
+ }
69
+
70
+ function mediaFallback(media: HTMLVideoElement | HTMLAudioElement) {
71
+ if (media.classList.contains("wy-loading")) {
72
+ media.classList.add("wy-loaded");
73
+ }
74
+ media.classList.add("wy-error");
75
+ // TODO: replace with react way
76
+ media.outerHTML = media.outerHTML.replace(/<(video|audio)/, "<div").replace(/(video|audio)>/, "div>");
77
+ }
78
+
79
+ function mediaLoaded(event: any) {
80
+ var src = event.target;
81
+ if (src.tagName === 'VIDEO' || src.tagName === 'AUDIO') {
82
+ if (src.classList.contains("wy-loading")) {
83
+ console.log("loaded")
84
+ src.classList.add("wy-loaded");
85
+ }
86
+ }
87
+ }
88
+
89
+ function mediaError(event: any) {
90
+ var src = event.target;
91
+ var media;
92
+ if (src.tagName === 'SOURCE') {
93
+ media = src.parentNode;
94
+ media.dataset.errors = (media.dataset.errors || 0) + 1;
95
+
96
+ if (media.querySelectorAll("source").length >= media.dataset.errors) {
97
+ console.warn(media.tagName.toLowerCase() + " source error, switching to fallback");
98
+ mediaFallback(media);
99
+ }
100
+ }
101
+ }
102
+
103
+ function codecError(event: any) {
104
+ var src = event.target;
105
+ if (src.tagName === 'VIDEO' || src.tagName === 'AUDIO') {
106
+ // Capture codec-error for video in firefox
107
+ if (src.tagName === 'VIDEO' && !src.videoWidth || src.tagName === 'AUDIO' && !src.duration) {
108
+ console.warn(src.tagName.toLowerCase() + " track not available, switching to fallback");
109
+ mediaFallback(src);
110
+ }
111
+ }
112
+ }
113
+
114
+ type VideoProps = {
115
+ src: string,
116
+ name: string,
117
+ mediaType?: string
118
+ }
119
+
120
+ export const PreviewVideo = ({ src, name, mediaType }: VideoProps) => {
121
+ /* TODO: loading, error handling and stopping */
122
+
123
+ return (
124
+ <>
125
+ <video className="wy-content-video" controls crossOrigin="use-credentials" autoPlay>
126
+ <source src={src} type={mediaType} />
127
+ <PreviewIcon src={src} name={name} icon="file-video" download />
128
+ </video>
129
+ {/* TODO: spinner here */}
130
+ </>
131
+ );
132
+ }
133
+
134
+ type AudioProps = {
135
+ src: string,
136
+ name: string,
137
+ mediaType?: string
138
+ }
139
+
140
+ export const PreviewAudio = ({ src, name, mediaType }: AudioProps) => {
141
+ /* TODO: loading, error handling and stopping */
142
+ return (
143
+ <>
144
+ <PreviewIcon src={src} name={name} icon="file-music" download>
145
+ <audio className="wy-content-audio" controls crossOrigin="use-credentials" autoPlay>
146
+ <source src={src} type={mediaType} />
147
+ </audio>
148
+ </PreviewIcon>
149
+ </>
150
+ );
151
+ }
152
+
153
+ type TextProps = {
154
+ src: string,
155
+ html?: boolean,
156
+ code?: boolean
157
+ }
158
+
159
+ export const PreviewText = ({ src, html = false, code = false }: TextProps) => {
160
+ const [textContent, setTextContent] = useState("");
161
+
162
+ useEffect(() => {
163
+ fetch(src)
164
+ .then(getStream)
165
+ // Create a new response out of the stream
166
+ .then(stream => new Response(stream))
167
+ // Create an object URL for the response
168
+ .then(response => response.text())
169
+ .then(text => {
170
+ setTextContent(text)
171
+ })
172
+ }, [src]);
173
+
174
+ return (
175
+ <>
176
+ {html ?
177
+ code ?
178
+ <div className="wy-content-code" dangerouslySetInnerHTML={{ __html: textContent }}></div>
179
+ :
180
+ <div className="wy-content-text">
181
+ <pre className="wy-document" dangerouslySetInnerHTML={{ __html: textContent }}></pre>
182
+ </div>
183
+ :
184
+ code ?
185
+ <div className="wy-content-code">{textContent}</div>
186
+ :
187
+ <div className="wy-content-text">
188
+ <pre className="wy-document">{textContent}</pre>
189
+ </div>
190
+ }
191
+ </>
192
+ );
193
+ }
194
+
195
+ type EmbedProps = {
196
+ src: string,
197
+ name: string,
198
+ icon: string,
199
+ provider?: string
200
+ }
201
+
202
+ export const PreviewEmbed = ({ src, name, icon, provider }: EmbedProps) => {
203
+ /* TODO: add loading and error handling */
204
+ return (
205
+ <>
206
+ {/* iframe needs to be object to not render error pages when content is blocked */}
207
+ <object className="wy-content-iframe" data={src}></object>
208
+
209
+ {/* TODO: add spinner here */}
210
+
211
+ <PreviewIcon src={src} name={name} icon={icon} provider={provider} className="wy-content-iframe-fallback" />
212
+ </>
213
+ );
214
+ }
215
+
216
+ type IconProps = {
217
+ children?: React.ReactNode,
218
+ src: string,
219
+ icon: string,
220
+ name: string,
221
+ provider?: string,
222
+ download?: boolean,
223
+ className?: string
224
+ }
225
+
226
+ export const PreviewIcon = ({ children, src, icon, name, provider, download = false, className }: IconProps) => {
227
+ return (
228
+ <div className={classNames("wy-content-media", className)}>
229
+ <div className="wy-content-icon">
230
+ <Icon.UI name={icon} />
231
+ </div>
232
+ <div className="wy-content-name">
233
+ {provider ?
234
+ <a href={src} target="_blank" title={`Open in ${provider}`}>{name} <Icon.UI name="open-in-new" size={1} /></a>
235
+ : download ?
236
+ <a href={src} target="_top" download>{name}</a>
237
+ :
238
+ <a href={src} target="_blank">{name} <Icon.UI name="open-in-new" size={1} /></a>
239
+ }
240
+ </div>
241
+ {children}
242
+ </div>
243
+ );
244
+ }
245
+
246
+ type PreviewProps = {
247
+ src: string,
248
+ format: PreviewFormatType,
249
+ name: string,
250
+ icon: string,
251
+ width?: number,
252
+ height?: number,
253
+ mediaType?: string,
254
+ provider?: string
255
+ }
256
+
257
+ export const Preview = ({ src, format, name, icon, width, height, mediaType, provider }: PreviewProps) => {
258
+ return (
259
+ <>
260
+ {format === "image" &&
261
+ <PreviewImage src={src} width={width} height={height} />
262
+ }
263
+ {format === "document" &&
264
+ <PreviewDocument src={src} />
265
+ }
266
+ {format === "video" &&
267
+ <PreviewVideo src={src} name={name} mediaType={mediaType} />
268
+ }
269
+ {format === "audio" &&
270
+ <PreviewAudio src={src} name={name} mediaType={mediaType} />
271
+ }
272
+ {format === "text" &&
273
+ <PreviewText src={src} />
274
+ }
275
+ {format === "code" &&
276
+ <PreviewText src={src} html code />
277
+ }
278
+ {format === "markup" &&
279
+ <PreviewText src={src} html />
280
+ }
281
+ {format === "embed" &&
282
+ <PreviewEmbed src={src} name={name} icon={icon} provider={provider} />
283
+ }
284
+ {format === "link" &&
285
+ <PreviewIcon src={src} name={name} icon={icon} provider={provider} />
286
+ }
287
+ {format === "download" &&
288
+ <PreviewIcon src={src} name={name} icon={icon} download />
289
+ }
290
+ </>
291
+ )
292
+ }
293
+
294
+ export default Preview;
@@ -5,7 +5,6 @@ import Button from "../ui/Button";
5
5
  import { MessengerContext } from "../contexts/MessengerContext";
6
6
  import classNames from "classnames";
7
7
 
8
- import { prefix as wy } from "../utils/styles";
9
8
  import useReactions from "../hooks/useReactions";
10
9
  import useMutateDeleteReaction from "../hooks/useMutateDeleteReaction";
11
10
  import { WeavyContext } from "../contexts/WeavyContext";
@@ -69,12 +68,12 @@ export const ReactionsMenu = ({ id, reactions }: ReactionMenuProps) => {
69
68
  }
70
69
 
71
70
  return (
72
- <div className={wy(classNames("", { "active": visible }))} style={{ position: 'relative' }}>
73
- <Button.UI onClick={toggleReactionMenu}><Icon.UI name="emoticon-outline" size={1} /></Button.UI>
74
- <div className={wy('reaction-menu dropdown-menu')} style={{ display: visible ? 'block' : 'none', position: 'absolute', top: '-3.25rem' }}>
75
- <div className={wy('reaction-picker')}>
71
+ <div className={classNames({ "wy-active": visible })} style={{ position: 'relative' }}>
72
+ <Button.UI onClick={toggleReactionMenu}><Icon.UI name="emoticon-plus" size={1} /></Button.UI>
73
+ <div className="wy-reaction-menu wy-dropdown-menu" style={{ display: visible ? 'block' : 'none', position: 'absolute', top: '-3.25rem' }}>
74
+ <div className="wy-reaction-picker">
76
75
  {emojis?.map((r: string, i: number) => {
77
- return <Button.UI key={i} onClick={handleReaction} className={wy(classNames("button-icon reaction-button", { "active": reactedEmoji === r }))} data-emoji={r}>{r}</Button.UI> //reactedEmoji
76
+ return <Button.UI key={i} onClick={handleReaction} className={classNames("wy-button-icon wy-reaction-button", { "wy-active": reactedEmoji === r })} data-emoji={r}>{r}</Button.UI> //reactedEmoji
78
77
  })}
79
78
  </div>
80
79
  </div>
@@ -89,7 +88,7 @@ export const ReactionsList = ({ id, reactions }: ReactionsProps) => {
89
88
  return (
90
89
  <>
91
90
  {reactionsList && reactionsList.map((r: ReactionGroup, i: number) => {
92
- return <span key={i} className={wy('reaction')} title={r.count.toString()}>{r.content}</span> //r.has_reacted
91
+ return <span key={i} className="wy-reaction" title={r.count.toString()}>{r.content}</span> //r.has_reacted
93
92
  })}
94
93
  </>
95
94
  )
@@ -4,7 +4,6 @@ import useSearchUsers from "../hooks/useSearchUsers";
4
4
  import Avatar from './Avatar';
5
5
  import Button from '../ui/Button';
6
6
  import Icon from '../ui/Icon';
7
- import { prefix as wy } from "../utils/styles";
8
7
 
9
8
  type SearchUsersProps = {
10
9
  handleSubmit: any,
@@ -42,33 +41,33 @@ const SearchUsers = ({handleSubmit, buttonTitle}: SearchUsersProps) => {
42
41
  }
43
42
 
44
43
  return (
45
- <div className={wy('search scroll-y')}>
46
- <div className={wy('search-form pane-group')}>
44
+ <div className="wy-search wy-scroll-y">
45
+ <div className="wy-search-form wy-pane-group">
47
46
  <Button.UI><Icon.UI name="magnify" /></Button.UI>
48
- <input className={wy('search-input')} value={text} onChange={(e) => setText(e.target.value)} name="text" placeholder='Search...' />
47
+ <input className="wy-search-input" value={text} onChange={(e) => setText(e.target.value)} name="text" placeholder='Search...' />
49
48
  </div>
50
49
 
51
- <div className={wy('pane-group')}>
50
+ <div className="wy-pane-group">
52
51
  {data && data.data.length === 0 &&
53
- <div className={wy('search-no-result')}>Your search did not match any people.</div>
52
+ <div className="wy-search-no-result">Your search did not match any people.</div>
54
53
  }
55
- <table className={wy('search-result-table')}>
54
+ <table className="wy-search-result-table">
56
55
  <tbody>
57
56
  {data && data.data.length > 0 && data.data.map((user: MemberType) => {
58
57
  return (
59
- <tr key={user.id} className={wy('search-result-table-checkbox')}>
60
- <td className={wy('search-result-table-icon')}>
58
+ <tr key={user.id} className="wy-search-result-table-checkbox">
59
+ <td className="wy-search-result-table-icon">
61
60
  <Avatar src={user.avatar_url} size={24} id={user.id} presence={user.presence} name={user.display_name} />
62
61
  </td>
63
62
  <td><label htmlFor={'chk' + user.id}>{user.display_name}</label></td>
64
- <td className={wy('search-result-table-icon')}><input type="checkbox" id={'chk' + user.id} checked={isChecked(user.id)} onChange={(e) => handleSelected(e, user)} /></td>
63
+ <td className="wy-search-result-table-icon"><input type="checkbox" id={'chk' + user.id} checked={isChecked(user.id)} onChange={(e) => handleSelected(e, user)} /></td>
65
64
  </tr>
66
65
  )
67
66
  })}
68
- </tbody>
67
+ </tbody>
69
68
  </table>
70
69
  </div>
71
- {/*<div className={wy('search-group')}>
70
+ {/*<div className="wy-search-group">
72
71
  <h2>Selected people</h2>
73
72
  <ul>
74
73
  {selected && selected.length > 0 && selected.map((user: UserType) => {
@@ -76,10 +75,12 @@ const SearchUsers = ({handleSubmit, buttonTitle}: SearchUsersProps) => {
76
75
  })}
77
76
  </ul>
78
77
  </div>*/}
79
- <div className={wy('footerbars')}>
80
- <div className={wy('footerbar')}>
81
- <div className={wy('pane-group')}>
82
- <button className={wy('button-primary')} type="button" onClick={() => {handleSubmit(selected); clear();}} disabled={selected.length === 0}>{buttonTitle}</button>
78
+ <div className="wy-footerbars">
79
+ <div className="wy-footerbar">
80
+ <div className="wy-pane-group">
81
+ <div className="wy-buttons">
82
+ <button className="wy-button wy-button-primary" type="button" onClick={() => {handleSubmit(selected); clear();}} disabled={selected.length === 0}>{buttonTitle}</button>
83
+ </div>
83
84
  </div>
84
85
  </div>
85
86
  </div>
@@ -1,7 +1,6 @@
1
1
  import React from "react";
2
2
  import Avatar from "./Avatar";
3
3
  import dayjs from 'dayjs';
4
- import { prefix as wy } from "../utils/styles";
5
4
 
6
5
  type Props = {
7
6
  id: number,
@@ -13,7 +12,7 @@ type Props = {
13
12
  const SeenBy = ({ seenBy }: Props) => {
14
13
 
15
14
  return (
16
- <div className={wy('readby-status')}>
15
+ <div className="wy-readby-status">
17
16
  {seenBy && seenBy.length > 0 && seenBy.map((member: MemberType) => {
18
17
  const date = dayjs.utc(member.read_at).tz(dayjs.tz.guess());
19
18
  return (<Avatar name={`Seen by ${member.name} at ${date.format('LLLL')}`} src={member.avatar_url} size={16} key={member.id}/>)})
@@ -2,7 +2,6 @@ import React, { createContext, useEffect, useState } from "react";
2
2
  import Overlay from '../ui/Overlay';
3
3
  import Button from '../ui/Button';
4
4
  import Icon from '../ui/Icon';
5
- import { prefix as wy } from "../utils/styles";
6
5
 
7
6
  export const PreviewContext = createContext<PreviewContextProps>({
8
7
  openPreview: Function,
@@ -64,11 +63,11 @@ const PreviewProvider = ({ children }: Props) => {
64
63
  {children}
65
64
  </PreviewContext.Provider>
66
65
 
67
- <Overlay.UI isOpen={modalPreviewOpen} className={wy('dark')}>
68
- <header className={wy('appbars')}>
69
- <nav className={wy('appbar')}>
66
+ <Overlay.UI isOpen={modalPreviewOpen} className={'wy-dark'}>
67
+ <header className={'wy-appbars'}>
68
+ <nav className={'wy-appbar'}>
70
69
  <Button.UI onClick={closePreview}><Icon.UI name='close' /></Button.UI>
71
- <div className={wy('appbar-text')}>
70
+ <div className={'wy-appbar-text'}>
72
71
  {activeAttachment &&
73
72
  <span>{activeAttachment.name}</span>
74
73
  }
@@ -102,4 +101,3 @@ const PreviewProvider = ({ children }: Props) => {
102
101
  };
103
102
 
104
103
  export default PreviewProvider;
105
-
@@ -1,5 +1,4 @@
1
1
  import { useContext } from "react";
2
-
3
2
  import { useQuery } from "react-query";
4
3
  import { WeavyContext } from "../contexts/WeavyContext";
5
4
 
@@ -1,6 +1,5 @@
1
1
  import { useContext, useEffect } from "react";
2
2
  import { WeavyContext } from "../contexts/WeavyContext";
3
- import { prefix as wy } from "../utils/styles";
4
3
 
5
4
  export default function usePresence() {
6
5
 
@@ -17,18 +16,18 @@ export default function usePresence() {
17
16
  const handlePresenceChange = (data: any) => {
18
17
 
19
18
  if (Array.isArray(data)) {
20
- document.querySelectorAll(wy(".presence")).forEach(function (item) {
21
- item.classList.remove(wy("presence-active"));
19
+ document.querySelectorAll(".wy-presence").forEach(function (item) {
20
+ item.classList.remove("wy-presence-active");
22
21
  });
23
22
 
24
23
  data.forEach(function (id) {
25
24
  document.querySelectorAll("[data-presence-id='" + id + "']").forEach(function (item) {
26
- item.classList.add(wy("presence-active"));
25
+ item.classList.add("wy-presence-active");
27
26
  });
28
27
  });
29
28
  } else {
30
29
  document.querySelectorAll("[data-presence-id='" + data + "']").forEach(function (item) {
31
- item.classList.add(wy("presence-active"));
30
+ item.classList.add("wy-presence-active");
32
31
  });
33
32
  }
34
33
  }
@@ -2,7 +2,6 @@ import { useCallback, useContext, useEffect, useLayoutEffect, useState } from "r
2
2
  import { UserContext } from "../contexts/UserContext";
3
3
  import useEvents from "./useEvents";
4
4
 
5
-
6
5
  export default function useReactions(id: number, reactions: ReactableType[]) {
7
6
  const { on, off } = useEvents();
8
7
  const { user } = useContext(UserContext);
@@ -0,0 +1,73 @@
1
+ @use "config" as *;
2
+
3
+ // Global alerts
4
+
5
+ .wy-alert-message {
6
+ padding: .25rem .5rem;
7
+ background-color: $client-alert-background;
8
+ text-align: center;
9
+ width: $client-panel-width;
10
+ color: $client-alert-color;
11
+ border-radius: .1875rem;
12
+ margin: 0 auto;
13
+ margin-top: 1rem;
14
+ font-family: $font-family-base;
15
+ position: relative;
16
+ z-index: 10;
17
+ box-shadow: $md-shadow-8dp;
18
+ max-width: calc(100% - 3rem);
19
+ pointer-events: none;
20
+ user-select: none;
21
+
22
+ a {
23
+ color: darken($client-alert-color, 10%);
24
+ text-decoration: $link-decoration;
25
+ font-weight: $alert-link-font-weight;
26
+ pointer-events: auto;
27
+ }
28
+
29
+ &.wy-fade {
30
+ transition: all $md-animation-duration $md-animation-curve-default;
31
+ opacity: 0;
32
+ height: 0;
33
+ padding-top: 0;
34
+ padding-bottom: 0;
35
+ margin-top: 0;
36
+
37
+ &.wy-in {
38
+ transition: opacity $md-animation-duration $md-animation-curve-default;
39
+ opacity: 1;
40
+ height: auto;
41
+ padding-top: .5rem;
42
+ padding-bottom: .5rem;
43
+ margin-top: 1rem;
44
+ }
45
+ }
46
+
47
+ .wy-button {
48
+ cursor: pointer;
49
+ display: inline-flex;
50
+ flex-shrink: 0;
51
+ flex-grow: 0;
52
+
53
+ > * {
54
+ display: inline-flex;
55
+ }
56
+
57
+ font-weight: 400;
58
+ text-align: center;
59
+ white-space: nowrap;
60
+ vertical-align: middle;
61
+ user-select: none;
62
+ border: 1px solid transparent;
63
+ padding: .3125rem .75rem;
64
+ font-size: 1rem;
65
+ line-height: 1.5;
66
+ border-radius: .1875rem;
67
+ color: $white;
68
+ background-color: $primary;
69
+ border-color: $primary;
70
+ box-shadow: $btn-box-shadow;
71
+ margin-top: .5rem;
72
+ }
73
+ }
@@ -0,0 +1,112 @@
1
+ @use "config" as *;
2
+ @use "mixins/backdrop";
3
+ @use "mixins/position";
4
+
5
+ .wy-appbars {
6
+ @include position.sticky-top;
7
+
8
+ @include backdrop.filter {
9
+ > .wy-appbar {
10
+ backdrop-filter: none;
11
+ }
12
+ }
13
+ }
14
+
15
+ .wy-appbar {
16
+ display: grid;
17
+ align-items: center;
18
+ justify-content: space-between;
19
+ height: $appbar-height;
20
+ padding: $navbar-padding-y $navbar-padding-x;
21
+ flex: 0 0 $appbar-height;
22
+ grid-template-columns: minmax(2rem, max-content) minmax(0, max-content) minmax(2rem, max-content);
23
+ column-gap: .5rem;
24
+
25
+ @include backdrop.filter;
26
+
27
+ .wy-badge {
28
+ align-self: center;
29
+ }
30
+
31
+ .wy-button {
32
+ max-height: 2rem;
33
+ }
34
+ }
35
+
36
+ .wy-appbar-buttons {
37
+ display: flex;
38
+ flex: 0 0 1rem;
39
+ }
40
+
41
+ .wy-appbar-text {
42
+ @include text-truncate();
43
+ color: inherit !important;
44
+ user-select: none;
45
+
46
+ a {
47
+ color: inherit;
48
+
49
+ &:hover {
50
+ color: inherit;
51
+ }
52
+ }
53
+ }
54
+
55
+ .wy-appbar {
56
+ // light theme (default)
57
+ &, .wy-light &, &.wy-light {
58
+ background-color: rgba($gray-50, $opacity-backdrop);
59
+ color: $navbar-light-color;
60
+ border-bottom: $border-width solid rgba($gray-200, $opacity-backdrop);
61
+ }
62
+ // dark theme
63
+ .wy-dark &, &.wy-dark {
64
+ background-color: rgba($dark, $opacity-backdrop);
65
+ color: $navbar-dark-color;
66
+ border-bottom: $border-width solid rgba($gray-800, $opacity-backdrop);
67
+ }
68
+ }
69
+
70
+ .wy-footerbars {
71
+ padding-bottom: $footerbar-height;
72
+ }
73
+
74
+ .wy-footerbar {
75
+ position: absolute;
76
+ bottom: 0;
77
+ left: 0;
78
+ right: 0;
79
+ z-index: $zindex-sticky;
80
+
81
+ &::after {
82
+ content: "";
83
+ position: absolute;
84
+ width: 100vw;
85
+ left: 0;
86
+ bottom: 0;
87
+ height: $footerbar-height;
88
+ border-top: $border-width solid rgba($gray-200, $opacity-backdrop);
89
+ background: rgba($gray-50, $opacity-backdrop);
90
+ z-index: -1;
91
+
92
+ @include backdrop.filter;
93
+ }
94
+
95
+ .wy-buttons {
96
+ flex-direction: row-reverse;
97
+
98
+ > :not(:last-child) {
99
+ margin: 0 0 0 .5rem;
100
+ }
101
+ }
102
+ }
103
+
104
+ .wy-footerbars-fixed {
105
+ .wy-footerbar {
106
+ position: fixed;
107
+
108
+ &::after {
109
+ position: fixed;
110
+ }
111
+ }
112
+ }