@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.
- package/.github/workflows/publish.yml +1 -1
- package/README.md +3 -4
- package/changelog.md +57 -0
- package/dist/cjs/index.js +28 -6
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/client/WeavyClient.d.ts +8 -1
- package/dist/cjs/types/components/Attachment.d.ts +2 -1
- package/dist/cjs/types/components/Chat.d.ts +1 -1
- package/dist/cjs/types/components/Image.d.ts +2 -0
- package/dist/cjs/types/components/PdfViewer.d.ts +8 -0
- package/dist/cjs/types/components/Preview.d.ts +56 -0
- package/dist/cjs/types/contexts/MessengerContext.d.ts +1 -2
- package/dist/cjs/types/contexts/PreviewContext.d.ts +2 -1
- package/dist/cjs/types/contexts/WeavyContext.d.ts +2 -3
- package/dist/cjs/types/types/Chat.d.ts +1 -1
- package/dist/cjs/types/types/Messenger.d.ts +0 -1
- package/dist/cjs/types/types/types.d.ts +18 -8
- package/dist/cjs/types/ui/Spinner.d.ts +9 -0
- package/dist/cjs/types/utils/fileUtilities.d.ts +13 -1
- package/dist/css/weavy-chat.css +2860 -0
- package/dist/css/weavy-messenger.css +3217 -0
- package/dist/css/weavy.css +3217 -0
- package/dist/esm/index.js +28 -6
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/client/WeavyClient.d.ts +8 -1
- package/dist/esm/types/components/Attachment.d.ts +2 -1
- package/dist/esm/types/components/Chat.d.ts +1 -1
- package/dist/esm/types/components/Image.d.ts +2 -0
- package/dist/esm/types/components/PdfViewer.d.ts +8 -0
- package/dist/esm/types/components/Preview.d.ts +56 -0
- package/dist/esm/types/contexts/MessengerContext.d.ts +1 -2
- package/dist/esm/types/contexts/PreviewContext.d.ts +2 -1
- package/dist/esm/types/contexts/WeavyContext.d.ts +2 -3
- package/dist/esm/types/types/Chat.d.ts +1 -1
- package/dist/esm/types/types/Messenger.d.ts +0 -1
- package/dist/esm/types/types/types.d.ts +18 -8
- package/dist/esm/types/ui/Spinner.d.ts +9 -0
- package/dist/esm/types/utils/fileUtilities.d.ts +13 -1
- package/dist/index.d.ts +15 -9
- package/package.json +14 -4
- package/rollup.config.js +3 -3
- package/src/client/WeavyClient.ts +105 -24
- package/src/components/Attachment.tsx +8 -8
- package/src/components/Avatar.tsx +2 -3
- package/src/components/Chat.tsx +13 -17
- package/src/components/Conversation.tsx +23 -32
- package/src/components/ConversationBadge.tsx +1 -2
- package/src/components/ConversationForm.tsx +11 -18
- package/src/components/ConversationList.tsx +4 -5
- package/src/components/ConversationListItem.tsx +11 -13
- package/src/components/FileBrowser.tsx +2 -3
- package/src/components/Image.tsx +39 -7
- package/src/components/MeetingCard.tsx +7 -8
- package/src/components/Message.tsx +13 -14
- package/src/components/Messages.tsx +7 -8
- package/src/components/Messenger.tsx +5 -6
- package/src/components/NewConversation.tsx +5 -7
- package/src/components/PdfViewer.tsx +276 -0
- package/src/components/Presence.tsx +2 -2
- package/src/components/Preview.tsx +355 -0
- package/src/components/Reactions.tsx +8 -8
- package/src/components/SearchUsers.tsx +19 -18
- package/src/components/SeenBy.tsx +1 -2
- package/src/contexts/MessengerContext.tsx +4 -12
- package/src/contexts/PreviewContext.tsx +89 -17
- package/src/contexts/WeavyContext.tsx +15 -5
- package/src/hooks/useBadge.ts +2 -6
- package/src/hooks/useChat.ts +3 -14
- package/src/hooks/useConversation.ts +1 -8
- package/src/hooks/useConversations.ts +1 -7
- package/src/hooks/useFileUploader.ts +6 -8
- package/src/hooks/useMembers.ts +1 -7
- package/src/hooks/useMessages.ts +1 -7
- package/src/hooks/useMutateChat.ts +6 -11
- package/src/hooks/useMutateConversation.ts +7 -10
- package/src/hooks/useMutateConversationName.ts +10 -12
- package/src/hooks/useMutateDeleteReaction.ts +3 -8
- package/src/hooks/useMutateExternalBlobs.ts +6 -11
- package/src/hooks/useMutateMeeting.ts +6 -11
- package/src/hooks/useMutateMembers.ts +8 -13
- package/src/hooks/useMutateMessage.ts +10 -15
- package/src/hooks/useMutatePinned.ts +3 -8
- package/src/hooks/useMutateReaction.ts +6 -12
- package/src/hooks/useMutateRead.ts +1 -10
- package/src/hooks/useMutateRemoveMembers.ts +7 -12
- package/src/hooks/useMutateTyping.ts +6 -11
- package/src/hooks/usePresence.ts +4 -5
- package/src/hooks/useReactions.ts +0 -1
- package/src/hooks/useSearchUsers.ts +1 -6
- package/src/hooks/useUser.ts +3 -14
- package/src/index.ts +2 -2
- package/src/scss/theme/_alert.scss +73 -0
- package/src/scss/theme/_appbar.scss +114 -0
- package/src/scss/theme/_attachments.scss +74 -0
- package/src/scss/theme/_avatar.scss +54 -0
- package/src/scss/theme/_badge.scss +47 -0
- package/src/scss/theme/_buttons.scss +96 -0
- package/src/scss/theme/_card.scss +7 -0
- package/src/scss/theme/_checkbox.scss +56 -0
- package/src/scss/theme/_cm-editor.scss +42 -0
- package/src/scss/theme/_code-vscode-dark.scss +184 -0
- package/src/scss/theme/_code-vscode-light.scss +179 -0
- package/src/scss/theme/_code.scss +12 -0
- package/src/scss/theme/_colors.scss +520 -0
- package/src/scss/theme/_config.scss +6 -0
- package/src/scss/theme/_content.scss +15 -0
- package/src/scss/theme/_conversations.scss +91 -0
- package/src/scss/theme/_dropdown.scss +86 -0
- package/src/scss/theme/_emoji.scss +5 -0
- package/src/scss/theme/_filebrowser.scss +26 -0
- package/src/scss/theme/_files.scss +140 -0
- package/src/scss/theme/_icons.scss +62 -0
- package/src/scss/theme/_image-grid.scss +63 -0
- package/src/scss/theme/_inputs.scss +28 -0
- package/src/scss/theme/_message-editor.scss +90 -0
- package/src/scss/theme/_messages.scss +238 -0
- package/src/scss/theme/_nav.scss +52 -0
- package/src/scss/theme/_overlays.scss +157 -0
- package/src/scss/theme/_pager.scss +19 -0
- package/src/scss/theme/_palette.scss +165 -0
- package/src/scss/theme/_pane.scss +16 -0
- package/src/scss/theme/_panels.scss +141 -0
- package/src/scss/theme/_picker-list.scss +37 -0
- package/src/scss/theme/_preview-code.scss +5 -0
- package/src/scss/theme/_preview-embed.scss +38 -0
- package/src/scss/theme/_preview-html.scss +7 -0
- package/src/scss/theme/_preview-icon.scss +41 -0
- package/src/scss/theme/_preview-image.scss +86 -0
- package/src/scss/theme/_preview-media.scss +28 -0
- package/src/scss/theme/_preview-pdf.scss +838 -0
- package/src/scss/theme/_preview-text.scss +5 -0
- package/src/scss/theme/_preview.scss +110 -0
- package/src/scss/theme/_reactions.scss +58 -0
- package/src/scss/theme/_reboot.scss +41 -0
- package/src/scss/theme/_root.scss +2 -0
- package/src/scss/theme/_scroll.scss +55 -0
- package/src/scss/theme/_search.scss +68 -0
- package/src/scss/theme/_spinner.scss +63 -0
- package/src/scss/theme/_tables.scss +53 -0
- package/src/scss/theme/_toasts.scss +47 -0
- package/src/scss/theme/_turbo.scss +17 -0
- package/src/scss/theme/_typing.scss +26 -0
- package/src/scss/theme/_variables.scss +139 -0
- package/src/scss/theme/bootstrap/_accordion.scss +146 -0
- package/src/scss/theme/bootstrap/_alert.scss +71 -0
- package/src/scss/theme/bootstrap/_badge.scss +38 -0
- package/src/scss/theme/bootstrap/_breadcrumb.scss +40 -0
- package/src/scss/theme/bootstrap/_button-group.scss +142 -0
- package/src/scss/theme/bootstrap/_buttons.scss +186 -0
- package/src/scss/theme/bootstrap/_card.scss +234 -0
- package/src/scss/theme/bootstrap/_carousel.scss +229 -0
- package/src/scss/theme/bootstrap/_close.scss +40 -0
- package/src/scss/theme/bootstrap/_containers.scss +41 -0
- package/src/scss/theme/bootstrap/_dropdown.scss +248 -0
- package/src/scss/theme/bootstrap/_forms.scss +9 -0
- package/src/scss/theme/bootstrap/_functions.scss +302 -0
- package/src/scss/theme/bootstrap/_grid.scss +33 -0
- package/src/scss/theme/bootstrap/_helpers.scss +10 -0
- package/src/scss/theme/bootstrap/_images.scss +42 -0
- package/src/scss/theme/bootstrap/_list-group.scss +191 -0
- package/src/scss/theme/bootstrap/_maps.scss +54 -0
- package/src/scss/theme/bootstrap/_mixins.scss +43 -0
- package/src/scss/theme/bootstrap/_modal.scss +237 -0
- package/src/scss/theme/bootstrap/_nav.scss +172 -0
- package/src/scss/theme/bootstrap/_navbar.scss +276 -0
- package/src/scss/theme/bootstrap/_offcanvas.scss +143 -0
- package/src/scss/theme/bootstrap/_pagination.scss +109 -0
- package/src/scss/theme/bootstrap/_placeholders.scss +51 -0
- package/src/scss/theme/bootstrap/_popover.scss +196 -0
- package/src/scss/theme/bootstrap/_progress.scss +59 -0
- package/src/scss/theme/bootstrap/_reboot.scss +610 -0
- package/src/scss/theme/bootstrap/_root.scss +73 -0
- package/src/scss/theme/bootstrap/_spinners.scss +85 -0
- package/src/scss/theme/bootstrap/_tables.scss +164 -0
- package/src/scss/theme/bootstrap/_toasts.scss +70 -0
- package/src/scss/theme/bootstrap/_tooltip.scss +120 -0
- package/src/scss/theme/bootstrap/_transitions.scss +27 -0
- package/src/scss/theme/bootstrap/_type.scss +106 -0
- package/src/scss/theme/bootstrap/_utilities.scss +647 -0
- package/src/scss/theme/bootstrap/_variables.scss +1633 -0
- package/src/scss/theme/bootstrap/forms/_floating-labels.scss +74 -0
- package/src/scss/theme/bootstrap/forms/_form-check.scss +175 -0
- package/src/scss/theme/bootstrap/forms/_form-control.scss +194 -0
- package/src/scss/theme/bootstrap/forms/_form-range.scss +91 -0
- package/src/scss/theme/bootstrap/forms/_form-select.scss +71 -0
- package/src/scss/theme/bootstrap/forms/_form-text.scss +11 -0
- package/src/scss/theme/bootstrap/forms/_input-group.scss +129 -0
- package/src/scss/theme/bootstrap/forms/_labels.scss +36 -0
- package/src/scss/theme/bootstrap/forms/_validation.scss +12 -0
- package/src/scss/theme/bootstrap/helpers/_clearfix.scss +3 -0
- package/src/scss/theme/bootstrap/helpers/_color-bg.scss +10 -0
- package/src/scss/theme/bootstrap/helpers/_colored-links.scss +12 -0
- package/src/scss/theme/bootstrap/helpers/_position.scss +36 -0
- package/src/scss/theme/bootstrap/helpers/_ratio.scss +26 -0
- package/src/scss/theme/bootstrap/helpers/_stacks.scss +15 -0
- package/src/scss/theme/bootstrap/helpers/_stretched-link.scss +15 -0
- package/src/scss/theme/bootstrap/helpers/_text-truncation.scss +7 -0
- package/src/scss/theme/bootstrap/helpers/_visually-hidden.scss +8 -0
- package/src/scss/theme/bootstrap/helpers/_vr.scss +8 -0
- package/src/scss/theme/bootstrap/mixins/_alert.scss +15 -0
- package/src/scss/theme/bootstrap/mixins/_backdrop.scss +14 -0
- package/src/scss/theme/bootstrap/mixins/_banner.scss +9 -0
- package/src/scss/theme/bootstrap/mixins/_border-radius.scss +78 -0
- package/src/scss/theme/bootstrap/mixins/_box-shadow.scss +18 -0
- package/src/scss/theme/bootstrap/mixins/_breakpoints.scss +127 -0
- package/src/scss/theme/bootstrap/mixins/_buttons.scss +70 -0
- package/src/scss/theme/bootstrap/mixins/_caret.scss +64 -0
- package/src/scss/theme/bootstrap/mixins/_clearfix.scss +9 -0
- package/src/scss/theme/bootstrap/mixins/_color-scheme.scss +7 -0
- package/src/scss/theme/bootstrap/mixins/_container.scss +11 -0
- package/src/scss/theme/bootstrap/mixins/_deprecate.scss +10 -0
- package/src/scss/theme/bootstrap/mixins/_forms.scss +152 -0
- package/src/scss/theme/bootstrap/mixins/_gradients.scss +47 -0
- package/src/scss/theme/bootstrap/mixins/_grid.scss +151 -0
- package/src/scss/theme/bootstrap/mixins/_image.scss +16 -0
- package/src/scss/theme/bootstrap/mixins/_list-group.scss +24 -0
- package/src/scss/theme/bootstrap/mixins/_lists.scss +7 -0
- package/src/scss/theme/bootstrap/mixins/_pagination.scss +10 -0
- package/src/scss/theme/bootstrap/mixins/_reset-text.scss +17 -0
- package/src/scss/theme/bootstrap/mixins/_resize.scss +6 -0
- package/src/scss/theme/bootstrap/mixins/_table-variants.scss +24 -0
- package/src/scss/theme/bootstrap/mixins/_text-truncate.scss +8 -0
- package/src/scss/theme/bootstrap/mixins/_transition.scss +26 -0
- package/src/scss/theme/bootstrap/mixins/_utilities.scss +97 -0
- package/src/scss/theme/bootstrap/mixins/_visually-hidden.scss +29 -0
- package/src/scss/theme/bootstrap/utilities/_api.scss +47 -0
- package/src/scss/theme/bootstrap/vendor/_rfs.scss +354 -0
- package/src/scss/theme/bs/_badge.scss +20 -0
- package/src/scss/theme/bs/_buttons.scss +185 -0
- package/src/scss/theme/bs/_dropdown.scss +86 -0
- package/src/scss/theme/bs/_forms.scss +161 -0
- package/src/scss/theme/bs/_list-group.scss +73 -0
- package/src/scss/theme/bs/_tables.scss +46 -0
- package/src/scss/theme/fonts/_fontmapping-roboto.scss +129 -0
- package/src/scss/theme/fonts/_fontmapping-segoe-ui.scss +127 -0
- package/src/scss/theme/fonts/_index.scss +2 -0
- package/src/scss/theme/mixins/_backdrop.scss +13 -0
- package/src/scss/theme/mixins/_palette.scss +165 -0
- package/src/scss/theme/mixins/_position.scss +33 -0
- package/src/scss/theme/mixins/_scrollbar.scss +110 -0
- package/src/scss/weavy-chat.scss +32 -0
- package/src/scss/weavy-messenger.scss +61 -0
- package/src/scss/weavy.scss +2 -0
- package/src/types/Chat.ts +1 -1
- package/src/types/Messenger.ts +1 -1
- package/src/types/types.ts +20 -11
- package/src/ui/Button.tsx +3 -4
- package/src/ui/Dropdown.tsx +4 -5
- package/src/ui/Icon.tsx +75 -39
- package/src/ui/Overlay.tsx +2 -3
- package/src/ui/Spinner.tsx +18 -0
- package/src/utils/fileUtilities.ts +166 -72
- package/src/utils/scrollbarDetection.js +48 -0
- package/dist/cjs/types/utils/styles.d.ts +0 -17
- package/dist/esm/types/utils/styles.d.ts +0 -17
- package/src/utils/styles.ts +0 -42
|
@@ -0,0 +1,355 @@
|
|
|
1
|
+
import React, { useEffect, useState, useCallback } from "react";
|
|
2
|
+
import Icon from "../ui/Icon";
|
|
3
|
+
import Spinner from "../ui/Spinner";
|
|
4
|
+
import classNames from "classnames";
|
|
5
|
+
import PdfViewer from "./PdfViewer";
|
|
6
|
+
import { checkImageLoad, imageLoaded } from "./Image";
|
|
7
|
+
|
|
8
|
+
const getStream = (response: Response) => {
|
|
9
|
+
if (response && response.ok && response.body) {
|
|
10
|
+
const reader = response.body.getReader();
|
|
11
|
+
return new ReadableStream({
|
|
12
|
+
start(controller) {
|
|
13
|
+
let pump: any = () => {
|
|
14
|
+
return reader.read().then(({ done, value }) => {
|
|
15
|
+
// When no more data needs to be consumed, close the stream
|
|
16
|
+
if (done) {
|
|
17
|
+
controller.close();
|
|
18
|
+
return;
|
|
19
|
+
}
|
|
20
|
+
// Enqueue the next data chunk into our target stream
|
|
21
|
+
controller.enqueue(value);
|
|
22
|
+
return pump();
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
return pump();
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
type ImageProps = {
|
|
33
|
+
src: string,
|
|
34
|
+
width?: number,
|
|
35
|
+
height?: number
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export const PreviewImage = ({ src, width, height }: ImageProps) => {
|
|
39
|
+
const imageRef = useCallback((element: HTMLImageElement) => {
|
|
40
|
+
if (element) {
|
|
41
|
+
checkImageLoad(element);
|
|
42
|
+
}
|
|
43
|
+
}, [])
|
|
44
|
+
|
|
45
|
+
return (
|
|
46
|
+
<>
|
|
47
|
+
{width && height ?
|
|
48
|
+
<div className="wy-content-image wy-responsive-image" style={{ ["--width" as any]: width, ["--height" as any]: height }}>
|
|
49
|
+
<img className="wy-loading-transition" ref={imageRef} src={src} onLoad={imageLoaded} width={width} height={height} decoding="async" />
|
|
50
|
+
<Spinner.UI />
|
|
51
|
+
</div>
|
|
52
|
+
:
|
|
53
|
+
<div className="wy-content-image wy-responsive-image wy-intrinsic-image">
|
|
54
|
+
<img ref={imageRef} src={src} onLoad={imageLoaded} decoding="async" />
|
|
55
|
+
</div>
|
|
56
|
+
}
|
|
57
|
+
</>
|
|
58
|
+
);
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
type DocumentProps = {
|
|
62
|
+
src: string,
|
|
63
|
+
client: any
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
export const PreviewDocument = ({ src, client }: DocumentProps) => {
|
|
67
|
+
let pdfWorkerUrl = (new URL("/js/preview.worker.js", client.url)).toString();
|
|
68
|
+
let pdfCMapsUrl = (new URL("/js/cmaps/", client.url)).toString();
|
|
69
|
+
|
|
70
|
+
return (
|
|
71
|
+
<PdfViewer src={src} pdfWorkerUrl={pdfWorkerUrl} pdfCMapsUrl={pdfCMapsUrl} />
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function mediaFallback(media: HTMLVideoElement | HTMLAudioElement) {
|
|
76
|
+
if (media.classList.contains("wy-loading")) {
|
|
77
|
+
media.classList.add("wy-loaded");
|
|
78
|
+
}
|
|
79
|
+
media.classList.add("wy-error");
|
|
80
|
+
// TODO: replace with react way
|
|
81
|
+
media.outerHTML = media.outerHTML.replace(/<(video|audio)/, "<div").replace(/(video|audio)>/, "div>");
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function mediaLoaded(event: any) {
|
|
85
|
+
var src = event.target;
|
|
86
|
+
if (src.tagName === 'VIDEO' || src.tagName === 'AUDIO') {
|
|
87
|
+
if (src.classList.contains("wy-loading")) {
|
|
88
|
+
console.log("loaded")
|
|
89
|
+
src.classList.add("wy-loaded");
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
function mediaError(event: any) {
|
|
95
|
+
var src = event.target;
|
|
96
|
+
var media;
|
|
97
|
+
if (src.tagName === 'SOURCE') {
|
|
98
|
+
media = src.parentNode;
|
|
99
|
+
media.dataset.errors = (media.dataset.errors || 0) + 1;
|
|
100
|
+
|
|
101
|
+
if (media.querySelectorAll("source").length >= media.dataset.errors) {
|
|
102
|
+
console.warn(media.tagName.toLowerCase() + " source error, switching to fallback");
|
|
103
|
+
mediaFallback(media);
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function codecError(event: any) {
|
|
109
|
+
var src = event.target;
|
|
110
|
+
if (src.tagName === 'VIDEO' || src.tagName === 'AUDIO') {
|
|
111
|
+
// Capture codec-error for video in firefox
|
|
112
|
+
if (src.tagName === 'VIDEO' && !src.videoWidth || src.tagName === 'AUDIO' && !src.duration) {
|
|
113
|
+
console.warn(src.tagName.toLowerCase() + " track not available, switching to fallback");
|
|
114
|
+
mediaFallback(src);
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
type MediaProps = {
|
|
120
|
+
format: string,
|
|
121
|
+
src: string,
|
|
122
|
+
name: string,
|
|
123
|
+
mediaType?: string
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
export const PreviewMedia = ({ format, src, name, mediaType }: MediaProps) => {
|
|
127
|
+
|
|
128
|
+
const [mediaElement, setMediaElement] = useState<HTMLVideoElement|HTMLAudioElement>();
|
|
129
|
+
const mediaRef = useCallback((element: any) => {
|
|
130
|
+
if (element) {
|
|
131
|
+
element.classList.add("wy-loading");
|
|
132
|
+
setMediaElement(element);
|
|
133
|
+
}
|
|
134
|
+
}, [])
|
|
135
|
+
|
|
136
|
+
useEffect(() => {
|
|
137
|
+
if (mediaElement) {
|
|
138
|
+
|
|
139
|
+
mediaElement.addEventListener('error', mediaError, true); // needs capturing
|
|
140
|
+
mediaElement.addEventListener('loadedmetadata', mediaLoaded, true); // needs capturing
|
|
141
|
+
mediaElement.addEventListener('loadedmetadata', codecError, true); // needs capturing
|
|
142
|
+
|
|
143
|
+
return () => {
|
|
144
|
+
// cleanup
|
|
145
|
+
mediaElement.pause();
|
|
146
|
+
mediaElement.removeAttribute("autoplay");
|
|
147
|
+
mediaElement.setAttribute("preload", "none");
|
|
148
|
+
|
|
149
|
+
mediaElement.removeEventListener('error', mediaError, true); // needs capturing
|
|
150
|
+
mediaElement.removeEventListener('loadedmetadata', mediaLoaded, true); // needs capturing
|
|
151
|
+
mediaElement.removeEventListener('loadedmetadata', codecError, true); // needs capturing
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
}, [mediaElement])
|
|
156
|
+
|
|
157
|
+
return (format === "video" ?
|
|
158
|
+
<>
|
|
159
|
+
<video ref={mediaRef} className="wy-content-video" controls crossOrigin="use-credentials" autoPlay>
|
|
160
|
+
<source src={src} type={mediaType} />
|
|
161
|
+
<PreviewIcon src={src} name={name} icon="file-video" download />
|
|
162
|
+
</video>
|
|
163
|
+
<Spinner.UI />
|
|
164
|
+
</>
|
|
165
|
+
:
|
|
166
|
+
<>
|
|
167
|
+
<PreviewIcon src={src} name={name} icon="file-music" download>
|
|
168
|
+
<audio ref={mediaRef} className="wy-content-audio" controls crossOrigin="use-credentials" autoPlay>
|
|
169
|
+
<source src={src} type={mediaType} />
|
|
170
|
+
</audio>
|
|
171
|
+
</PreviewIcon>
|
|
172
|
+
</>
|
|
173
|
+
);
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
type TextProps = {
|
|
177
|
+
src: string,
|
|
178
|
+
html?: boolean,
|
|
179
|
+
code?: boolean
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
export const PreviewText = ({ src, html = false, code = false }: TextProps) => {
|
|
183
|
+
const [textContent, setTextContent] = useState("");
|
|
184
|
+
|
|
185
|
+
useEffect(() => {
|
|
186
|
+
fetch(src)
|
|
187
|
+
.then(getStream)
|
|
188
|
+
// Create a new response out of the stream
|
|
189
|
+
.then(stream => new Response(stream))
|
|
190
|
+
// Create an object URL for the response
|
|
191
|
+
.then(response => response.text())
|
|
192
|
+
.then(text => {
|
|
193
|
+
setTextContent(text)
|
|
194
|
+
})
|
|
195
|
+
}, [src]);
|
|
196
|
+
|
|
197
|
+
return (
|
|
198
|
+
<>
|
|
199
|
+
{html ?
|
|
200
|
+
code ?
|
|
201
|
+
<div className="wy-content-code wy-code" dangerouslySetInnerHTML={{ __html: textContent }}></div>
|
|
202
|
+
:
|
|
203
|
+
<div className="wy-document">
|
|
204
|
+
<div className="wy-content-html" dangerouslySetInnerHTML={{ __html: textContent }}></div>
|
|
205
|
+
</div>
|
|
206
|
+
:
|
|
207
|
+
code ?
|
|
208
|
+
<div className="wy-content-code">{textContent}</div>
|
|
209
|
+
:
|
|
210
|
+
<div className="wy-document">
|
|
211
|
+
<pre className="wy-content-text">{textContent}</pre>
|
|
212
|
+
</div>
|
|
213
|
+
}
|
|
214
|
+
</>
|
|
215
|
+
);
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
|
|
219
|
+
type EmbedProps = {
|
|
220
|
+
src: string,
|
|
221
|
+
name: string,
|
|
222
|
+
icon: string,
|
|
223
|
+
provider?: string
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
export const PreviewEmbed = ({ src, name, icon, provider }: EmbedProps) => {
|
|
227
|
+
const [embedElement, setEmbedElement] = useState<HTMLObjectElement>();
|
|
228
|
+
const embedRef = useCallback((element: any) => {
|
|
229
|
+
if (element) {
|
|
230
|
+
element.classList.add("wy-loading");
|
|
231
|
+
setEmbedElement(element);
|
|
232
|
+
}
|
|
233
|
+
}, [])
|
|
234
|
+
|
|
235
|
+
useEffect(() => {
|
|
236
|
+
if (embedElement) {
|
|
237
|
+
let embedFallbackTimeout = setTimeout(function () {
|
|
238
|
+
console.log("fallback");
|
|
239
|
+
embedElement.classList.add("wy-fallback");
|
|
240
|
+
}, 2500)
|
|
241
|
+
|
|
242
|
+
let embedLoaded = (event: any) => {
|
|
243
|
+
var obj = event.target;
|
|
244
|
+
if (obj.tagName === 'OBJECT' && obj.classList.contains("wy-loading") && !obj.classList.contains("wy-loaded")) {
|
|
245
|
+
console.log("loaded");
|
|
246
|
+
obj.classList.add("wy-loaded");
|
|
247
|
+
clearTimeout(embedFallbackTimeout);
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
embedElement.addEventListener('load', embedLoaded, true); // needs capturing
|
|
252
|
+
|
|
253
|
+
return () => {
|
|
254
|
+
// cleanup
|
|
255
|
+
embedElement.removeEventListener('load', embedLoaded, true); // needs capturing
|
|
256
|
+
clearTimeout(embedFallbackTimeout);
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
}, [embedElement])
|
|
261
|
+
|
|
262
|
+
return (
|
|
263
|
+
<>
|
|
264
|
+
{/* iframe needs to be object to not render error pages when content is blocked */}
|
|
265
|
+
<object ref={embedRef} className="wy-content-iframe" data={src}></object>
|
|
266
|
+
|
|
267
|
+
<Spinner.UI />
|
|
268
|
+
|
|
269
|
+
<PreviewIcon src={src} name={name} icon={icon} provider={provider} className="wy-content-iframe-fallback" />
|
|
270
|
+
</>
|
|
271
|
+
);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
type IconProps = {
|
|
275
|
+
children?: React.ReactNode,
|
|
276
|
+
src: string,
|
|
277
|
+
icon: string,
|
|
278
|
+
name: string,
|
|
279
|
+
provider?: string,
|
|
280
|
+
download?: boolean,
|
|
281
|
+
className?: string
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
export const PreviewIcon = ({ children, src, icon, name, provider, download = false, className }: IconProps) => {
|
|
285
|
+
return (
|
|
286
|
+
<div className={classNames("wy-content-icon", className)}>
|
|
287
|
+
<div className="wy-content-icon">
|
|
288
|
+
<Icon.UI name={icon} />
|
|
289
|
+
</div>
|
|
290
|
+
<div className="wy-content-name">
|
|
291
|
+
{provider ?
|
|
292
|
+
<>
|
|
293
|
+
<span>No preview available. </span>
|
|
294
|
+
<a href={src} target="_blank" title={name}>{`Open in ${provider}?`}</a>
|
|
295
|
+
</>
|
|
296
|
+
: download ?
|
|
297
|
+
<a href={src} target="_top" download>{name}</a>
|
|
298
|
+
:
|
|
299
|
+
<a href={src} target="_blank">{name} <Icon.UI name="open-in-new" size={1} /></a>
|
|
300
|
+
}
|
|
301
|
+
</div>
|
|
302
|
+
{children}
|
|
303
|
+
</div>
|
|
304
|
+
);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
type PreviewProps = {
|
|
308
|
+
client: any,
|
|
309
|
+
src: string,
|
|
310
|
+
link?: string,
|
|
311
|
+
format: PreviewFormatType,
|
|
312
|
+
name: string,
|
|
313
|
+
icon: string,
|
|
314
|
+
width?: number,
|
|
315
|
+
height?: number,
|
|
316
|
+
mediaType?: string,
|
|
317
|
+
provider?: string
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
export const Preview = ({ client, src, link, format, name, icon, width, height, mediaType, provider }: PreviewProps) => {
|
|
321
|
+
return (
|
|
322
|
+
<>
|
|
323
|
+
{format === "image" &&
|
|
324
|
+
<PreviewImage key={src} src={src} width={width} height={height} />
|
|
325
|
+
}
|
|
326
|
+
{format === "pdf" &&
|
|
327
|
+
/* Key not needed since component is reused and handles cleanup */
|
|
328
|
+
<PreviewDocument src={src} client={client} />
|
|
329
|
+
}
|
|
330
|
+
{(format === "video" || format === "audio") &&
|
|
331
|
+
<PreviewMedia key={src} format={format} src={src} name={name} mediaType={mediaType} />
|
|
332
|
+
}
|
|
333
|
+
{format === "text" &&
|
|
334
|
+
<PreviewText key={src} src={src} />
|
|
335
|
+
}
|
|
336
|
+
{format === "code" &&
|
|
337
|
+
<PreviewText key={src} src={src} html code />
|
|
338
|
+
}
|
|
339
|
+
{format === "html" &&
|
|
340
|
+
<PreviewText key={src} src={src} html />
|
|
341
|
+
}
|
|
342
|
+
{format === "embed" &&
|
|
343
|
+
<PreviewEmbed key={src} src={src} name={name} icon={icon} provider={provider} />
|
|
344
|
+
}
|
|
345
|
+
{format === "none" && (
|
|
346
|
+
link ?
|
|
347
|
+
<PreviewIcon src={src} name={name} icon={icon} provider={provider} />
|
|
348
|
+
:
|
|
349
|
+
<PreviewIcon src={src} name={name} icon={icon} download />
|
|
350
|
+
)}
|
|
351
|
+
</>
|
|
352
|
+
)
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
export default Preview;
|
|
@@ -5,9 +5,9 @@ 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";
|
|
10
|
+
import { WeavyContext } from "../contexts/WeavyContext";
|
|
11
11
|
|
|
12
12
|
type ReactionMenuProps = {
|
|
13
13
|
id: number,
|
|
@@ -25,7 +25,7 @@ export const ReactionsMenu = ({ id, reactions }: ReactionMenuProps) => {
|
|
|
25
25
|
const reactionMutation = useMutateReaction();
|
|
26
26
|
const reactionDeleteMutation = useMutateDeleteReaction();
|
|
27
27
|
const [visible, setVisible] = useState<boolean>(false);
|
|
28
|
-
const { options } = useContext(
|
|
28
|
+
const { options } = useContext(WeavyContext);
|
|
29
29
|
const [reactedEmoji, setReactedEmoji] = useState<string>('');
|
|
30
30
|
|
|
31
31
|
const emojis = options?.reactions;
|
|
@@ -68,12 +68,12 @@ export const ReactionsMenu = ({ id, reactions }: ReactionMenuProps) => {
|
|
|
68
68
|
}
|
|
69
69
|
|
|
70
70
|
return (
|
|
71
|
-
<div className={
|
|
72
|
-
<Button.UI onClick={toggleReactionMenu}><Icon.UI name="emoticon-
|
|
73
|
-
<div className=
|
|
74
|
-
<div className=
|
|
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">
|
|
75
75
|
{emojis?.map((r: string, i: number) => {
|
|
76
|
-
return <Button.UI key={i} onClick={handleReaction} className={
|
|
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
|
|
77
77
|
})}
|
|
78
78
|
</div>
|
|
79
79
|
</div>
|
|
@@ -88,7 +88,7 @@ export const ReactionsList = ({ id, reactions }: ReactionsProps) => {
|
|
|
88
88
|
return (
|
|
89
89
|
<>
|
|
90
90
|
{reactionsList && reactionsList.map((r: ReactionGroup, i: number) => {
|
|
91
|
-
return <span key={i} className=
|
|
91
|
+
return <span key={i} className="wy-reaction" title={r.count.toString()}>{r.content}</span> //r.has_reacted
|
|
92
92
|
})}
|
|
93
93
|
</>
|
|
94
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=
|
|
46
|
-
<div className=
|
|
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=
|
|
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=
|
|
52
|
-
{data && data.data.length === 0 &&
|
|
53
|
-
<div className=
|
|
50
|
+
<div className="wy-pane-group">
|
|
51
|
+
{data && (!data.data || data.data.length === 0) &&
|
|
52
|
+
<div className="wy-search-no-result">Your search did not match any people.</div>
|
|
54
53
|
}
|
|
55
|
-
<table className=
|
|
54
|
+
<table className="wy-search-result-table">
|
|
56
55
|
<tbody>
|
|
57
|
-
{data && data.data.length > 0 && data.data.map((user: MemberType) => {
|
|
56
|
+
{data && data.data && data.data.length > 0 && data.data.map((user: MemberType) => {
|
|
58
57
|
return (
|
|
59
|
-
<tr key={user.id} className=
|
|
60
|
-
<td className=
|
|
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=
|
|
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=
|
|
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=
|
|
80
|
-
<div className=
|
|
81
|
-
<div className=
|
|
82
|
-
<
|
|
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=
|
|
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}/>)})
|
|
@@ -3,22 +3,14 @@ import usePresence from "../hooks/usePresence";
|
|
|
3
3
|
|
|
4
4
|
export const MessengerContext = createContext<MessengerContextProps>({
|
|
5
5
|
selectedConversationId: null,
|
|
6
|
-
setSelectedConversationId: (id: any) => { }
|
|
7
|
-
options: {}
|
|
6
|
+
setSelectedConversationId: (id: any) => { }
|
|
8
7
|
});
|
|
9
8
|
|
|
10
9
|
type Props = {
|
|
11
|
-
children: React.ReactNode
|
|
12
|
-
options?: MessengerContextOptions
|
|
10
|
+
children: React.ReactNode
|
|
13
11
|
}
|
|
14
12
|
|
|
15
|
-
const MessengerProvider = ({ children
|
|
16
|
-
|
|
17
|
-
let defaultOptions: MessengerContextOptions = {
|
|
18
|
-
reactions: ['😍', '😎', '😉', '😜', '👍']
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
let opts = { ...defaultOptions, ...options };
|
|
13
|
+
const MessengerProvider = ({ children }: Props) => {
|
|
22
14
|
|
|
23
15
|
const [selectedConversationId, setSelectedConversation] = useState(null);
|
|
24
16
|
|
|
@@ -31,7 +23,7 @@ const MessengerProvider = ({ children, options }: Props) => {
|
|
|
31
23
|
|
|
32
24
|
return (
|
|
33
25
|
<>
|
|
34
|
-
<MessengerContext.Provider value={{
|
|
26
|
+
<MessengerContext.Provider value={{ selectedConversationId, setSelectedConversationId }}>
|
|
35
27
|
{children}
|
|
36
28
|
</MessengerContext.Provider>
|
|
37
29
|
</>
|