+
{clickToPlayVisible && (
-
-
-
-
- Демонстрация начата
-
-
-
- Нажмите, чтобы продолжить
-
-
-
-
-
-
+
{
+ pixelStreaming?.play();
+ setClickToPlayVisible(false);
+ }}
+ >
+
Click to play
)}
+
+
+ {latencyTestResult &&
+ Object.entries(latencyTestResult).map(([key, value], i) => {
+ if (
+ [
+ "EncodeMs",
+ "CaptureToSendMs",
+ "latencyExcludingDecode",
+ "networkLatency",
+ "testStartTimeMs",
+ ].includes(key)
+ )
+ return (
+
+ {key}: {value}
+
+ );
+ })}
+
);
};
diff --git a/src/components/icons/AttachIcon.tsx b/src/components/icons/AttachIcon.tsx
new file mode 100644
index 0000000..f45135a
--- /dev/null
+++ b/src/components/icons/AttachIcon.tsx
@@ -0,0 +1,27 @@
+function AttachIcon() {
+ return (
+
+ );
+}
+
+export default AttachIcon;
diff --git a/src/components/icons/ChatIcon.tsx b/src/components/icons/ChatIcon.tsx
index 5201671..e000dac 100644
--- a/src/components/icons/ChatIcon.tsx
+++ b/src/components/icons/ChatIcon.tsx
@@ -1,17 +1,17 @@
-interface IconProps {
- className?: string;
-}
-
-function ChatIcon({ className }: IconProps) {
+function ChatIcon() {
return (
);
}
diff --git a/src/components/icons/CloseIcon.tsx b/src/components/icons/CloseIcon.tsx
index 1a35e7c..9a6fcdc 100644
--- a/src/components/icons/CloseIcon.tsx
+++ b/src/components/icons/CloseIcon.tsx
@@ -7,16 +7,13 @@ function CloseIcon() {
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
-
-
-
+
);
}
diff --git a/src/components/icons/DetachIcon.tsx b/src/components/icons/DetachIcon.tsx
new file mode 100644
index 0000000..ed9303b
--- /dev/null
+++ b/src/components/icons/DetachIcon.tsx
@@ -0,0 +1,28 @@
+function DetachIcon() {
+ return (
+
+ );
+}
+
+export default DetachIcon;
diff --git a/src/components/icons/FullscreenIcon.tsx b/src/components/icons/FullscreenIcon.tsx
index 34e7163..27ca23c 100644
--- a/src/components/icons/FullscreenIcon.tsx
+++ b/src/components/icons/FullscreenIcon.tsx
@@ -7,16 +7,20 @@ function FullscreenIcon() {
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
-
-
-
+
+
);
}
diff --git a/src/components/icons/GearIcon.tsx b/src/components/icons/GearIcon.tsx
new file mode 100644
index 0000000..814f22a
--- /dev/null
+++ b/src/components/icons/GearIcon.tsx
@@ -0,0 +1,28 @@
+function GearIcon() {
+ return (
+
+ );
+}
+
+export default GearIcon;
diff --git a/src/components/icons/HandOffIcon.tsx b/src/components/icons/HandOffIcon.tsx
index a03106f..5c40efb 100644
--- a/src/components/icons/HandOffIcon.tsx
+++ b/src/components/icons/HandOffIcon.tsx
@@ -7,30 +7,21 @@ function HandOffIcon() {
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
-
-
-
-
-
-
-
+
+
);
}
diff --git a/src/components/icons/MicroOffIcon.tsx b/src/components/icons/MicroOffIcon.tsx
index 5ddcd09..149d029 100644
--- a/src/components/icons/MicroOffIcon.tsx
+++ b/src/components/icons/MicroOffIcon.tsx
@@ -7,25 +7,21 @@ function MicroOffIcon() {
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
-
-
-
-
+
+
);
}
diff --git a/src/components/icons/MicroOnIcon.tsx b/src/components/icons/MicroOnIcon.tsx
index 5570df7..c6ea9e5 100644
--- a/src/components/icons/MicroOnIcon.tsx
+++ b/src/components/icons/MicroOnIcon.tsx
@@ -7,18 +7,13 @@ function MicroOnIcon() {
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
-
-
-
-
-
-
+
);
}
diff --git a/src/components/icons/MoreIcon.tsx b/src/components/icons/MoreIcon.tsx
new file mode 100644
index 0000000..ec25d90
--- /dev/null
+++ b/src/components/icons/MoreIcon.tsx
@@ -0,0 +1,17 @@
+function MoreIcon() {
+ return (
+
+ );
+}
+
+export default MoreIcon;
diff --git a/src/components/icons/PersonsIcon.tsx b/src/components/icons/PersonsIcon.tsx
index 91a15b6..8e1e372 100644
--- a/src/components/icons/PersonsIcon.tsx
+++ b/src/components/icons/PersonsIcon.tsx
@@ -7,25 +7,18 @@ function PersonsIcon() {
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
-
-
-
-
-
-
-
+
+
);
}
diff --git a/src/components/icons/ShareIcon.tsx b/src/components/icons/ShareIcon.tsx
index 20caeb8..f8706c4 100644
--- a/src/components/icons/ShareIcon.tsx
+++ b/src/components/icons/ShareIcon.tsx
@@ -7,17 +7,13 @@ function ShareIcon() {
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
-
-
-
-
-
-
+
);
}
diff --git a/src/components/icons/WindowIcon.tsx b/src/components/icons/WindowIcon.tsx
new file mode 100644
index 0000000..82f6b99
--- /dev/null
+++ b/src/components/icons/WindowIcon.tsx
@@ -0,0 +1,28 @@
+function WindowIcon() {
+ return (
+
+ );
+}
+
+export default WindowIcon;
diff --git a/src/components/ui/Button.tsx b/src/components/ui/Button.tsx
new file mode 100644
index 0000000..0d4d513
--- /dev/null
+++ b/src/components/ui/Button.tsx
@@ -0,0 +1,67 @@
+interface ButtonProps {
+ type?: "button" | "reset" | "submit";
+ variant?: "primary" | "secondary" | "tertiary";
+ fullWidth?: boolean;
+ large?: boolean;
+ icon?: JSX.Element;
+ onlyIcon?: boolean;
+ disabled?: boolean;
+ children?: React.ReactNode;
+ onClick?: () => void;
+}
+
+function Button({
+ type = "button",
+ variant = "primary",
+ fullWidth,
+ large,
+ icon,
+ onlyIcon,
+ disabled,
+ children,
+ onClick,
+}: ButtonProps) {
+ const variantClasses = [
+ {
+ name: "primary",
+ classes:
+ "enabled:bg-[#49A1F5] enabled:hover:bg-[#4190DB] enabled:text-white disabled:bg-[#F2F2F2] disabled:text-[#CCCCCC]",
+ },
+ {
+ name: "secondary",
+ classes:
+ "enabled:bg-[#F0F1F2] enabled:hover:bg-[#E6ECF2] enabled:text-[#77828C] disabled:bg-[#F2F2F2] disabled:text-[##CCCCCC]",
+ },
+ {
+ name: "tertiary",
+ classes:
+ "enabled:hover:bg-[#E6ECF2] enabled:text-[#77828C] disabled:text-[#CCCCCC]",
+ },
+ ];
+
+ return (
+
+ );
+}
+
+export default Button;
diff --git a/src/main.tsx b/src/main.tsx
index 0961f0b..1c8e426 100644
--- a/src/main.tsx
+++ b/src/main.tsx
@@ -8,22 +8,24 @@ import {
import "./index.css";
import "./i18n";
import App from "./App";
-import StreamPage from "./StreamPage";
import HistoryPage from "./HistoryPage";
import ScheduledPage from "./ScheduledPage";
import CalendarPage from "./CalendarPage";
import useAuthStore from "./stores/useAuthStore";
import PersonalAreaLoginPage from "./PersonalAreaLoginPage";
import PersonalAreaDashboardPage from "./PersonalAreaDashboardPage";
+import StreamPage2 from "./pages/StreamPage2";
+import ErrorBoundary from "./ErrorBoundary";
const router = createBrowserRouter([
{
path: "/",
element:
,
+ errorElement:
,
},
{
path: "/stream/:id",
- element:
,
+ element:
,
},
{
path: "/history",
diff --git a/src/pages/StreamPage2.css b/src/pages/StreamPage2.css
new file mode 100644
index 0000000..bb3daf5
--- /dev/null
+++ b/src/pages/StreamPage2.css
@@ -0,0 +1,15 @@
+.entering {
+ opacity: 1;
+}
+
+.entered {
+ opacity: 1;
+}
+
+.exiting {
+ opacity: 0;
+}
+
+.exited {
+ opacity: 0;
+}
diff --git a/src/pages/StreamPage2.tsx b/src/pages/StreamPage2.tsx
new file mode 100644
index 0000000..680147b
--- /dev/null
+++ b/src/pages/StreamPage2.tsx
@@ -0,0 +1,468 @@
+/* eslint-disable @typescript-eslint/no-non-null-assertion */
+/* eslint-disable @typescript-eslint/no-explicit-any */
+/* eslint-disable react-hooks/exhaustive-deps */
+import "./StreamPage2.css";
+import ky from "ky";
+import { PixelStreamingWrapper } from "../components/PixelStreamingWrapper";
+import { useParams } from "react-router-dom";
+import { FormEvent, useEffect, useRef, useState } from "react";
+import { Transition } from "react-transition-group";
+import Button from "../components/ui/Button";
+import CloseIcon from "../components/icons/CloseIcon";
+import HandOffIcon from "../components/icons/HandOffIcon";
+import MicroOffIcon from "../components/icons/MicroOffIcon";
+import PersonsIcon from "../components/icons/PersonsIcon";
+import MicroOnIcon from "../components/icons/MicroOnIcon";
+import MoreIcon from "../components/icons/MoreIcon";
+import FullscreenIcon from "../components/icons/FullscreenIcon";
+import WindowIcon from "../components/icons/WindowIcon";
+import ChatIcon from "../components/icons/ChatIcon";
+import ShareIcon from "../components/icons/ShareIcon";
+import GearIcon from "../components/icons/GearIcon";
+import { useFullscreen } from "ahooks";
+import AttachIcon from "../components/icons/AttachIcon";
+import DetachIcon from "../components/icons/DetachIcon";
+import Draggable from "react-draggable";
+
+interface User {
+ id: string;
+ username: string;
+}
+
+function StreamPage2() {
+ const params = useParams();
+ const [wsUrl, setWsUrl] = useState
();
+ const [username, setUsername] = useState("");
+ const [step, setStep] = useState(1);
+ const usernameRef = useRef(null!);
+ const [users, setUsers] = useState([
+ {
+ id: "1",
+ username: "User 1",
+ },
+ {
+ id: "2",
+ username: "User 2",
+ },
+ {
+ id: "3",
+ username: "User 3",
+ },
+ {
+ id: "4",
+ username: "User 3",
+ },
+ {
+ id: "1",
+ username: "User 1",
+ },
+ {
+ id: "2",
+ username: "User 2",
+ },
+ ]);
+ const [isShowUsers, setIsShowUsers] = useState(false);
+ const [isShowChat, setIsShowChat] = useState(false);
+ const [isMicEnabled, setIsMicEnabled] = useState(false);
+ const [isVideoInitialized, setIsVideoInitialized] = useState(false);
+ const ref = useRef(null);
+ const [isFullscreen, { toggleFullscreen }] = useFullscreen(ref);
+ const [isUsersDetached, setIsUsersDetached] = useState(false);
+ const [isChatDetached, setIsChatDetached] = useState(false);
+
+ async function getWsUrl() {
+ const activeSession: any = await ky
+ .get(`${import.meta.env.VITE_COORD_URL}/active_sessions/${params.id}`)
+ .json();
+
+ setWsUrl(
+ `wss://${activeSession.location}.sess.stream.graff.tech/${activeSession.server}/${activeSession.cirrusPort}/`
+ );
+ }
+
+ function handleSetUsername(e: FormEvent) {
+ e.preventDefault();
+
+ if (!username) {
+ usernameRef.current.focus();
+ return;
+ }
+
+ setStep(2);
+ }
+
+ function setUsernameGuest() {
+ setUsername("Гость");
+ setStep(2);
+ }
+
+ function allowMic() {
+ setStep(3);
+ }
+
+ function disallowMic() {
+ setStep(3);
+ }
+
+ useEffect(() => {
+ if (!username) return;
+
+ setUsername(() => username.trim());
+ }, [username]);
+
+ useEffect(() => {
+ if (isChatDetached || isUsersDetached) {
+ document.body.classList.add("overflow-hidden");
+ } else {
+ document.body.classList.remove("overflow-hidden");
+ }
+ }, [isUsersDetached, isChatDetached]);
+
+ useEffect(() => {
+ getWsUrl();
+ }, []);
+
+ return (
+
+
+
+
+
+
+ {username && username[0].toUpperCase()}
+
+
{username}
+
+
+ } onlyIcon />
+ : }
+ onlyIcon
+ onClick={() => setIsMicEnabled((prev) => !prev)}
+ />
+
+
+
+ {users.map(
+ (user, index) =>
+ index < 3 && (
+
+
+ {user.username && user.username[0].toUpperCase()}
+
+
{user.username}
+
+ )
+ )}
+
+ {users.length > 3 && (
+
}
+ onlyIcon
+ onClick={() => setIsShowUsers((prev) => !prev)}
+ />
+ )}
+
+
+
+
+
+ }
+ onlyIcon
+ onClick={() => setIsShowChat((prev) => !prev)}
+ />
+
+
+
+ : }
+ onlyIcon
+ onClick={toggleFullscreen}
+ />
+ } onlyIcon />
+ } onlyIcon />
+
+
+
+
+
+
+ {wsUrl && (
+
setIsVideoInitialized(true)}
+ />
+ )}
+
+
+
+
+
+
+
Участники
+
+ : }
+ onlyIcon
+ onClick={() => setIsUsersDetached((prev) => !prev)}
+ />
+ }
+ onlyIcon
+ onClick={() => setIsShowUsers(false)}
+ />
+
+
+
+ {users.map((user) => (
+
+
+
+
+ {user.username[0].toUpperCase()}
+
+
+
{user.username}
+
+
+ }
+ onlyIcon
+ />
+
+
+ ))}
+
+
+
+
+
+
+
+
+
+
Чат
+
+ : }
+ onlyIcon
+ onClick={() => setIsChatDetached((prev) => !prev)}
+ />
+ }
+ onlyIcon
+ onClick={() => setIsShowChat(false)}
+ />
+
+
+
//
+
+
+
+
+
+
+
+
+ {(state) => (
+
+
+ {(state) => (
+
+ )}
+
+
+
+ {(state) => (
+
+
+
+ Хотите принять участие в обсуждении?
+
+
+
+
+
+
+
Разрешите использование микрофона
+
+
+
+ Выключить микрофон можно в любой момент
+
+
+
+
+
+
+
+ )}
+
+
+
+ {(state) => (
+
+
+
+ Пожалуйста, подождите
+
+
+
+

+
Подключение
+
+
+ )}
+
+
+ )}
+
+
+ );
+}
+
+export default StreamPage2;
diff --git a/yarn.lock b/yarn.lock
index 563b31b..3179b06 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -596,6 +596,20 @@ acorn@^8.9.0:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a"
integrity sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==
+ahooks@^3.7.10:
+ version "3.7.10"
+ resolved "https://registry.yarnpkg.com/ahooks/-/ahooks-3.7.10.tgz#6ac1dfbcedff8c673367c044ffef41ffae6da483"
+ integrity sha512-/HLYif7sFA/5qSuWKrwvjDbf3bq+sdaMrUWS7XGCDRWdC2FrG/i+u5LZdakMYc6UIgJTMQ7tGiJCV7sdU4kSIw==
+ dependencies:
+ "@babel/runtime" "^7.21.0"
+ dayjs "^1.9.1"
+ intersection-observer "^0.12.0"
+ js-cookie "^2.x.x"
+ lodash "^4.17.21"
+ resize-observer-polyfill "^1.5.1"
+ screenfull "^5.0.0"
+ tslib "^2.4.1"
+
ajv@^6.12.4:
version "6.12.6"
resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.12.6.tgz#baf5a62e802b07d977034586f8c3baf5adf26df4"
@@ -828,6 +842,11 @@ date-fns@^2.30.0:
dependencies:
"@babel/runtime" "^7.21.0"
+dayjs@^1.9.1:
+ version "1.11.10"
+ resolved "https://registry.yarnpkg.com/dayjs/-/dayjs-1.11.10.tgz#68acea85317a6e164457d6d6947564029a6a16a0"
+ integrity sha512-vjAczensTgRcqDERK0SR2XMwsF/tSvnvlv6VcF2GIhg6Sx4yOIt/irsr1RDJsKiIyBzJDpCoXiWWq28MqH2cnQ==
+
debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2:
version "4.3.4"
resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865"
@@ -1316,6 +1335,11 @@ inherits@2:
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
+intersection-observer@^0.12.0:
+ version "0.12.2"
+ resolved "https://registry.yarnpkg.com/intersection-observer/-/intersection-observer-0.12.2.tgz#4a45349cc0cd91916682b1f44c28d7ec737dc375"
+ integrity sha512-7m1vEcPCxXYI8HqnL8CKI6siDyD+eIWSwgB3DZA+ZTogxk9I4CDnj4wilt9x/+/QbHI4YG5YZNmC6458/e9Ktg==
+
invariant@^2.2.4:
version "2.2.4"
resolved "https://registry.yarnpkg.com/invariant/-/invariant-2.2.4.tgz#610f3c92c9359ce1db616e538008d23ff35158e6"
@@ -1388,6 +1412,11 @@ jiti@^1.19.1:
resolved "https://registry.yarnpkg.com/jiti/-/jiti-1.21.0.tgz#7c97f8fe045724e136a397f7340475244156105d"
integrity sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==
+js-cookie@^2.x.x:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/js-cookie/-/js-cookie-2.2.1.tgz#69e106dc5d5806894562902aa5baec3744e9b2b8"
+ integrity sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ==
+
"js-tokens@^3.0.0 || ^4.0.0":
version "4.0.0"
resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499"
@@ -1620,6 +1649,11 @@ lodash.merge@^4.6.2:
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a"
integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==
+lodash@^4.17.21:
+ version "4.17.21"
+ resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c"
+ integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==
+
loglevel@1.8.1:
version "1.8.1"
resolved "https://registry.yarnpkg.com/loglevel/-/loglevel-1.8.1.tgz#5c621f83d5b48c54ae93b6156353f555963377b4"
@@ -1948,6 +1982,14 @@ react-dom@^18.2.0:
loose-envify "^1.1.0"
scheduler "^0.23.0"
+react-draggable@^4.4.6:
+ version "4.4.6"
+ resolved "https://registry.yarnpkg.com/react-draggable/-/react-draggable-4.4.6.tgz#63343ee945770881ca1256a5b6fa5c9f5983fe1e"
+ integrity sha512-LtY5Xw1zTPqHkVmtM3X8MUOxNDOUhv/khTgBgrUvwaS064bwVvxT+q5El0uUFNx5IEPKXuRejr7UqLwBIg5pdw==
+ dependencies:
+ clsx "^1.1.1"
+ prop-types "^15.8.1"
+
react-full-screen@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/react-full-screen/-/react-full-screen-1.1.1.tgz#b707d56891015a71c503a65dbab3086d75be97d7"
@@ -2071,6 +2113,11 @@ regenerator-runtime@^0.14.0:
resolved "https://registry.yarnpkg.com/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz#356ade10263f685dda125100cd862c1db895327f"
integrity sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==
+resize-observer-polyfill@^1.5.1:
+ version "1.5.1"
+ resolved "https://registry.yarnpkg.com/resize-observer-polyfill/-/resize-observer-polyfill-1.5.1.tgz#0e9020dd3d21024458d4ebd27e23e40269810464"
+ integrity sha512-LwZrotdHOo12nQuZlHEmtuXdqGoOD0OhaxopaNFxWzInpEgaLWoVuAMbTzixuosCx2nEG58ngzW3vxdWoxIgdg==
+
resolve-from@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6"
@@ -2125,6 +2172,11 @@ scheduler@^0.23.0:
dependencies:
loose-envify "^1.1.0"
+screenfull@^5.0.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/screenfull/-/screenfull-5.2.0.tgz#6533d524d30621fc1283b9692146f3f13a93d1ba"
+ integrity sha512-9BakfsO2aUQN2K9Fdbj87RJIEZ82Q9IGim7FqM5OsebfoFC6ZHXgDq/KvniuLTPdeM8wY2o6Dj3WQ7KeQCj3cA==
+
sdp-transform@^2.14.1:
version "2.14.2"
resolved "https://registry.yarnpkg.com/sdp-transform/-/sdp-transform-2.14.2.tgz#d2cee6a1f7abe44e6332ac6cbb94e8600f32d813"
@@ -2339,7 +2391,7 @@ ts-interface-checker@^0.1.9:
resolved "https://registry.yarnpkg.com/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz#784fd3d679722bc103b1b4b8030bcddb5db2a699"
integrity sha512-Y/arvbn+rrz3JCKl9C4kVNfTfSm2/mEp5FSz5EsZSANGPSlQrpRI5M4PKF+mJnE52jOO90PnPSc3Ur3bTQw0gA==
-tslib@2.6.2, tslib@^2.1.0:
+tslib@2.6.2, tslib@^2.1.0, tslib@^2.4.1:
version "2.6.2"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.6.2.tgz#703ac29425e7b37cd6fd456e92404d46d1f3e4ae"
integrity sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==